XNA Waterphysics自上而下十六进制网格

时间:2013-12-09 16:40:41

标签: c# xna game-physics hexagonal-tiles top-down

我正在使用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--;
        }
    }
}

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

我已经查看了几个版本,发现了平滑粒子流体动力学,但我不确定它是否可以自上而下实现,而且我似乎找不到任何指导方向。

任何帮助都会很棒,即使是一些指针也足够了。

提前致谢, C. Venhuizen

1 个答案:

答案 0 :(得分:2)

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

我不太明白你的代码在做什么。你是为每个瓷砖拨打一次Flow,还是只召唤一次,它会在所有瓷砖上运行?如果我要猜测,我会说每个瓷砖分配一个新列表会非常慢。但最好的方法就是分析。

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

  1. 计算水位 W + 海拔 H
  2. 为每个邻居计算相同的内容
  3. 补充一半水流到邻居,W + H
  4. 最低

    随机顺序是这样的循环不会导致水流向右边的许多六边形,但左边没有多少个六边形或其他这样的方向伪影。更简洁的是使用双缓冲区:将所有新值写入单独的数组,然后将它们复制回最后的第一个数组(或交换数组)。

    除此之外,还有大量的启发式技术用于侵蚀和(未完成)游戏的其他功能。代码很旧很糟糕但是如果你想看一下,可以下载它here(ZIP文件)。见water.cpp。我在水流循环中避免了内存分配。