Index Array Error. Scratching my head.

Howdy, currently working on a card minigame, and for some reason im getting an IndexoutofRangeException error.

“IndexOutOfRangeException: Index was outside the bounds of the array.
SceneControllerHard.Start () (at Assets/Scripts/Hard/SceneControllerHard.cs:39)”

What’s confusing is that this is a copy and paste of another script that works perfectly and exists in another scene where you have a harder game difficulty. below i have attached both the working and error variations of the script. The line being called in the error is in bold :slight_smile:

Broken Version:

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

public class SceneControllerHard : MonoBehaviour
{

    public const int gridRows = 3;
    public const int gridCols = 9;
    public const float offsetX = 2f;
    public const float offsetY = 3.4f;

    [SerializeField] private MainCardHard originalCard;
    [SerializeField] private Sprite[] images;

    private void Start()
    {
        Vector3 startPos = originalCard.transform.position; //The position of the first card. All other cards are offset from here.

        int[] numbers = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12 };
        numbers = ShuffleArray(numbers);

        for (int i = 0; i < gridCols; i++)
        {
            for (int j = 0; j < gridRows; j++)
            {
                MainCardHard card;
                if (i == 0 && j == 0)
                {
                    card = originalCard;
                }
                else
                {
                    card = Instantiate(originalCard) as MainCardHard;
                }

                int index = j * gridCols + i;
                int id = numbers[index];
                card.ChangeSprite(id, images[id]);

                float posX = (offsetX * i) + startPos.x;
                float posY = (offsetY * j) + startPos.y;
                card.transform.position = new Vector3(posX, posY, startPos.z);
            }
        }
    }

    private int[] ShuffleArray(int[] numbers)
    {
        int[] newArray = numbers.Clone() as int[];
        for (int i = 0; i < newArray.Length; i++)
        {
            int tmp = newArray[i];
            int r = Random.Range(i, newArray.Length);
            newArray[i] = newArray[r];
            newArray[r] = tmp;
        }
        return newArray;
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------

    private MainCardHard _firstRevealed;
    private MainCardHard _secondRevealed;


    public bool canReveal
    {
        get { return _secondRevealed == null; }
    }

    public void CardRevealed(MainCardHard card)
    {
        if (_firstRevealed == null)
        {
            _firstRevealed = card;
        }
        else
        {
            _secondRevealed = card;
            StartCoroutine(CheckMatch());
        }
    }

    private IEnumerator CheckMatch()
    {
        if (_firstRevealed.id == _secondRevealed.id)
        {
         
        }
        else
        {
            yield return new WaitForSeconds(0.5f);

            _firstRevealed.Unreveal();
            _secondRevealed.Unreveal();
        }

        _firstRevealed = null;
        _secondRevealed = null;

    }

    public void Restart()
    {
        SceneManager.LoadScene("Scene_001");
    }

}

Working Version:

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

public class SceneControllerNormal : MonoBehaviour
{

    public const int gridRows = 2;
    public const int gridCols = 9;
    public const float offsetX = 2f;
    public const float offsetY = 3.4f;

    [SerializeField] private MainCardNormal originalCard;
    [SerializeField] private Sprite[] images;

    private void Start()
    {
        Vector3 startPos = originalCard.transform.position; //The position of the first card. All other cards are offset from here.

        int[] numbers = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8 };
        numbers = ShuffleArray(numbers);

        for (int i = 0; i < gridCols; i++)
        {
            for (int j = 0; j < gridRows; j++)
            {
                MainCardNormal card;
                if (i == 0 && j == 0)
                {
                    card = originalCard;
                }
                else
                {
                    card = Instantiate(originalCard) as MainCardNormal;
                }

                int index = j * gridCols + i;
              [B]  int id = numbers[index];[/B]
                card.ChangeSprite(id, images[id]);

                float posX = (offsetX * i) + startPos.x;
                float posY = (offsetY * j) + startPos.y;
                card.transform.position = new Vector3(posX, posY, startPos.z);
            }
        }
    }

    private int[] ShuffleArray(int[] numbers)
    {
        int[] newArray = numbers.Clone() as int[];
        for (int i = 0; i < newArray.Length; i++)
        {
            int tmp = newArray[i];
            int r = Random.Range(i, newArray.Length);
            newArray[i] = newArray[r];
            newArray[r] = tmp;
        }
        return newArray;
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------

    private MainCardNormal _firstRevealed;
    private MainCardNormal _secondRevealed;


    public bool canReveal
    {
        get { return _secondRevealed == null; }
    }

    public void CardRevealed(MainCardNormal card)
    {
        if (_firstRevealed == null)
        {
            _firstRevealed = card;
        }
        else
        {
            _secondRevealed = card;
            StartCoroutine(CheckMatch());
        }
    }

    private IEnumerator CheckMatch()
    {
        if (_firstRevealed.id == _secondRevealed.id)
        {
          
        }
        else
        {
            yield return new WaitForSeconds(0.5f);

            _firstRevealed.Unreveal();
            _secondRevealed.Unreveal();
        }

        _firstRevealed = null;
        _secondRevealed = null;

    }

    public void Restart()
    {
        SceneManager.LoadScene("Scene_001");
    }

}

This is my first array error, and Im honestly out of my depth on this one. Especially since that portion of code is identical in each file.

in your working version you have 2 x 9, 18 cells, and you have 18 elements in your numbers array.
in your not working version you have 3 x 9, 27 cells, and you have 26 elements in your numbers array.
When your code tries to fill cell 27, there is no element left in the array.

thank you you absolute king! never would have figured that out. im not good with numbers lol.

1 Like

Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

http://plbm.com/?p=236

Steps to success:

  • find which collection it is and what line of code accesses it <— critical first step!)
  • find out why it has fewer items than you expect
  • fix whatever logic is making the indexing value exceed the collection size
  • remember that a collection with ZERO elements cannot be indexed at all: it is empty
  • remember you might have more than one instance of this script in your scene/prefab
  • remember the collection may be used in more than one location in the code
  • remember that indices start at ZERO (0) and go to the count / length minus 1.

This means with three (3) elements, they are numbered 0, 1, and 2 only.

The error message will tell what line the error happens on. Simply add a Debug.Log on the line above that shows the size of the array and index that you are trying to access. That will make it pretty clear what’s going wrong.