【问题标题】:XNA optimizations - Loop Unrolling?XNA 优化 - 循环展开?
【发布时间】:2013-12-16 22:24:13
【问题描述】:

我正在制作 XNA 游戏,我想知道是否有办法优化某些循环。例如:

我有一个 Map 类,其中包含一组图块,因此,在 Map Update() 中,我只调用每个图块 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

这就是为什么我在考虑一些优化,比如循环展开,但是,我不知道它是否适用于未定义长度的循环(我认为不是)(因为编译器在编译时不知道这些循环的长度)

总结一下:

  1. 是否可以使用循环展开来优化这些循环?
  2. 您能建议我进行其他类型的优化吗?

谢谢

【问题讨论】:

  • 你会从四叉树中受益吗?使用某种过滤器可能可以避免许多此类完整的碰撞检查。
  • google 空间分区和 Magus 提到的四叉树

标签: c# performance optimization monogame loop-unrolling


【解决方案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) 复杂度)。显然,您还需要注意不要检查数组边界之外的内容,如果您的粒子大于单个像素,可能还有其他一些细节需要处理,但您明白了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    相关资源
    最近更新 更多