Mysterious IndexOutOfRangeException

Hi guys!

Currently I’m working on a little sidescrolling game. It focuses on the player unlocking different units and sending them from their base to destroy the enemy base.

When a player has an unit unlocked and enough resources for it they can click the units button in the UI and it will be put in a queue, since only 1 unit can be trained at a time. When the player does this the game creates a queue button that can be clicked to remove the unit from the queue and refund it’s costs.
For this I’m using these 2 possibilities (depending on if there are already units in the queue).

QueueButtons [0] = Instantiate (QueuePrefabs[unit], new Vector3 (1216f, 952f, 0f), Quaternion.identity, QueueMenu);
QueueButtons [0].GetComponent<Button> ().onClick.AddListener (delegate {
						CancelUnit(0);
});

for (int i = 0; i < training_queue.Length; i++) {
   if (training_queue  *== -1) {*

QueueButtons = Instantiate (QueuePrefabs [unit], new Vector3 (1216f / 2f + 160f * i, 952f, 0f), Quaternion.identity, QueueMenu);
QueueButtons .GetComponent ().onClick.AddListener (delegate {CancelUnit (i);});
i = training_queue.Length;
}
}
But every time I try to use a button created by the second method Unity gives me this error message:
IndexOutOfRangeException: Array index is out of range.
PlayerCastle.CancelUnit (Int32 queue_slot) (at Assets/Scripts/PlayerCastle.cs:159)
PlayerCastle+c__AnonStorey0.<>m__0 () (at Assets/Scripts/PlayerCastle.cs:135)
UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:154)
UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:637)
UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:773)
UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:52)
UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44)
UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:50)
UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:261)
UnityEngine.EventSystems.EventSystem:Update()

*(The line meant here is: *
if (training_queue [queue_slot] != -1) {
)
Queue_slot stands for an int the method CancelUnit this line is in, requires. It is the same number I gave the buttons in the AddListener functions.
Normally this error would mean my value I tried to put would be too large for the array training_queue, wouldn’t it? But it actually can’t be larger since my for statement only allows i to be smaller than training_queues’ size.
What am I missing/doing wrong?
If you need additional info just tell me, I didn’t want to post my complete class code since its over 200 lines.
Thank you in advance!

Even though it’s probably possible to somehow find the error, it’s a good idea to move away from multiple Arrays having the same length. Having these will lead to hard-to-detect errors sooner or later.

The trick is to create a class or struct that combines the values of all arrays on a specific index and then create a single array that contains these objects.

So instead of

public int[] playerIDs;
public string[] playerNames;

you do

[System.Serializable]
public struct Player
{
  int id;
  string name;
}

and then

public Player[] players;

This way, you only have one array and your for loop can go

for(var i = 0; i < players.Length; i++)
{
  players*.This();*

players*.That();*
instead of
for(var i = 0; i < someArray.Length; i++)
{
anotherArray*.Stuff();*