Search code examples
c#unity-game-engineindexoutofrangeexception

Unity IndexOutOfRangeException that I can't solve


I have a script Shop.cs for an in-game shop. I get this weird error when I click the button. It says:

IndexOutOfRangeException: Array index is out of range.
Shop+<Start>c__AnonStorey1.<>m__9 () (at Assets/Scripts/Menu/Shop.cs:24)
UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:144)
UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:621)
UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:756)
UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:53)
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:52)
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:269)
UnityEngine.EventSystems.EventSystem:Update()

Btns and Weapons are the same length.
Here is Shop.cs

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;

public class Shop : MonoBehaviour {

    public Button[] btns;
    public int money;
    public Weapon[] weapons;

    public int weaponLength;

    void Start()
    {

        weapons = new Weapon[weaponLength];

        AddWeaponsToArray();

        for(int i = 0; i < btns.Length; i++)
        {
            btns[i].onClick.AddListener(delegate ()
            {
                if (weapons[i] == null)
                    Debug.LogError("Not enough wpns!!!");
                else
                    BoughtSomething(weapons[i], btns[i]);
            });
        }


    }

    void Update()
    {
        for (int i = 0; i < weapons.Length; i++)
        {
            Weapon _wpn = weapons[i];
            if (!_wpn.purchased)
                _wpn.active = false;
            if (_wpn.active)
                btns[i].enabled = false;
            if (!_wpn.purchased && _wpn.cost > money)
                btns[i].enabled = false;
        }
    }

    void AddWeaponsToArray()
    {
        weapons[0] = CreateWeapon.newWeapon("Roto", 1, 100, 0.5f, 50, 100, false, false);
    }

    void BoughtSomething(Weapon _wpn, Button _btn)
    {
        if (_wpn.purchased)
        {
            _wpn.active = true;
        }
        else
        {
            money -= _wpn.cost;
            _wpn.purchased = true;
            _wpn.active = true;
        }
    }

}

I'm sorry if this is a noob question. If you would like me to put another script, I will. Also I will give you images of the inspector or the scene or something I'll add it to this post.

enter image description here


Solution

  • Could be caused by the variables not being captured. See the great answer here for more information: Using the iterator variable of foreach loop in a lambda expression - why fails?

    Basically, since you just have a reference to your index variable, when it gets updated to 2 in your for loop, 2 is the value returned when your delegate is called. btn[2] is out of range.

    You should be able to just do this:

    int capturedIndex = i;
    BoughtSomething(weapons[capturedIndex], btns[capturedIndex]);