我正在制作一个XNA游戏,我想知道是否有一种优化某些循环的方法。例如:
我有一个Map类,其中包含一组tile,因此,在Map Update()中我只调用每个tile Update()
// Update method in Map Class
public void Update()
{
for (int index = 0; index < tiles.Count; index++)
{
tiles[index].Update();
}
}
这样可以正常工作但是,对于一些较大的填充对象,例如Particle类,其中每个粒子都使用ParticleManager类(包含粒子集合)进行管理,因此可能会变得更糟:
// Update method in ParticleManager class
public void Update()
{
for (int index = 0; index < particle.Count; index++)
{
particle[index].Update();
}
}
//Update Method in Particle class
public void Update()
{
for (int index = 0; index < Map.tiles.Count; index++)
{
CheckCollitions(Map.tile[index], this);
}
}
ParticleManager循环每个粒子,每个粒子检查每个Tile的碰撞。 因此,如果您有20个粒子和100个Tiles,它将进行大量计算:
20 loops cycles * 100 loops cycles
这就是为什么我在考虑一些优化,比如循环展开,但是,我不知道它是否有效(我认为没有)带有未定义的长度循环(导致编译器在编译时不知道那些循环长度)< / p>
总结一下:
由于
答案 0 :(得分:1)
首先,循环展开是一种微观优化,不会带来很多好处。在完全需要之前不要打扰。
更重要的是,优化代码的方式更多的是使用的数据结构和算法,而不是迭代集合的速度。
在您的特定示例中,您实际上正在执行此操作。
for (int p = 0; p < particle.Count; p++)
{
for (int t = 0; t < Map.tiles.Count; t++)
{
CheckCollitions(Map.tile[t], particle[p]);
}
}
这样的嵌套循环表明O(n ^ 2)的复杂性,是潜在性能问题的明确标志。
通常,当您使用碰撞检测时,可以通过根据您已知的事物减少可能发生碰撞的对象数量来优化代码。
例如,我假设瓷砖不会移动并以均匀的网格布局。我也可以假设粒子非常小。
假设您将切片数据存储在二维数组中。
var tiles = new int[32,32];
值0表示没有图块,值1(或> 0)表示图块是实心的。您还知道,当在屏幕上呈现切片时,它们是64x64像素。
这意味着,您可以使用简单的数学运算快速地对任何图块进行基本碰撞测试。
for (int p = 0; p < particle.Count; p++)
{
var tileWidth = 64;
var tileHeight = 64;
var particlePosition = particle[p].Position;
var tx = particlePosition.X / tileWidth;
var ty = particlePosition.Y / tileHeight;
var tile = tiles[tx, ty];
if(tile == 0)
{
// no collision
}
else
{
// collision detected
}
}
此时,您确切地知道粒子位置落入阵列中的哪个瓦片并移除内部循环(有效地将其降低到O(n)复杂度)。显然,你还需要注意不要在数组边界外检查,如果粒子大于单个像素,可能还有其他一些细节可以处理,但你明白了。