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

Unity开发游戏触发ArgumentOutOfRangeException异常求助

Unity开发中的索引越界异常问题

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <00000000000000000000000000000000>:0)
GameController.Update () (at Assets/Scripts/GameController.cs:95)

项目存在多个错误,但唯有此异常导致项目完全无法运行,异常位于第95行。

完整代码

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;

public class GameController : MonoBehaviour {

    private CubePos nowCube = new CubePos(0, 1, 0);
    public float cubeChangePlaceSpeed = 0.5f;
    public Transform cubeToPlace;

    private float camMoveToYPosition, camMoveSpeed = 2f;

    public Text scoreTxt;

    public GameObject[] cubesToCreate;

    public GameObject allCubes, vfx;
    public GameObject[] canvasStartPage;
    private Rigidbody allCubesRb;

    public Color[] bgColors;
    private Color toCameraColor;

    private bool IsLose, firstCube;

    private List<Vector3> allCubesPositions = new List<Vector3> {
        new Vector3(0, 0, 0),
        new Vector3(1, 0, 0),
        new Vector3(-1, 0, 0),
        new Vector3(0, 1, 0),
        new Vector3(0, 0, 1),
        new Vector3(0, 0, -1),
        new Vector3(1, 0, 1),
        new Vector3(-1, 0, -1),
        new Vector3(-1, 0, 1),
        new Vector3(1, 0, -1),
    };

    private int prevCountMaxHorizontal = 0;
    private Transform mainCam;
    private Coroutine showCubePlace;

    private List<GameObject> posibleCubesToCreate = new List<GameObject>();

    private void Start() {

        if (PlayerPrefs.GetInt("score") < 5)
            posibleCubesToCreate.Add(cubesToCreate[0]);
        else if(PlayerPrefs.GetInt("score") < 10)
            AddPossibleCubes(2);
        else if (PlayerPrefs.GetInt("score") < 15)
            AddPossibleCubes(3);
        else if (PlayerPrefs.GetInt("score") < 25)
            AddPossibleCubes(4);
        else if (PlayerPrefs.GetInt("score") < 35)
            AddPossibleCubes(5);
        else if (PlayerPrefs.GetInt("score") < 50)
            AddPossibleCubes(6);
        else if (PlayerPrefs.GetInt("score") < 75)
            AddPossibleCubes(7);
        else if (PlayerPrefs.GetInt("score") < 100)
            AddPossibleCubes(8);

        scoreTxt.text = "<size=47><color=#d58508>best:</color></size> " + PlayerPrefs.GetInt("score") + " <size=33>now:</size> ";

        toCameraColor = Camera.main.backgroundColor;

        mainCam = Camera.main.transform;
        camMoveToYPosition = 5.9f + nowCube.y - 1f;

        allCubesRb = allCubes.GetComponent<Rigidbody>();
        showCubePlace = StartCoroutine(ShowCubePlace());
    }

    private void Update() {
        if((Input.GetMouseButtonDown(0) || Input.touchCount > 0) && cubeToPlace != null && allCubes != null && !EventSystem.current.IsPointerOverGameObject()) {
#if !UNITY_EDITOR
            if (Input.GetTouch(0).phase != TouchPhase.Began)
                return;
#endif

            if(!firstCube) {
                firstCube = true;
                foreach (GameObject obj in canvasStartPage)
                    Destroy(obj);
            }

            GameObject createCube = null;
            if (posibleCubesToCreate.Count == 1)
                createCube = posibleCubesToCreate[0];
            else
                createCube = posibleCubesToCreate[UnityEngine.Random.Range(0, posibleCubesToCreate.Count)];

            GameObject newCube = Instantiate(
                createCube,
                cubeToPlace.position,
                Quaternion.identity) as GameObject;

            newCube.transform.SetParent(allCubes.transform);
            nowCube.setVector(cubeToPlace.position);
            allCubesPositions.Add(nowCube.getVector());

            if (PlayerPrefs.GetString("music") != "No")
                GetComponent<AudioSource>().Play();

            GameObject newVfx = Instantiate(vfx, newCube.transform.position, Quaternion.identity) as GameObject;
            Destroy(newVfx, 1.5f);

            allCubesRb.isKinematic = true;
            allCubesRb.isKinematic = false;

            SpawnPositions();
            MoveCameraChangeBg();
        }

//无法使用该代码(游戏失败后删除主立方体)

        /*
                if (!IsLose && allCubesRb.velocity.magnitude < 0.1f)
                {
                    Destroy(cubeToPlace.gameObject);
                    IsLose = true;
                    StopCoroutine(showCubePlace);
                }
        */

        mainCam.localPosition = Vector3.MoveTowards(mainCam.localPosition,
            new Vector3(mainCam.localPosition.x, camMoveToYPosition, mainCam.localPosition.z),
            camMoveSpeed * Time.deltaTime);

        if (Camera.main.backgroundColor != toCameraColor)
            Camera.main.backgroundColor = Color.Lerp(Camera.main.backgroundColor, toCameraColor, Time.deltaTime / 1.5f);
    }


