Non MonoBehaiour script execution sequence and error (null object reference)

I have an error that keeps happening when running my code. I have a public class (non monobehaviour) that I create an array of within another class/script in order to list out magic spells. When I run my scripts at runtime, I get an error when trying to create the array for global Magic items (globalSpecialList).
I am still relatively new to Unity (and programming) so this might be a basic issue that I am running into, but I am getting lost on using the MonoBehaviour and then the non MonoBehavious class, and also figuring out when those run, etc.

FYI: I created twelve of the same array input just to test out the multiple input for the array while working on these scripts.

Here is the info:

Error:
NullReferenceException: Object reference not set to an instance of an object
GlobalSpecialList.LoadOutAllSpecial () (at Assets/Scripts/GlobalSpecialList.cs:25)

GlobalSpeciaList:

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

[System.Serializable]
public class GlobalSpecialList : MonoBehaviour
{
   
    public Special[] special;
    public enum Magic
    {
        fire1,
    }

    void Awake()
    {
       special = new Special[12]; //set array size since I dont know how to do this dynamically
    }




    public void LoadOutAllSpecial()
    {
        special[(int)Magic.fire1].specialName = "Fire1";
        special[(int)Magic.fire1].specialDescription = "Fireball go boom!";
        special[(int)Magic.fire1].spCost = 5;
        special[(int)Magic.fire1].specialDamage = 10;
        special[(int)Magic.fire1].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[(int)Magic.fire1].element = Special.specialElementType.Fire;
        special[(int)Magic.fire1].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[1].specialName = "Fire1";
        special[1].specialDescription = "Fireball go boom!";
        special[1].spCost = 5;
        special[1].specialDamage = 10;
        special[1].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[1].element = Special.specialElementType.Fire;
        special[1].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[2].specialName = "Fire1";
        special[2].specialDescription = "Fireball go boom!";
        special[2].spCost = 5;
        special[2].specialDamage = 10;
        special[2].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[2].element = Special.specialElementType.Fire;
        special[2].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[3].specialName = "Fire1";
        special[3].specialDescription = "Fireball go boom!";
        special[3].spCost = 5;
        special[3].specialDamage = 10;
        special[3].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[3].element = Special.specialElementType.Fire;
        special[3].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[4].specialName = "Fire1";
        special[4].specialDescription = "Fireball go boom!";
        special[4].spCost = 5;
        special[4].specialDamage = 10;
        special[4].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[4].element = Special.specialElementType.Fire;
        special[4].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[5].specialName = "Fire1";
        special[5].specialDescription = "Fireball go boom!";
        special[5].spCost = 5;
        special[5].specialDamage = 10;
        special[5].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[5].element = Special.specialElementType.Fire;
        special[5].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[6].specialName = "Fire1";
        special[6].specialDescription = "Fireball go boom!";
        special[6].spCost = 5;
        special[6].specialDamage = 10;
        special[6].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[6].element = Special.specialElementType.Fire;
        special[6].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[7].specialName = "Fire1";
        special[7].specialDescription = "Fireball go boom!";
        special[7].spCost = 5;
        special[7].specialDamage = 10;
        special[7].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[7].element = Special.specialElementType.Fire;
        special[7].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[8].specialName = "Fire1";
        special[8].specialDescription = "Fireball go boom!";
        special[8].spCost = 5;
        special[8].specialDamage = 10;
        special[8].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[8].element = Special.specialElementType.Fire;
        special[8].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[9].specialName = "Fire1";
        special[9].specialDescription = "Fireball go boom!";
        special[9].spCost = 5;
        special[9].specialDamage = 10;
        special[9].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[9].element = Special.specialElementType.Fire;
        special[9].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[10].specialName = "Fire1";
        special[10].specialDescription = "Fireball go boom!";
        special[10].spCost = 5;
        special[10].specialDamage = 10;
        special[10].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[10].element = Special.specialElementType.Fire;
        special[10].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

        special[11].specialName = "Fire1";
        special[11].specialDescription = "Fireball go boom!";
        special[11].spCost = 5;
        special[11].specialDamage = 10;
        special[11].specialGameObjectPrefab = Resources.Load("PreFab/SpecialPrefabs/Magic/Fire/fire1Prefab") as GameObject;
        special[11].element = Special.specialElementType.Fire;
        special[11].specialTargetAmt = Special.specialTargetAmount.single; //can you target multiple or just 1 entity

    }
}

Special:

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

[System.Serializable]
public class Special //: MonoBehaviour
{
    public enum specialElementType
    {
        Earth,
        Wind,
        Fire,
        Water,
        Black,
        White,
        Nothing
    }

    public enum specialTargetAmount
    {
        single,
        multiple,
    }

    public GameObject specialGameObjectPrefab;
    public string specialName;
    public string specialDescription;
    public int specialID;
    public float specialDamage;
    public int spCost;
    public specialElementType element;
    public specialTargetAmount specialTargetAmt;

    public Special(Special special)
    {
        this.specialGameObjectPrefab = special.specialGameObjectPrefab;
        this.specialName = special.specialName;
        this.specialDescription = special.specialDescription;
        this.specialID = special.specialID;
        this.specialDamage = special.specialDamage;
        this.spCost = special.spCost;
        this.element = special.element;
        this.specialTargetAmt = special.specialTargetAmt;
    }

}

I appreciate any help or input/direction you all can give me on this.

Thanks

Your Special array contains 12 nulls as per line 17. You have to make a new instance of special, then assign it to an element of the array. It doesn’t create instances of Special automatically just because you declared the array :slight_smile:

using UnityEngine;

public class GlobalSpecialList : MonoBehaviour
{
    public Special[] special;

    void Awake()
    {
        special = new Special[12];

        for (int i = 0; i < special.Length; i++)
        {
            special[i] = new Special();
        }
    }
}

If you want a collection that expands automatically as your comments suggests you might, you can use a List instead.

1 Like

Thanks mopthrow! I got this working now.

I did have to add another function

    public Special()
    {

    }

else I was getting an error. Not entirely sure why that is, and hopefully it won’t bite me later down the road, but I am still glad I can get it to compile.

Thanks again!

1 Like

You’re welcome :slight_smile:

The reason you had to add another function is that your Special class already had a constructor with parameters. This thing:

public Special(Special special)
    {
        this.specialGameObjectPrefab = special.specialGameObjectPrefab;
        this.specialName = special.specialName;
        this.specialDescription = special.specialDescription;
        this.specialID = special.specialID;
        this.specialDamage = special.specialDamage;
        this.spCost = special.spCost;
        this.element = special.element;
        this.specialTargetAmt = special.specialTargetAmt;
    }

If you add a constructor with parameters to your plain C# class like this, you can no longer use the always-there-but-invisible default paramterless constructor unless you explicitly add it in again. You just added that now necessary default parameterless constructor by doing this

public Special()
{
}

If you were ever to delete your constructors that have parameters, you could also delete the paramterless one and get no errors.

In short, you did the right thing to fix the error. It won’t cause you any problems down the line.