unity3d 如何修复统一列表错误ArgumentOutOfRangeException?

mkshixfv  于 2022-11-16  发布在  其他
关注(0)|答案(1)|浏览(244)

我有一个GameObject,当其他有效的GameObject通过碰撞触发器时,它会在List中添加和删除它们。在某些情况下,它会随机选择List中的一个对象,并用另一个GameObject替换它。它在大多数情况下工作正常,但偶尔会给予ArgumentOutOfRangeException错误。代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BubbleScriptNecroGrab : MonoBehaviour
{

    [SerializeField] public List<GameObject> bubbleOnes = new List<GameObject>();
    [SerializeField] public List<GameObject> necroAcolytes = new List<GameObject>();
    [SerializeField] GameObject activeBubble;
    [SerializeField] GameObject necroAcolyte;

    bool necroReady = true;

    void Update()
    {

        if (bubbleOnes.Count > 0 && necroReady == true)
        {
            StartCoroutine(bubbleSignal());
        }

    }

    // These two functions add and remove eligible bubbles from its associated list
    // as they pass through the collider.
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag == "Bubble1")
        {
            GameObject other = collision.gameObject;
            bubbleOnes.Add(other);
        }

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

    // When this is called, select a random bubble from the list, delete it and
    // replace it with a prefab.
    IEnumerator bubbleSignal()
    {
        necroReady = false;
        yield return new WaitForSeconds(Random.Range(0.1f, 1.5f));
        int randomList = Random.Range(0, bubbleOnes.Count -1);                  // adding -1 reduced amount of errors
        Vector3 targetBubblePos = bubbleOnes[randomList].transform.position;    // Code seems to break on this line
        Destroy(bubbleOnes[randomList]);
        GameObject necroAcolyteClone = Instantiate(necroAcolyte, targetBubblePos, Quaternion.identity);
        necroAcolyteClone.GetComponent<AcolyteScript>().activeTarget = transform.parent.gameObject;
        necroReady = true;

    }

}

我怀疑的是,当bubbleSignal函数运行时,它选择了一个很大或最大的值,就像它从列表中漂移出碰撞器一样。我该如何修复这个问题?

46qrfjad

46qrfjad1#

一般情况下-1

int randomList = Random.Range(0, bubbleOnes.Count -1);

并不像你想的那样。
上限已经是互斥的,因此这将永远不会返回最后一个索引。
除此之外,我在你的代码中没有看到任何明显的错误(在这一点上),这将导致我假设bubbleOnes,因此randomList = 0,但由于根本没有元素,bubbleOnes[randomList]已经抛出了异常。
例如,当OnTriggerExit2D被调用时,在bubbleSignal例程或更准确地说,在WaitForSeconds例程完成之前,列表中只有一个元素。在这种情况下,您将从列表中删除最后一个元素,留下一个空列表,然后WaitForSeconds将最终完成,并到达带有空列表的异常行。
你应该处理这种情况,并做。

IEnumerator bubbleSignal()
{
    necroReady = false;

    yield return new WaitForSeconds(Random.Range(0.1f, 1.5f));

    if(bubbleOnes.Count > 0)
    {
        var randomList = Random.Range(0, bubbleOnes.Count);                  
        var targetBubblePos = bubbleOnes[randomList].transform.position;
        Destroy(bubbleOnes[randomList]);
        var necroAcolyteClone = Instantiate(necroAcolyte, targetBubblePos, Quaternion.identity);
        necroAcolyteClone.GetComponent<AcolyteScript>().activeTarget = transform.parent.gameObject;
    }

    necroReady = true;
}

一般来说,在你的用例中,我不会在Update中使用协程和轮询检查来决定是否运行它。

[SerializeField] private float minTime = 0.1f;
[SerializeField] private float maxTime = 1.5f;

private float timer;

void Start()
{
    timer = Random.Range(minTime, maxTime);
}

void Update()
{
    if (bubbleOnes.Count > 0)
    {
        timer -= Time.deltaTime;

        if(timer <= 0)
        {
            var randomList = Random.Range(0, bubbleOnes.Count);        
            var targetBubblePos = bubbleOnes[randomList].transform.position;
            Destroy(bubbleOnes[randomList]);
            var necroAcolyteClone = Instantiate(necroAcolyte, targetBubblePos, Quaternion.identity);
            necroAcolyteClone.GetComponent<AcolyteScript>().activeTarget = transform.parent.gameObject;

            timer += Random.Range(minTime, maxTime);
        }
    } 
    // [optionally]
    // Instead of just continuing the counter from where it stopped last time
    // you could also reset it while the list is empty
    else
    {
        timer = Random.Range(minTime, maxTime);
    }
}

通过这种方式,您可以确保不存在计时问题,因为所有代码只有在列表在该时刻不为空时才实际执行。

相关问题