    IEnumerator ShowCubePlace() {
        while(true) {
            SpawnPositions();

            yield return new WaitForSeconds(cubeChangePlaceSpeed);
        }
    }

    private void SpawnPositions() {
        List<Vector3> positions = new List<Vector3>();
        if (IsPositionEmpty(new Vector3(nowCube.x + 1, nowCube.y, nowCube.z))
            && nowCube.x + 1 != cubeToPlace.position.x)
            positions.Add(new Vector3(nowCube.x + 1, nowCube.y, nowCube.z));
        if (IsPositionEmpty(new Vector3(nowCube.x - 1, nowCube.y, nowCube.z))
            && nowCube.x - 1 != cubeToPlace.position.x)
            positions.Add(new Vector3(nowCube.x - 1, nowCube.y, nowCube.z));
        if (IsPositionEmpty(new Vector3(nowCube.x, nowCube.y + 1, nowCube.z))
            && nowCube.y + 1 != cubeToPlace.position.y)
            positions.Add(new Vector3(nowCube.x, nowCube.y + 1, nowCube.z));
        if (IsPositionEmpty(new Vector3(nowCube.x, nowCube.y - 1, nowCube.z))
            && nowCube.y - 1 != cubeToPlace.position.y)
            positions.Add(new Vector3(nowCube.x, nowCube.y - 1, nowCube.z));
        if (IsPositionEmpty(new Vector3(nowCube.x, nowCube.y, nowCube.z + 1))
            && nowCube.z + 1 != cubeToPlace.position.z)
            positions.Add(new Vector3(nowCube.x, nowCube.y, nowCube.z + 1));
        if (IsPositionEmpty(new Vector3(nowCube.x, nowCube.y, nowCube.z - 1))
            && nowCube.z - 1 != cubeToPlace.position.z)
            positions.Add(new Vector3(nowCube.x, nowCube.y, nowCube.z - 1));


        if (positions.Count > 1)
            cubeToPlace.position = positions[UnityEngine.Random.Range(0, positions.Count)];
        else if (positions.Count == 0)
            IsLose = true;
        else
            cubeToPlace.position = positions[0];
    }

    private bool IsPositionEmpty(Vector3 targetPos) {
        if (targetPos.y == 0)
            return false;

        foreach(Vector3 pos in allCubesPositions) {
            if (pos.x == targetPos.x && pos.y == targetPos.y && pos.z == targetPos.z)
                return false;
        }
        return true;
    }

