Mire Studios is made up of two people who have always enjoyed playing games. We're gamers that make games so you can expect a wide variety of different games from us.
Sometimes, you need globally accessible data. Although I'm not going to go into the whole thing debate about global data. I have noticed, that in Unity, a Singleton is sometimes a good way to move temporary data across scenes.
If you go search the web, you will see many examples of how to create Singletons in Unity. However, most of them require you to copy some boilerplate code into every script and having to copy code from one script into another is never a good idea. They also don't create themselves or do it in a weird way.
Here's our solution, a Singleton template. This abstract class puts all of the boilerplate into one script and has the bonus of the Singleton creating itself when it's requested by another script. This means, that if you forget to place a GameObject with the script into a scene, it will be created for you.
Below you will find two, slightly different examples of the Singleton template. I will explain them after showing the code:
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
var create = new GameObject(string.Concat(typeof(T),
" Singleton")).AddComponent<T>();
_instance = create;
}
return _instance;
}
}
protected virtual void Awake()
{
if (_instance == null)
_instance = this as T;
else
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
}
This implementation will simply create the object if it's null as you see in the getter. This is good if you have an object where the values are not exposed to the editor. If you are using a Singleton that has values that must be set in the editor. The following will suit you better:
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
var create = Instantiate(Resources.Load(Prefab)) as T;
_instance = create;
}
return _instance;
}
}
protected abstract string Prefab { get; }
protected virtual void Awake()
{
if (_instance == null)
_instance = this as T;
else
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
}
This implementation requires that you have the object saved as a prefab in the Resources Folder. This will create the object, in case you forgot it, and will keep the values as it's a prefab. The main difference here is that the singleton will need to implement the "Prefab" field. Where you must simply just return the string name of the prefab you want to instantiate, easy.
Now to go over what these scripts do in more detail. If the singleton is already in the scene, a new one won't be created. Second, if there are multiple singletons the others will be destroyed so that there will only be one. Finally, to use the script, simply inherit from it and do what you would normally do with any other Singleton. The "T" parameter is simply the class that you pass in. Here's a quick example:
public class TestSingelton : MonoSingleton<TestSingleton>
{
private void Start()
{
Debug.Log("I am a Singleton");
}
}
Notice that you pass in the same class type as is inheriting the script. Pretty simple, right? If you any questions about these two Singleton templates, let us know in the comments below.
Until next time.