State is the root of all evil. Global state is even worse. However, if something can simplify your life, then used with caution might be a huge time-saver. In this post, I will show my approach to global data storage in a Unity project. It allows you to store and edit in the Editor all kind of serializable data including references to various Unity objects such as Sprites or GameObjects.

Warning

First of all, I don’t recommend using this to store any kind of mutable state. I haven’t tested it, and my intuition and experience say it would lead to very complex issues. The main purpose of this solution is to have one place that stores read-only static info.

Why would I use it?

Suppose you want to use several const magic numbers - some delay, spacing or treshold. One way is to create a static class with public fields. The downside is that whenever you want to change any value, you have to change it in the code. Following my solution, you will be able to edit the values directly in the Editor.

Another reason might be that you want to store some references to other Unity objects, e.g. Sprites. Normally, you need to add a public property to your component and then assign it some object in the Editor. During the rapid develpment stage it can be annoying if you frequently add and remove objects and components. This can also become an issue if the same information is used by a lot of objects. Imagine having to assign the same 10 references to 20 different objects.

Why wouldn’t I use it?

Because it introduces a global state without any protection against mutations. Depending on the use, it may as well simplify your project as make it more complex.

Solution

First, add the following ScriptableObject to your Assets:

using UnityEditor;
using UnityEngine;

[CreateAssetMenu(menuName = "Globals")]
public class Globals : ScriptableObject
{
    public static Globals instance { get; private set; }

    [SerializeField]
    public Sprite SomeGlobalSprite;

    /* Add more fields here */

    [InitializeOnLoadMethod]
    static void OnRuntimeMethodLoad()
    {
        instance = Resources.Load<Globals>("Globals");

        if (instance == null)
        {
            throw new System.Exception("Could not load Globals Resource!");
        }

        Debug.Log("Globals initialized!");
    }
}

Then, create an instance of it in the Resources folder and name it Globals (if you choose different name, remember to adjust the code).

And that’s all! To set values, select the Resources/Globals asset in the Editor and assign whatever you need in the Inspector.

If you are as lazy as me and don’t want to type this Globals.instance. every time you access one of the global values, you can add a helper class to shorten your code:

public class MyMonoBehaviour : MonoBehaviour
{
    public static Globals G => Globals.instance;
}

and then derive from MyMonoBehavior instead of MonoBehavior in each component that uses Globals.