我正在使用C#/XNA进行一个项目,在自上而下的基于十六进制的网格中创建水物理时遇到了问题。
我们使用的是一个十六进制波浪形图,其帮助如下:http://www.redblobgames.com/grids/hexagons.所以我想我可以为水流实现一个算法,但我似乎做不好,而且它的性能似乎很重。
/// <summary>
/// This method will level all the water to the same height. It does so by looking arround and make them all even
/// </summary>
/// <param name="tiles">The tile array needed to level arround</param>
public void Flow(List<Tile> tiles, Tilemap tileMap)
{
float waterAmountEachTile;
List<Water> waterTiles = new List<Water>(7);
//include self
waterTiles.Add(this);
float waterAmount = (this.waterHeight + this.ZPos);
for (int i = 0; i < tiles.Count; i++)//first loop to get all values
{
if (tiles[i].GetType() == typeof(Water))
{
waterTiles.Add((Water)tiles[i]);//check wich tiles are water and put them in a new array
waterAmount += (waterTiles[waterTiles.Count - 1].waterHeight + waterTiles[waterTiles.Count - 1].ZPos); //Increase the ammount - debuggen later werkt count goed
}
}
waterAmountEachTile = waterAmount / waterTiles.Count; //Calculate how high each tile should be ( we need this for drycheck)
dryCheck(ref waterAmount, waterTiles, waterAmountEachTile, tileMap);
waterAmountEachTile = waterAmount / waterTiles.Count; //recalculate the ammount for each tile
foreach (Water waterTile in waterTiles) //second loop to adjust the tile to the according hight
{
waterTile.waterHeight = (waterAmountEachTile - waterTile.ZPos);
}
}
/// <summary>
/// Checks if the tile should be dry or continue being a water tile.
/// </summary>
/// <param name="waterAmount"> the ammount of water to divide among the tiles</param>
/// <param name="waterTiles">The watertiles list to do the drycheck on</param>
/// <param name="waterAmountEachTile">The height to set each water tile</param>
/// <returns></returns>
private void dryCheck(ref float waterAmount, List<Water> waterTiles, float waterAmountEachTile, Tilemap tileMap)
{
//TODO dit fixen
for (int i = 0; i < waterTiles.Count; i++)
{
if (waterTiles[i].ZPos > waterAmountEachTile) //is grond hoger dan water
{
waterAmount -= waterTiles[i].ZPos;
tileMap.TileMap[waterTiles[i].XPos][waterTiles[i].YPos] = new Ground(this.graphics, waterTiles[i].XPos, waterTiles[i].YPos,
waterTiles[i].ZPos, this.size, Tilemap.HexVertices);
waterTiles.Remove(waterTiles[i]);
i--;
}
}
}
现在我的问题是,你们中有人知道在自上而下的环境中实现水物理的方法吗,最好是使用基于十六进制的网格。
我查阅了一些自由论,发现了光滑粒子流体动力学,但我不确定它是否可以自上而下实现,而且我似乎找不到任何方向的指导。
任何帮助都将是伟大的,甚至一些指针可能就足够了。
提前感谢,C.Venhuizen
您是否分析了代码以确定最慢的部分?
我不太明白你的代码在做什么。您是为每个磁贴调用Flow
一次,还是调用一次,然后它在所有磁贴上运行?如果我猜测,我会说为每个磁贴分配一个新列表会很慢。但最好的方法是了解情况。
最初让我写作的东西http://www.redblobgames.com/grids/hexagons是一个自上而下的六角游戏,一切都是关于水的流动。我在1995年写了这个游戏,最近我把它移植到了网上运行。我开始使用的算法很简单。对于每个十六进制,按随机顺序遍历:
- 计算水位W+高程H
- 为每个邻居计算相同
- 使流向W+H最低的邻居的水量达到一半
随机顺序是为了使循环不会导致水向右流动许多六角体,但向左流动的六角体不多,或其他这样的方向伪影。更干净的方法是使用双缓冲区:将所有新值写入一个单独的数组,然后在最后将它们复制回第一个数组(或交换数组)。
除此之外,我还使用了大量的启发式方法来处理(未完成的)游戏的侵蚀和其他功能。代码很旧,很糟糕,但如果你想看一看,你可以在这里下载(ZIP文件)。参见water.cpp
。我避免了在水流循环中分配内存。