Easy Singletons in Unity

Seona Bellamy
4 min readMay 31, 2021

--

The Singleton Design Pattern is a very useful one to have under your belt as a developer. It’s used to both enforce certain classes to only exist once in your program, and provide an easy way for other classes to interact with them. As a good rule of thumb, any class you have that includes the word “Manager” or “Controller” is probably a candidate for becoming a singleton.

Of course, if you use a lot of singletons then you’ll find yourself writing much the same code over and over (and over and over). This both breaks the principle of DRY code (Don’t Repeat Yourself) and is really boring! But there’s an easy way to get around this and make creating singletons a breeze.

Introducing the MonoSingleton

Let’s start with the full class, then we’ll go through it bit by bit and see what it does and how it does it.

using UnityEngine;


public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
Debug.LogError(typeof(T).ToString() + " is missing.");
}

return _instance;
}
}



void Awake()
{
if (_instance != null)
{
Debug.LogWarning("Second instance of " + typeof(T) + " created. Automatic self-destruct triggered.");
Destroy(this.gameObject);
}
_instance = this as T;

Init();
}


void OnDestroy()
{
if (_instance == this)
{
_instance = null;
}
}


public virtual void Init() { }
}

First of all, look at the class declaration. It’s a bit more complex than we’re used to seeing.

public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>

Note the use of the word abstract. This means this class can never be instantiated directly or attached to a game object. The only way to use it is to have another class inherit from it. The class is called MonoSingleton as we’d expect, but we’re also passing it a generic in the form of <T>. This means that we need to pass it an object type — more on this later. The class itself inherits from MonoBehaviour, which means any class which inherits from it will also be able to take advantage of MonoBehaviour like we’re used to. Finally we define that generic by basically saying we want to pass it a type of itself. This will make more sense when we see it in action later.

private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
Debug.LogError(typeof(T).ToString() + " is missing.");
}

return _instance;
}
}

The Singleton pattern depends on their being a public Instance that can be interacted with by the rest of the program. Here we’re setting up a private _instance variable, then providing a public getter for it. The getter also checks that there is actually an instance, and flags an error if it’s missing. The typeof(T).ToString() means that the error will use that generic T we defined above to tell you which singleton is missing its instance.

void Awake()
{
if (_instance != null)
{
Debug.LogWarning("Second instance of " + typeof(T) + " created. Automatic self-destruct triggered.");
Destroy(this.gameObject);
}
_instance = this as T;

Init();
}

While the getter wanted to make sure we did have an instance, when the script first runs we want to make sure we don’t have an instance. Remember, this is a singleton. There Can Be Only One. If there is already an instance of this class, log a warning and then destroy the gameObject to make sure we only ever have the one instance. If there isn’t already an instance, then create one of the current type. Finally, run the Init() method.

void OnDestroy()
{
if (_instance == this)
{
_instance = null;
}
}

When the object is destroyed, make sure we clean up after ourselves by nulling any current instance. This frees us up to create a new one later if we need to without “ghost” instances hanging around.

public virtual void Init() { }

Finally, we create a virtual Init() method that individual implementations of the MonoSingleton can overwrite for their own purposes. I tend to use this to initialise lists and dictionaries and that sort of thing.

MonoSingleton in action

But how do we use this class? It’s pretty simple, as it happens. Instead of the usual class inheriting from MonoBehaviour, we do this:

public class SpawnManager : MonoSingleton<SpawnManager>

We inherit from MonoSingleton, and we pass the class itself as the generic. Now this SpawnManager will function as a singleton, and also inherits MonoBehaviour through MonoSingleton so we can write all the rest of our code just as we usually would.

--

--