为什么循环没有从列表中删除所有不以“CM”开头的项目?

Dan*_*Lip 2 c# unity-game-engine

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using System.Linq;

public class CamerasInfo : MonoBehaviour
{
    public List<CinemachineFreeLook> FreeLook;
    public List<CinemachineVirtualCamera> Virtual;
    public List<Camera> AllCameras;
    public List<string> currentActiveCameras;

    // Start is called before the first frame update
    void Start()
    {
        Cameras();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void Cameras()
    {
        FreeLook = FindObjectsOfType<CinemachineFreeLook>().ToList();
        Virtual = FindObjectsOfType<CinemachineVirtualCamera>().ToList();
        for(int i = 0; i < Virtual.Count; i++)
        {
            if (!Virtual[i].name.StartsWith("CM"))
                Virtual.RemoveAt(i);
        }

        AllCameras = Camera.allCameras.ToList();

        foreach (CinemachineFreeLook freelook in FreeLook)
        {
            if (freelook.isActiveAndEnabled)
                currentActiveCameras.Add(freelook.Name);
        }

        foreach (CinemachineVirtualCamera vir in Virtual)
        {
            if (vir.isActiveAndEnabled)
                currentActiveCameras.Add(vir.Name);
        }

        for(int i = 0; i < AllCameras.Count; i++)
        {
            if (AllCameras[i].isActiveAndEnabled)
                currentActiveCameras.Add(AllCameras[i].name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这部分有 8 个摄像头在虚拟监听:

for(int i = 0; i < Virtual.Count; i++)
            {
                if (!Virtual[i].name.StartsWith("CM"))
                    Virtual.RemoveAt(i);
            }
Run Code Online (Sandbox Code Playgroud)

相机

但它只删除了 3 个摄像头而不是 6 个。最后我应该只留下两个以 CM 开头的摄像头,但在编辑器中有 5 个摄像头:

它不会删除底部顶部和中间:

相机

can*_*on7 5

问题是您正在遍历列表,同时还从中删除项目。

让我们举个例子

 0       1       2
[TopRig, TopRig, CM]
Run Code Online (Sandbox Code Playgroud)

我们进入for循环,i = 0。我们查看元素 0,即TopRig,因此我们调用.RemoveAt(0)。我们的名单现在是:

 0       1
[TopRig, CM]
Run Code Online (Sandbox Code Playgroud)

我们现在进入for循环的下一次迭代,并且i增量为 1。我们查看(修改后的)列表的元素 1,并看到它是CM

看到问题了吗?我们直接跳过了第二个TopRig,因为我们从列表中删除了一个元素(导致所有后续元素向后移动),并且还 increment i。我们需要确保我们只递增i,如果我们从列表中删除一个项目:

for (int i = 0; i < Virtual.Count; /* no increment */)
{
    if (!Virtual[i].name.StartsWith("CM"))
        Virtual.RemoveAt(i);
    else
        i++;
}
Run Code Online (Sandbox Code Playgroud)

或考虑到它会增加的事实:

for (int i = 0; i < Virtual.Count; i++)
{
    if (!Virtual[i].name.StartsWith("CM"))
    {
        Virtual.RemoveAt(i);
        i--;
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以向后遍历列表,从而回避问题:

for (int i = Virtual.Count - 1; i >= 0; i--)
{
    if (!Virtual[i].name.StartsWith("CM"))
        Virtual.RemoveAt(i);
}
Run Code Online (Sandbox Code Playgroud)