    private void MoveCameraChangeBg() {
        int maxX = 0, maxY = 0, maxZ = 0, maxHor;

        foreach(Vector3 pos in allCubesPositions) {
            if (Mathf.Abs(Convert.ToInt32(pos.x)) > maxX)
                maxX = Convert.ToInt32(pos.x);

            if (Convert.ToInt32(pos.y) > maxY)
                maxY = Convert.ToInt32(pos.y);

            if (Mathf.Abs(Convert.ToInt32(pos.z)) > maxZ)
                maxZ = Convert.ToInt32(pos.z);
        }

        // 记录分数代码 27.02.23

        maxY--;

        if (PlayerPrefs.GetInt("score") < maxY)
            PlayerPrefs.SetInt("score", maxY);

        scoreTxt.text = "<size=47><color=#d58508>best:</color></size> " + PlayerPrefs.GetInt("score") + " <size=33>now:</size> " + maxY;

        camMoveToYPosition = 5.9f + nowCube.y - 1f;

        maxHor = maxX > maxZ ? maxX : maxZ;
        if(maxHor % 3 == 0 && prevCountMaxHorizontal != maxHor) {
            mainCam.localPosition -= new Vector3(0, 0, 2.5f);
            prevCountMaxHorizontal = maxHor;
        }

        if (maxY >= 7)
            toCameraColor = bgColors[2];
        else if (maxY >= 5)
            toCameraColor = bgColors[1];
        else if (maxY >= 2)
            toCameraColor = bgColors[0];

    }

    private void AddPossibleCubes(int till) {
        for(int i = 0; i < till; i++)
            posibleCubesToCreate.Add(cubesToCreate[i]);
    }
}

struct CubePos {
    public int x, y, z;

    public CubePos(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public Vector3 getVector() {
        return new Vector3(x, y, z);
    }

    public void setVector(Vector3 pos) {
        x = Convert.ToInt32(pos.x);
        y = Convert.ToInt32(pos.y);
        z = Convert.ToInt32(pos.z);
    }
}

问题原因

  1. posibleCubesToCreate列表为空:当玩家分数≥100时,Start()方法中无对应分支处理,列表未添加任何元素,后续Update()中直接访问索引触发越界。
  2. 缺失空值校验:获取createCube时未检查列表是否为空,直接通过索引访问。
  3. 数组越界风险:AddPossibleCubes()方法中till参数可能超过cubesToCreate数组实际长度,导致添加元素时越界。

修复方案

1. 补充分数≥100的分支

修改Start()方法,添加兜底逻辑:

private void Start() {
    if (PlayerPrefs.GetInt("score") < 5)
        posibleCubesToCreate.Add(cubesToCreate[0]);
    else if(PlayerPrefs.GetInt("score") < 10)
        AddPossibleCubes(2);
    else if (PlayerPrefs.GetInt("score") < 15)
        AddPossibleCubes(3);
    else if (PlayerPrefs.GetInt("score") < 25)
        AddPossibleCubes(4);
    else if (PlayerPrefs.GetInt("score") < 35)
        AddPossibleCubes(5);
    else if (PlayerPrefs.GetInt("score") < 50)
        AddPossibleCubes(6);
    else if (PlayerPrefs.GetInt("score") < 75)
        AddPossibleCubes(7);
    else if (PlayerPrefs.GetInt("score") < 100)
        AddPossibleCubes(8);
    else
        // 分数≥100时添加所有可用预制体
        AddPossibleCubes(cubesToCreate.Length);

    // 原后续代码...
}

2. 添加空列表校验

修改Update()中获取createCube的逻辑:

GameObject createCube = null;
if (posibleCubesToCreate.Count == 0)
{
    if(cubesToCreate.Length > 0)
        createCube = cubesToCreate[0];
    else
    {
        Debug.LogError("请在Inspector面板中为cubesToCreate数组赋值!");
        return;
    }
}
else if (posibleCubesToCreate.Count == 1)
    createCube = posibleCubesToCreate[0];
else
    createCube = posibleCubesToCreate[UnityEngine.Random.Range(0, posibleCubesToCreate.Count)];

3. 修复AddPossibleCubes()方法

添加数组长度校验:

private void AddPossibleCubes(int till) {
    // 取till和数组长度的最小值,防止越界
    int maxIndex = Mathf.Min(till, cubesToCreate.Length);
    for(int i = 0; i < maxIndex; i++)
        posibleCubesToCreate.Add(cubesToCreate[i]);
}

4. 额外检查

确保Unity Inspector面板中cubesToCreate数组已正确添加预制体,无空元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 02:57:03