优化六角网格上的移动

时间:2012-06-25 03:48:27

标签: c# recursion hexagonal-tiles

我正在制作一个基于转弯的六角网格游戏。玩家选择单位并在十六进制网格中移动它们。网格中的每个图块都是特定的地形类型(例如沙漠,丘陵,山脉等),每个单位类型在地形上移动时具有不同的能力(例如,一些可以轻松地在山上移动,一些有困难而且有些根本没有。)

每个单位都有一个移动值,每个单位根据其地形类型和单位类型进行一定程度的移动。例如,它需要一个坦克1才能越过沙漠,4个越过沼泽并且无法在山上移动。飞行单位以1的成本移动到所有地方。

我遇到的问题是,当选择一个单位时,我想突出显示它周围的区域,显示它可以移动的位置,这意味着计算出通过周围六边形的所有可能路径,每个路径将采取多少移动和根据该信息点亮瓷砖。

我使用递归函数工作,发现计算花了太长时间,我将函数移动到一个线程中,这样它就不会阻塞游戏,但是线程计算可移动性需要大约2秒钟移动8的单位面积。 它有超过一百万次递归,这显然是有问题的。

我想知道是否有人对如何优化此问题有一个聪明的想法。

这是我目前正在使用的递归函数(它的C#btw):

private void CalcMoveGridRecursive(int nCenterIndex, int nMoveRemaining)
{
    //List of the 6 tiles adjacent to the center tile
    int[] anAdjacentTiles = m_ThreadData.m_aHexData[nCenterIndex].m_anAdjacentTiles;

    foreach(int tileIndex in anAdjacentTiles)
    {
        //make sure this adjacent tile exists
        if(tileIndex == -1)
            continue;

        //How much would it cost the unit to move onto this adjacent tile
        int nMoveCost = m_ThreadData.m_anTerrainMoveCost[(int)m_ThreadData.m_aHexData[tileIndex].m_eTileType];

        if(nMoveCost != -1 && nMoveCost <= nMoveRemaining)
        {
            //Make sure the adjacent tile isnt already in our list.
            if(!m_ThreadData.m_lPassableTiles.Contains(tileIndex))
                m_ThreadData.m_lPassableTiles.Add(tileIndex);

            //Now check the 6 tiles surrounding the adjacent tile we just checked (it becomes the new center).
            CalcMoveGridRecursive(tileIndex, nMoveRemaining - nMoveCost);
        }
    }
}

在递归结束时,m_lPassableTiles包含一个单元可能达到的所有图块的索引列表,并使它们发光。

一切正常,只需要太长时间。有没有人知道更好的方法呢?

2 个答案:

答案 0 :(得分:0)

如您所知,使用递归函数,您希望尽可能简化问题。这仍然看起来像是试图立刻咬掉太多。几个想法:

  1. 尝试使用HashSet结构来存储m_lPassableTiles?您可以通过这种方式避免Contains条件,这通常是一项昂贵的操作。

  2. 我没有彻底测试过这个问题的逻辑,但你可以在foreach循环之前设置一个基本案例吗?即,nMoveRemaining == 0

  3. 在不知道您的程序是如何在内部设计的情况下,我希望m_anAdjacentTiles无论如何都只包含现有的切片,因此您可以取消该检查(tileIndex == -1)。不是一个巨大的性能提升,但使您的代码更简单。

  4. 顺便说一下,我认为这样做的游戏,如文明V,只计算移动成本,因为用户建议将单位移动到某个位置。换句话说,您选择一个图块,它会显示它将采取多少动作。这是一种更有效的操作。

    当然,当你移动一个单位时,周围的土地被揭示 - 但我认为只有单位可以在一个“转弯”中移动才能显示土地,然后在移动时会显示更多。如果您选择将几个转弯移动到未知区域,最好仔细观察或一次转动一圈。 :)

    (适用后来...)

    等等,一百万次递归?是的,我认为这是正确的数学:6^8(8是可用的运动) - 但你的网格真的那么大吗? 1000×1000?该单位实际可以穿过多少个瓷砖?假设不同的地形类型,在任何给定方向上平均可能是4或5?

    如果我错了(因为我不知道你的底层设计),请纠正我,但我认为有一些重叠...主要重叠。它正在检查已检查的相邻瓷砖的相邻瓷砖。我认为唯一可以避免无限递归的事情就是检查剩下的动作。

    将图块添加到m_lPassableTiles后,将其从接收到您的函数中的任何相邻图块列表中删除。你在Contains的行中做了类似的事情......如果你附上if语句来包含你的递归调用怎么办?这应该会将你的递归调用从最多100万+减少到数千......我想。

答案 1 :(得分:0)

感谢大家的投入。我通过用Dijkstra's Algorithm替换Recursive函数解决了这个问题,它完美无缺。