Optimization 战争之雾与二维网格
首先,我正在使用XNA框架开发一个2D战略游戏 我正在为我的游戏实现2D战争迷雾。图形部分已经完成,并且工作得很好,但是我现在尝试实现战争迷雾的“逻辑”部分 我创建了一个代表我的标高的二维网格。每一帧,每一个单元都会使用Bresenham的算法(这似乎是找出给定圆中哪些单元的最佳方法)更新周围一个圆中的单元。 这实际上是有效的。。。当我想知道一个给定的位置是否可见时,我只需要得到细胞的状态 问题是,当我有大量的衍生单位时,我的游戏运行得太慢了。。。 出现此性能问题的第一个原因是,由于每个单元都会更新其周围的单元,因此许多单元会多次更新。。。但我看不出有什么解决办法 所以。。。也许我用这种方式实现它是错误的,或者也许我错过了一个明显的优化,但我有点卡住了 代码如下:Optimization 战争之雾与二维网格,optimization,Optimization,首先,我正在使用XNA框架开发一个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;
}
class-LevelGridCell
{
公共无效设置可见(浮动时间)
{
if(m_可视时间=a_时间);
}
浮动m_visibleTime=0;
}
类级别网格
{
公共级别GridCell GetAt(整数x,整数y)
{
返回m_网格[a_x+a_y*m_宽度];
}
公共无效设置可见(浮动a_时间、整数a_x、整数a_y、浮动a_半径)
{
GetAt(a_x,a_y).SetVisible(a_time);
intintradius=(int)(a_半径/m_单元大小);
intx=0,y=intRadius,p=1-intRadius;
PlotSetVisible(a_x,a_y,x,y,a_时间);
while(x=0和&a_x=0和&a_y 对于(int i=xctr-x;i,如果没有看到您的代码,我们不得不猜测问题可能是什么。如果您已经分析了您的代码,您应该能够找出哪些部分特别慢;根据这些信息,您可以直接解决问题
以下是一些关于哪些位可能慢的猜测:
- 一个圆就是一个圆。你对每个单位都遵循Bresenham的圆算法吗?看起来你可以只计算一次圆,相对于(0,0)。然后,对于(x,y)处的单位,你只需查找圆并将圆中的点偏移到(x,y),然后对该单位应用战争迷雾逻辑
- 战争迷雾只会对最近移动过的单位进行更改。如果某个单位处于静止状态,则可能不需要再次计算其可见性。您是否能够将这种优化应用于战争迷雾可见性规则
- Bresenham的圆算法有助于绘制圆的边缘。如何填充圆的内部?是否应该找到更好的填充范围内部的算法
一条评论询问了有关使用一个生成的圆的更多详细信息,因此我在这里添加了一些注释。(编辑答案是这样做的吗?对不起,我对Stack Exchange比较陌生。)
“战争之雾”通常意味着一个单位可以看到周围的一些半径。你的单位的半径是多少?每种单位类型有不同的半径吗?有多少种单位类型
假设一个单位类型的可见性范围的半径为5个正方形。这就给我们留下了一个圆,看起来像这样:
00001110000
00010001000
00100000100
01000000010
10000000001
10000x00001
10000000001
01000000010
00100000100
00010001000
00001110000
因为我们有一个圆,我们知道我们不必做任何太难的事情来填充它。一个简单的算法将在最右边的1和最左边的1之间通过每一行填充。这将比求解Breshenham的算法来填充所有内部点快得多
使用填充圆,我们找到这个数组,然后:
00001110000
00011111000
00111111100
01111111110
11111111111
11111x11111
11111111111
01111111110
00111111100
00011111000
00001110000
现在,如果我们有一个半径为5平方可视的单位,将战争之雾应用到该单位就意味着将这个预先计算的数组应用到战争之雾数组,这样这个预先计算的数组的中心就在我们正在处理的单位上。你可以用一个简单的嵌套循环来完成,一旦你计算了从中心的偏移量,然后剪辑t他将数组的边界设置为地图的边缘
如果你有几个不同的战争迷雾可视半径,你可以预先计算几个不同的阵列。如果你有规则说你的战争迷雾因障碍物(如地形、建筑物或景观)而不同,那么你必须做更多的处理,但预计算的想法仍然可以应用。K.I.S.S
为什么每次都要计算一个圆?那太贵了
这样想。当你在paint.exe中编辑一张图片时,选中大画笔,你会认为每次都在计算这个圆吗?当你在Photoshop中选择一个奇特的或自定义形状的画笔时,它是如何工作的
你只需要计算一次圆,即使是(我会硬编码,上面的巴迪已经给了你一个快速通道)
const char circle[]={
00001110000
00011111000
00111111100
01111111110
11111111111
11111 X11111您是否分析了您的代码以查看哪些部分是瓶颈吗?你每次都在重新计算整个战争迷雾吗?你能代替计算每次人移动时的差异吗?当你说战争迷雾的逻辑部分时,你是指决定向用户显示还是隐藏它,还是单位是否能看到某个点?@AbstractChaos I
const char circle[] = {
00001110000
00011111000
00111111100
01111111110
11111111111
11111x11111 <-- put this into a static C array
11111111111
01111111110
00111111100
00011111000
00001110000
}