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

如何修复Unity中List的ArgumentOutOfRangeException异常?

问题根源分析

你怀疑的点完全正确:协程bubbleSignal执行时,先等待了0.1-1.5秒,这段时间内目标气泡可能已经移出碰撞体,被OnTriggerExit2D从bubbleOnes列表中移除。同时原代码的随机索引计算还有错误:

  • Unity的Random.Range(int min, int max)是左闭右开区间,Random.Range(0, bubbleOnes.Count -1)会漏掉最后一个元素的索引;当列表长度变为1时,bubbleOnes.Count -1等于0,此时调用Random.Range(0,0)会触发参数错误,直接导致索引越界。
修复方案

针对这两个问题,我们可以通过以下步骤解决:

  1. 修正随机索引逻辑:使用Random.Range(0, bubbleOnes.Count)来覆盖所有有效索引。
  2. 避免索引失效:在等待前先选中目标对象(而非索引),等待完成后检查该对象是否仍在列表中,确保操作的对象是有效的。
  3. 空列表防护:在协程开始和等待后都检查列表状态,避免对空列表进行操作。
修复后的完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BubbleScriptNecroGrab : MonoBehaviour
{
    [SerializeField] private List<GameObject> bubbleOnes = new List<GameObject>();
    [SerializeField] private List<GameObject> necroAcolytes = new List<GameObject>();
    [SerializeField] private GameObject activeBubble;
    [SerializeField] private GameObject necroAcolyte;

    private bool necroReady = true;

    void Update()
    {
        if (bubbleOnes.Count > 0 && necroReady)
        {
            StartCoroutine(bubbleSignal());
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Bubble1"))
        {
            GameObject targetBubble = collision.gameObject;
            // 避免重复添加同一个对象
            if (!bubbleOnes.Contains(targetBubble))
            {
                bubbleOnes.Add(targetBubble);
            }
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("Bubble1"))
        {
            GameObject targetBubble = collision.gameObject;
            bubbleOnes.Remove(targetBubble);
        }
    }

    IEnumerator bubbleSignal()
    {
        necroReady = false;

        // 启动协程时先检查列表是否为空
        if (bubbleOnes.Count == 0)
        {
            necroReady = true;
            yield break;
        }

        // 等待前先锁定目标对象,而非索引
        GameObject targetBubble = bubbleOnes[Random.Range(0, bubbleOnes.Count)];
        yield return new WaitForSeconds(Random.Range(0.1f, 1.5f));

        // 等待后检查目标是否仍在列表中(未被移除)
        if (bubbleOnes.Contains(targetBubble))
        {
            Vector3 targetPos = targetBubble.transform.position;
            Destroy(targetBubble);
            // 主动从列表移除已销毁的对象,避免残留无效引用
            bubbleOnes.Remove(targetBubble);

            GameObject acolyteClone = Instantiate(necroAcolyte, targetPos, Quaternion.identity);
            acolyteClone.GetComponent<AcolyteScript>().activeTarget = transform.parent.gameObject;
        }

        necroReady = true;
    }
}

额外优化点:

  • 使用CompareTag替代直接比较tag,效率更高且避免拼写错误。
  • 添加重复添加防护,防止同一个气泡多次进入触发器时被重复加入列表。
  • 销毁对象后主动从列表移除,避免列表中残留已销毁的无效引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:40:34