战争迷雾和2D网格

s0u*_*bap 4 optimization

首先,我正在使用XNA框架开发2D策略游戏.

我正在为我的游戏实施2D战争迷雾.图形部分已经完成并且工作得非常好,但我现在正试图实现这场战争迷雾的"逻辑"部分.

我创建了一个代表我的关卡的2D网格.每个框架,每个单元使用Bresenham的算法(它似乎是确定给定圆中哪些单元格的最佳方法)更新围绕它的圆圈.这实际上是有效的......当我想知道某个位置是否可见时,我只需要获得该单元的状态......

问题是,当我有大量的衍生单位时,我的游戏运行得如此缓慢......这个性能问题的第一个原因是,由于每个单元更新它周围的单元格,许多单元格会多次更新...但我看不出任何解决方案......

所以...也许我错了以这种方式实现它,或者我可能错过了一个明显的优化,但我有点卡住......

这是代码:

class LevelGridCell
{
    public void SetVisible(float a_time)
    {
        if (m_visibleTime < a_time)
            m_visibleTime = a_time;
    }
    public bool IsVisible(float a_time)
    {
        return (m_visibleTime != 0f && m_visibleTime >= a_time);
    }

    float m_visibleTime = 0;
}

class LevelGrid
{
    public LevelGridCell GetAt(int a_x, int a_y)
    {
        return m_grid[a_x + a_y * m_width];
    }

    public void SetVisible(float a_time, int a_x, int a_y, float a_radius)
    {
        GetAt(a_x, a_y).SetVisible(a_time);

        int intRadius = (int)(a_radius / m_cellSize);
        int x = 0, y = intRadius, p = 1 - intRadius;
        PlotSetVisible(a_x, a_y, x, y, a_time);
        while (x < y)
        {
            x++;
            if (p < 0)
                p += 2 * x + 1;
            else
            {
                y--;
                p += 2 * (x - y) + 1;
            }
            PlotSetVisible(a_x, a_y, x, y, a_time);
        }
    }
    private void SafeSetVisible(int a_x, int a_y, float a_time)
    {
        if (a_x >= 0 && a_x < m_width && a_y >= 0 && a_y < m_height)
        {
            GetAt(a_x, a_y).SetVisible(a_time);
        }
    }
    private void PlotSetVisible(int xctr, int yctr, int x, int y, float a_time)
    {

        for (int i = xctr - x; i <= xctr + x; ++i)
        {
            SafeSetVisible(i, yctr + y, a_time);
            SafeSetVisible(i, yctr - y, a_time);
        }
        for (int i = xctr - y; i <= xctr + y; ++i)
        {
            SafeSetVisible(i, yctr + x, a_time);
            SafeSetVisible(i, yctr - x, a_time);
        }
    }

    List<LevelGridCell> m_grid = new List<LevelGridCell>();
    float m_cellSize;
    int m_width;
    int m_height;
}
Run Code Online (Sandbox Code Playgroud)

Mik*_*keB 5

在没有看到您的代码的情况下,我们不得不猜测问题可能是什么.如果您已经分析了代码,那么您应该能够找出哪个部分特别慢; 鉴于这些信息,您可以直接解决问题.

以下是关于哪些位可能很慢的几个猜测:

  • 圆圈是圆圈.你是否关注每个单位的Bresenham圆圈算法?看起来你可以只计算一次圆,相对于(0,0).然后,对于(x,y)处的单位,您可以简单地查找圆并将圆中的点偏移到(x,y),然后将战争逻辑雾应用于该单位.

  • 战争迷雾只会改变最近移动的单位.如果一个单位是静止的,那么您可能不需要再次计算其可见性.您是否能够将此类优化应用于战争迷雾可见性规则?

  • Bresenham的圆形算法可帮助您绘制圆的边缘.你是如何填充圆圈内部的?您是否应该找到更好的算法来填充范围的内部?

评论询问有关使用一个生成的圆的更多详细信息,所以在这里我添加一些关于它的注释.(正在编辑答案的方式吗?抱歉,我对Stack Exchange相对较新.)

"战争迷雾"通常意味着一个单位可以看到它周围的一些半径.你单位的半径是多少?每种单位类型的半径是否不同?有多少单位类型?

假设一个单位类型的可见范围半径为5个方格.这给我们留下了一个如下所示的圆圈:

00001110000
00010001000
00100000100
01000000010
10000000001
10000x00001
10000000001
01000000010
00100000100
00010001000
00001110000
Run Code Online (Sandbox Code Playgroud)

由于我们有一个圆圈,我们知道我们不必做任何太难以填补的事情.一个简单的算法将遍历最右边1和最左边1之间的每一行.这将比解决所有内部点的Breshenham算法快得多.

使用实心圆圈,我们找到这个数组,然后:

00001110000
00011111000
00111111100
01111111110
11111111111
11111x11111
11111111111
01111111110
00111111100
00011111000
00001110000
Run Code Online (Sandbox Code Playgroud)

现在,如果我们有一个半径为5个方格可见度的单位,将战争雾应用于该单位只意味着将这个预先计算的数组应用于战争数组的雾,这样这个预先计算的数组的中心就在我们的单位上处理.一旦从中心计算偏移量并将数组的边界剪切到地图的边缘,就可以使用简单的嵌套循环执行此操作.

如果您有几个不同的半径用于战争迷雾,您可以预先计算几个不同的阵列.如果你有规则说你的战争迷雾因障碍物(如地形或建筑物或风景)而变化,那么你必须做更多的处理,但仍然可以应用预计算的想法.