The singleton pattern is useful when writing game components like a game manager or localization manager in Unity. I would like to share with you the implementation I am currently using in my project.
Inspiration
While creating my implementation I took inspiration from several sources:
- Localization Manager sample – an approach using the
Awake()
method, which destroys all instances created after the first one. - Unity Community Wiki – this implementation guarantees to create one instance only and is thread-safe thanks to locking.
- Singleton pattern blog post by Jon Skeet – once again I revisited this excellent blog post on implementing singleton pattern in C#, and I warmly recommend it!
Code
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour | |
{ | |
private static readonly Lazy<T> LazyInstance = new Lazy<T>(CreateSingleton); | |
public static T Instance => LazyInstance.Value; | |
private static T CreateSingleton() | |
{ | |
var ownerObject = new GameObject($"{typeof(T).Name} (singleton)"); | |
var instance = ownerObject.AddComponent<T>(); | |
DontDestroyOnLoad(ownerObject); | |
return instance; | |
} | |
} | |
//usage: | |
public class GameManager : Singleton<GameManager> | |
{ | |
… | |
} |
Note: This code requires enabling the .NET 4 scripting runtime to access the Lazy<T>
type.
- Open player settings in the Unity Inspector by selecting Edit > Project Settings > Player.
- Under the Configuration heading, click the Scripting Runtime Version drop-down and select .NET 4.x Equivalent. You will have to restart Unity for the change to take effect.
Explanation
My singleton is implemented as a generic class deriving from MonoBehaviour
. This is necessary to have access to the DontDestroyOnLoad
method we call in CreateSingleton
.
The type argument should also derive from MonoBehaviour
so that we can use the instance as a component and receive all messages like Awake
, Start
and Update
. When used in a derived class, you pass the concrete type as the type argument. This looks a bit circular when written, but it is basically just saying “class X is a singleton of type X”.
For the pattern itself, I went with the version using Lazy<T>
suggested by Jon Skeet in his article. The advantage of this is that Lazy<T>
handles the thread-safety out of the box and we don’t have to do any locking ourselves.
The singleton initialization itself is very straightforward – we create an empty GameObject
, attach our component to it and finally mark it so that it won’t be destroyed when new scene is loaded.
It doesn’t seem to work like that in Unity or maybe something is missing. Was not able to use your code in Unity 2019.3.
This requires two libraries, which are included by adding these two lines to top of the code:
using System;
using UnityEngine;