限制 For 循环中的列表迭代(最接近玩家)

Limiting List Iterations in a For Loop (Closest To Player)

我有一个 List<Collider> colliders 用于瓦片地图。

我想到的一种方法是检查所有碰撞器位置的完整列表,与玩家的位置进行比较,然后将最近的碰撞器添加到临时列表以加快迭代速度。仅每 100 毫秒执行一次此操作将减少性能损失。但我想还有比这更好的方法,对吧?

我在这里阅读了一个不同的 post 以进行碰撞优化,它提到使用 "CPU Budget",我打算为此和其他人实施。我还没有读过线程。

较短的问题:如何将最大迭代次数限制为仅距离玩家最近的对撞机?

您可以尝试类似的方法:

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;

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

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

使用 Stopwatch,迭代 1,000 次,range 为 20:

  • 10,000 个列表:始终为 0 毫秒
  • 50,000 个列表:平均 2 毫秒。
  • 100,000 个列表:平均 4 毫秒。
  • 250,000 人名单:平均 12 毫秒。

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

为了减少要检查的碰撞器的数量,您可以预先将它们从候选列表中排除。将碰撞器保留在 Dictionary colliders 中,同时创建第二个 Dictionary > 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
    }
}

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