You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中C# List RemoveAt异常:单次点击触发多次移除问题

Unity C# List 重复删除问题修复

问题根源

当生成随机索引(比如2)并触发chooseNpc事件后,所有预制体的NpcController都会执行NpcEvent判断:

  1. 第一个匹配索引的预制体执行删除操作后,List中原索引大于该值的元素会自动前移一位(比如原索引3变为2)
  2. 后续预制体执行IndexOf时,会得到新的索引值,刚好等于未更新的randNpcValue,导致重复触发移动和删除逻辑

修正方案

将选中、移动、删除的逻辑统一放在ListController中处理,避免多个预制体同时判断索引,同时移除目标对象的事件监听防止后续误触发:

修改后的 ListController 代码

public class ListController : MonoBehaviour // 修正类名拼写错误
{
    public GameObject cubePrefab;
    private GameObject cubeInstance;
    public static List<GameObject> cubeList = new List<GameObject>();

    public TextMeshProUGUI checkText;

    public static event Action chooseNpc;
    public static int randNpcValue;

    private void Start()
    {
        for(int i = 0; i < 5; i++)
        {
            cubeInstance = Instantiate(cubePrefab, new Vector3(i, -2, 0), Quaternion.identity);
            cubeList.Add(cubeInstance);
        }
    }

    public void CheckListText()
    {
        checkText.text = "Npc in list: " + cubeList.Count.ToString();
    }

    public static void SelectRandomCube()
    {
        if(cubeList.Count == 0) return; // 空列表直接返回,避免报错
        
        randNpcValue = Random.Range(0, cubeList.Count);
        var targetCube = cubeList[randNpcValue];
        
        // 执行移动逻辑
        targetCube.transform.localPosition = new Vector3(targetCube.transform.position.x, 2, 0);
        
        // 从列表移除
        cubeList.RemoveAt(randNpcValue);
        Debug.Log($"Delete from list: {randNpcValue}");
        
        // 移除目标对象的事件监听,防止后续触发
        var npcController = targetCube.GetComponent<NpcController>();
        if(npcController != null)
        {
            ListController.chooseNpc -= npcController.NpcEvent;
        }
    }
}

简化后的 NpcController 代码

如果不需要其他事件逻辑,可移除删除和移动代码(仅保留必要的事件绑定,或直接移除该脚本):

public class NpcController : MonoBehaviour
{
    void Start()
    {
        ListController.chooseNpc += NpcEvent;
    }

    private void NpcEvent()
    {
        // 这里可以保留其他需要针对选中对象执行的逻辑,比如播放动画等
        // 移动和删除逻辑已移至ListController,无需在这里处理
    }
}

额外注意事项

  • 修正了类名ListCOntroller的拼写错误为ListController,避免潜在的命名问题
  • 增加了空列表判断,防止Random.Range传入无效范围导致报错
  • 如果需要销毁预制体,可在SelectRandomCube中添加Destroy(targetCube);语句

内容的提问来源于stack exchange,提问作者qwdza54

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:45:51