2

我正在使用 C#/XNA 开发一个项目,但在自上而下的基于十六进制的网格中创建水物理时遇到了麻烦。

我们在http://www.redblobgames.com/grids/hexagons的帮助下使用 hex-tilemap 。所以我想我可以为水流实现一个算法,但我似乎无法做到正确,而且它似乎非常注重性能。

/// <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--;
        }
    }
}

现在我的问题是,你们中是否有人知道在自上而下的环境中实施水物理的方法,最好是使用基于十六进制的网格。

我查看了几个库,发现了 Smoothed-particle hydrodynamics,但我不确定它是否可以自上而下地实施,而且我似乎无法找到该方向的任何指南。

任何帮助都会很棒,甚至一些指针可能就足够了。

在此先感谢 C. Venhuizen

4

1 回答 1

2

您是否分析过您的代码以确定最慢的部分是什么?

我不太明白你的代码在做什么。您Flow是为每个图块调用一次,还是只调用一次,然后它会遍历所有图块?如果我的话,我会说为每个图块分配一个新列表会很慢。但最好的了解方式是剖析。

最初让我写http://www.redblobgames.com/grids/hexagons的东西是一个完全关于水流的自上而下的十六进制游戏。我在 1995 年写了那个游戏,最近我把它移植到了这里的网络上运行。我开始使用的算法很简单。对于每个十六进制,以随机顺序遍历

  1. calculate the water level W + elevation H
  2. calculate the same for each neighbor
  3. make up to half the water flow to the neighbor with the lowest W + H

The random order is so that the loop doesn't cause water to flow many hexes to the right but not many hexes to the left, or other such direction artifacts. Even cleaner would be to use a double buffer for this: write all the new values to a separate array, and then copy them back to the first array at the end (or swap the arrays).

Beyond that, there are tons of heuristics I used for erosion and other features of the (unfinished) game. The code is old and awful but if you want to take a look, you can download it here (ZIP file). See water.cpp. I avoided memory allocations in the water flow loop.

于 2013-12-10T15:43:26.227 回答