限制For循环中的列表迭代(最接近播放器)

时间:2015-02-12 22:46:18

标签: c# optimization xna collision

我有一张List<Collider> colliders用于图块地图。

我想到的一种方法是检查所有碰撞器的完整列表&#39;位置,与玩家的位置进行比较,然后将最近的碰撞者添加到临时列表中,以便更快地进行迭代。每100ms只执行一次会降低性能损失。但我想象有比这更好的方法,对吗?

我已经在这里阅读了一篇关于碰撞优化的不同帖子,并且提到了使用&#34; CPU Budget&#34;,我打算为此实现这一点以及其他。我还没有读过有关线程的信息。

更短的问题:如何将最大迭代次数限制为最接近玩家的碰撞者?

3 个答案:

答案 0 :(得分:2)

要减少要检查的碰撞器数量,您可以先将它们从候选列表中排除。将对手保留在字典对撞机中,并创建第二个字典&gt; collidersByChunks 即可。作为第二个字典中的键使用块的坐标,并作为值使用碰撞器的子列表。像这样:

class ColliderManager
{
    Dictionary<TKey, Collider> colliders;
    Dictionary<Vector2, List<TKey>> collidersByChunks;

    public void AddCollider(TKey pKey, Collider pCOllider)
    {
        this.colliders.Add(pKey, pCollider);

        foreach(Vector2 chunkCoord in this.GetChunkCoords(pCollider.Rectangle))
        {
            List<TKey> collidersAtChunk = null;
            if(!this.collidersByChunks.TryGetValue(chunkCoord, out collidersAtChunk))
            {
                collidersAtChunk = new List<TKey>();
                this.collidersByChunks.Add(chunkCoords, collidersAtChunk);
            }

            collidersAtChunk.Add(pKey, pCollider);
        }
    }

    private Vector2[] GetChunkCoords(Rectangle pRectangle)
    {
        // return all chunks pRectangle intersects
    }
}

检查时确定哪些块穿过扫描对象并仅将其与来自该块的碰撞器进行比较。

答案 1 :(得分:1)

我发现使用List.Where()在这种情况下效果最好。 100,000个碰撞器的列表(有点极端,但很可能在512x512地图上),使用:

foreach (TestCollider test in integers.Where(c => c.IsInRange() == true)) { }

使用Stopwatch,迭代1000次,range为20:

  • 10,000:0ms的列表总是
  • 50,000:2ms avg。
  • 的列表
  • 100,000:4ms平均值列表
  • 250,000:12 ms avg。
  • 的列表

如果有人有任何改进建议,我会很乐意更新。

答案 2 :(得分:0)

您可以尝试以下方式:

foreach (Collider collider in colliders.OrderBy(c => c.Position - player.Position))
{
    // The tiles closest to the player should be at the start
    if (collider.Rectangle.Intersects(player.Rectangle))
    {
        // Do whatever you want to do here
        Break;
    }
}

不要忘记在代码顶部添加using System.Linq;