Singletons are a type of object used frequently in computer programming. As wikipedia says:
…the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
So that means you only have one of the class, and you can access it anywhere. Using a singleton:
void Start() { GameController controller = GameController.GetInstance(); controller.addUnit(this); }
An example of creating a Singleton is on the Unify wiki. I do not use this pattern personally, but it is an acceptable way to make a singleton in Unity. I’ll show a different way of doing this that I prefer later.
Singletons Are Overused
Singletons are easily the most controversial and poorly used programming pattern. They are also very good at making your life easier. There is one main drawback to the pattern: if you end up needing more than one later, you may be screwed. Some examples in games:
- There is only going to ever be one player. Until multiplayer.
- Or one monitor. (Unity only recently added multiple monitor support! Got to wonder how hard that was!)
- Or one view of your game. Until you need a minimap.
So I try to think carefully before making a singleton. It is frequently a judgement call: yes, i am limiting myself but I don’t care enough about feature ‘X’.
Memory
When creating a singleton, it is important to understand the concept of the keyword ‘static‘. Static variables are variables that are globally accessible. They exist in memory until manually removed. Singletons by definition are static. It is important for singletons to clean up after themselves. Perhaps for a more advanced article I will write about the memory effects of singletons, but suffice it to say that using singletons can significantly effect memory usage.
Signs You Might Want a Singleton
If you’re using GameObject.FindWithTag, or GameObject.Find() to find the same object over and over, you probably want a singleton.
You have one game controller, and instead of writing a lot of code to pass the controller in to all your units, they can simply access it globally.
Almost always an input manager will interpret mouse, touch, and keyboard events into something actionable within the game. You only need one.
If you have a class that contains a LOT of static variables, and static functions, you have essentially created a singleton, but without the benefits of inheritance, and all the memory issues. If this class isn’t a ‘utility’ class, then you may want to think about singleton-ing it up. That’s a technical term.
Singletons in Unity should be MonoBehaviours
In order to better fit into the Unity life cycle, it is beneficial for Singletons to simply inherit from MonoBehaviour. This allows the usage of constructs like coroutines, Awake(), and Start() methods.
Initializing a Singleton
When using a singleton for the first time, there is usually some kind of initialization involved. Sometimes this initialization is costly or problematic, especially if it happens in the middle of a game and causes stutter. Initializing singletons at startup using Awake() and Start() is much more straightforward and will prevent stutter or race conditions down the road.
A Simple ‘Manager’ Pattern
The Singleton pattern on the wiki mentioned above is a solid pattern for creating a singleton. But its not what I use. Here is an example Managers class from a game:
using UnityEngine; public class Managers : MonoBehaviour { public CRMouseManager mm; public CRGameController gc; public CRGameUI gameUI; public CRUIController ui; public Camera mainCamera; public CommandCenter cc; public CRResources res; private static Managers instance; void Awake() { instance = this; } void OnDestroy() { instance = null; } public static Managers Get() { return instance; } }
Some example usages:
//Just use a method on a sub-object Managers.Get().cc.SomeMethod(); //Put the value in a local var so I don't have to get it. CommandCenter cc = Managers.Get().cc; //Or get the manager itself for use later: Managers m = Managers.Get(); // ... later... m.cc.SomeMethod(); m.gameUI.GameOver(); m.ui.Popup("Game Over Yo");
There are a few things to note about this code, good and bad:
- None of the ‘singletons’ in the Manager have to inherit from MonoBehaviour, Singleton, etc. This gives me the freedom to link to whatever I want.
- Adding a singleton means adding another variable to this class. No more.
- Upon Awake() the instance variable is set, and OnDestroy() it is unset for memory purposes.
- Whenever Get() is called during game execution we can assume that instance exists and no logic is required.
- This game only has one scene and everything else is prefab-based. If there were multiple scenes, a call to DontDestroyOnLoad(gameObject) would be required.
- This is very tightly coupled game-dependent code. Not easily portable to other games. It is possible to write more complicated code that is more portable, but I usually do not care enough.
- Some of these vars might be null! ‘gc’ and ‘gameUI’ only exist when you’re in a game, and are manually set by the member variables themselves. Not at all obvious and totally undocumented. Who wrote this crap?! 🙂
At the end of the day singletons are a mixed bag, and so is this code. What I like about Managers is that its dead simple. I have seen a some complicated singleton code. I’ve also seen a lot of duplication of the same singleton code over and over, constantly re-implementing GetInstance(). Singletons don’t need to be complicated!