落沙模拟中的水

问题描述

Demonstration of strange water physics

我目前正在使用 C++ 和 SDL2 开发一个非常简单的“落沙”模拟游戏,但在让水以更逼真的方式流动时遇到了问题。我基本上有一个单元格网格,我从下到上,从左到右迭代,如果我找到一个水单元格,我只需检查下面,从下到左,下到右,左然后右的空单元格它移动到它找到的第一个(如果两个对角线单元格或两个水平单元格都是空闲的,它会随机选择)。然后我将它移入的单元​​格标记为已处理,以便在该循环的其余部分不会再次检查它。

我的问题是粒子运动的一种“左偏”;如果我在屏障上方生成一个正方形的水细胞,一旦粒子开始到达屏障,它们基本上都会向左移动而不移动,而右侧的细胞将以正确的方式向下运行。所以不是形成一个漂亮的三角形,均匀地流向两边,整个形状只会向左移动。每当我从左到右迭代时,这种效果就会逆转,所以我知道这与此有关,但到目前为止我一直在努力修复它。我最初认为这是我如何将单元格标记为已处理的问题,但在数小时的测试中我没有发现该系统有明显的错误。有没有人在开发这样的模拟时遇到过类似的挑战,或者知道我遗漏了什么?任何帮助将不胜感激。

编辑: 好的,所以我取得了一些进展,但是我遇到了另一个似乎与迭代无关的错误,因为现在我保存了旧单元格的副本并从中读取以决定更新,然后更新原始单元格并显示出来。这已经使沙子更好地工作,但是水平检查游离细胞的水现在在水平移动时“消失”。我整个上午都在测试它,但还没有找到解决方案,我认为这可能与我复制数组的方式有关,但据我所知,它似乎有效。

新片段:

Simulation.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;
    }
}

Main.cpp

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,c_sand);
    if(sim.getCell(x,y)->m_type == 2) screen.setPixel(x,0x0000cc00);
}


screen.render();

我附上了一个显示问题的 gif,希望这可能有助于使它更清楚一些。你可以看到沙子被正常放置,然后是水和放置后它产生的奇怪图案(注意它在生成时如何向左移动,与沙子不同)

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...