簡體   English   中英

落沙模擬中的水

[英]Water in a falling sand simulation

奇怪的水物理演示

我目前正在 C++ 和 SDL2 中開發一個非常簡單的“落沙”模擬游戲,並且在讓水以更真實的方式流動時遇到問題。 我基本上有一個單元格網格,我從下到上、從左到右進行迭代,如果我找到一個水單元格,我只需在下面、從下到左、從下到右、從左到右檢查空單元格並且它移動到它找到的第一個(如果兩個對角單元格或兩個水平單元格都是空閑的,它會隨機選擇)。 然后我將它移入的單元格標記為已處理,以便不再檢查該循環的 rest。

我的問題是粒子如何移動的一種“左偏”; 如果我在屏障上方生成一個正方形的水細胞,一旦粒子開始到達屏障,它們基本上都會向左移動而不會移動,而右側的細胞將以正確的方式向下流動。 所以不是形成一個漂亮的三角形,均勻地流向兩邊,整個形狀只會向左移動。 每當我從左到右迭代時,這種效果就會逆轉,所以我知道這與此有關,但到目前為止,我一直在努力修復它。 我最初認為這是我如何將單元格標記為已處理的問題,但在數小時的測試中我沒有發現該系統存在明顯的錯誤。 有沒有人在開發這樣的模擬時遇到過類似的挑戰,或者知道我錯過了什么? 任何幫助將不勝感激。

編輯:好的,所以我取得了一些進展,但是我遇到了另一個似乎與迭代無關的錯誤,因為現在我保存了舊單元格的副本並從中讀取以決定更新,然后更新原始單元格並顯示它。 這已經使沙子工作得更好,但是水平檢查自由細胞的水現在在水平移動時“消失”了。 我整個早上都在測試它,但還沒有找到解決方案,我認為這可能與我復制 arrays 的方式有關,但據我所知,它似乎有效。

新片段:

模擬.cpp

void Simulation::update()
{
    copyStates(m_cells, m_oldCells); // so now oldcells is the last new state

    for(int y = m_height - 1; y>= 0; y--)
    for(int x = 0; x < m_width; x++)
        {
            Cell* c = getOldCell(x, y); // check in the old state for possible updates
            switch(c->m_type)
            {
                case EMPTY:
                    break;
                case SAND:
                    if(c->m_visited == false) update_sand(x, y);
                    break;
                case WATER:
                    if(c->m_visited == false) update_water(x, y);
                    break;
                default:
                    break;
            }
        }
}

void Simulation::update_water(int x, int y)
{
    bool down = (getOldCell(x, y+1)->m_type == EMPTY) && checkBounds(x, y+1) && !getOldCell(x, y+1)->m_visited;
    bool d_left = (getOldCell(x-1, y+1)->m_type == EMPTY) && checkBounds(x-1, y+1) && !getOldCell(x-1, y+1)->m_visited;
    bool d_right = (getOldCell(x+1, y+1)->m_type == EMPTY) && checkBounds(x+1, y+1) && !getOldCell(x+1, y+1)->m_visited ;
    bool left = (getOldCell(x-1, y)->m_type == EMPTY) && checkBounds(x-1, y) && !getOldCell(x-1, y)->m_visited ;
    bool right = (getOldCell(x+1, y)->m_type == EMPTY) && checkBounds(x+1, y) && !getOldCell(x+1, y)->m_visited ;

    // choose random dir if both are possible
    if(d_left && d_right)
    {
        int r = rand() % 2;
        if(r) d_right = false;
        else d_left = false;
    }

    if(left && right)
    {
        int r = rand() % 2;
        if(r) right = false;
        else left = false;
    }
    
    if(down)
    {
        getCell(x, y+1)->m_type = WATER; // we now update the new state
        getOldCell(x, y+1)->m_visited = true; // mark as visited so it will not be checked again in update()
    } else if(d_left)
    {
        getCell(x-1, y+1)->m_type = WATER;
        getOldCell(x-1, y+1)->m_visited = true;
    } else if(d_right)
    {
        getCell(x+1, y+1)->m_type = WATER;
        getOldCell(x+1, y+1)->m_visited = true;
    } else if(left)
    {
        getCell(x-1, y)->m_type = WATER;
        getOldCell(x-1, y)->m_visited = true;
    } else if(right)
    {
        getCell(x+1, y)->m_type = WATER;
        getOldCell(x+1, y)->m_visited = true;
    }
    
    if(down || d_right || d_left || left || right) // the original cell is now empty; update the new state
    {
        getCell(x, y)->m_type = EMPTY;
    }
}

void Simulation::copyStates(Cell* from, Cell* to)
{
    for(int x = 0; x < m_width; x++)
    for(int y = 0; y < m_height; y++)
    {
        to[x + y * m_width].m_type = from[x + y * m_width].m_type;
        to[x + y * m_width].m_visited = from[x + y * m_width].m_visited;
    }
}

主文件

sim.update();

Uint32 c_sand = 0xedec9a00;
for(int y = 0; y < sim.m_height; y++)
for(int x = 0; x < sim.m_width; x++)
{
    sim.getCell(x, y)->m_visited = false;
    if(sim.getCell(x, y)->m_type == 0) screen.setPixel(x, y, 0);
    if(sim.getCell(x, y)->m_type == 1) screen.setPixel(x, y, c_sand);
    if(sim.getCell(x, y)->m_type == 2) screen.setPixel(x, y, 0x0000cc00);
}


screen.render();

我附上了一個顯示問題的 gif,希望這可能有助於使它更清楚一點。 你可以看到沙子被正常放置,然后是水和它在放置后形成的奇怪圖案(注意它在生成時是如何向左移動的,不像沙子)

您還必須將目標位置標記為已訪問,以阻止多個單元格移動到同一位置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM