Singletons for dummies

I’ve read tons of articles about the singleton pattern in Unity, yet I fail to understand the need to use one. Everyone keeps telling me that a generic GameManager class (handling score, instantiation, levels) almost always needs to be a singleton. But if I have such a script, and attach it to an empty GameObject, what’s wrong with using the following on every object that needs to communicate with the GameManager ?

gameManager = FindObjectOfType<GameManager>();

There is only one of those, so there’s no confusion possible. Why should I use a singleton instead?

Thanks.

The idea of singletons is the commodity of having access to the singular instance of an object and its members without the need of having to look for the reference every time. Singletons achieve this pretty easily with a small class. (Note that this could be also achieved without singletons, by dependency injection but that is a bit more difficult to set up, specially in Unity).

The way you’re suggesting (having every object that needs the GameManager call FindObjectOfType) could potentially cause performance issues if the quantity of objects doing it starts growing.

Quoting Unity’s documentation on the FindObjectOfType method:

Please note that this function is very slow. It is not recommended to use this function every frame. In most cases you can use the singleton pattern instead.

If you are certain that only a few objects will do it, and not every frame, then there’s no problem, you probably don’t need a solution like singletons.

The thing about singletons is that they are the easy way out for finding references, however, there are multiple concerns around them since they introduce global state but that is a whole different topic. My take on it is that if you are working in this project by yourself and it is a “small” project (like, not an MMORPG), then having singletons doesn’t hurt. Having said that, there are times when your project is even smaller, so small that even singletons are overkill.

In the end, the decision is up to you, since you would know the necessities and scope of your project, better than anyone.

Documentation

Hello @Cirrocumulus ! :slight_smile:

(I think I’m one of those guilty telling you to use a singleton, so it’s fitting that I answer this question… :D)

The idea of the singleton pattern is that it refers to an object instance that is easily reachable from anywhere and there exists exactly one of it at all times (meaning not less and not more than 1). So before you make something singleton, ask yourself if it really fits this description: there should be exactly one at all times, and it should be reachable from anywhere. If either one isn’t true, you are probably better off with somehow getting a reference to the object.

In Unity we have FindObjectOfType<T>(), but the singleton pattern originates from languages where there is no such functionality. So to solve this they use static instance variable. A static variable is one whose value is shared among all instances of the class. Think of it as a something that belongs to the class itself, not to object instances, and all object instances and the whole system sees the same variable.

You could use FindObjectOfType<GameManager>() and store the result to implement this pattern, but 1) FindObjectOfType() it is a slow call, 2) you can’t ensure there is only one GameManager, 3) using a singleton makes your code more readable. Below is a simple implementation that usually is enough (but isn’t thread-safe!):

public class GameManager : MonoBehaviour {
    private static GameManager instance = null; // the private static singleton instance variable
    public static GameManager Instance { get { return instance; } } // public getter property, anyone can access it!

    private void Awake () {
        if (instance == null) { // if the singleton instance has not yet been initialized
            instance = this;
        }
        else { // the singleton instance has already been initialized
            if (instance != this) { // if this instance of GameManager is not the same as the initialized singleton instance, it is a second instance, so it must be destroyed!
                Destroy(gameObject); // watch out, this can cause trouble!
        }
    }

    private void OnDestroy () {
        if (instance == this) { // if the this is the singleton instance that is being destroyed...
            instance = null; // set the instance to null
        }
    }
}

Now you can access GameManager from anywhere by calling GameManager.Instance, for example:

if (/* player killed an opponent */) {
    if (GameManager.Instance != null) { GameManager.Instance.IncreasePointsBy(opponent.GetPointValue());
    }
}

The problems that you can run into:

  • You don’t have a singleton instance, because you don’t have an object in the scene with the GameManager script on it: you should either manually make sure that you have such an object in every scene that needs it, or make it an auto-instantiating singleton (see below)
  • You want the GameManager to survive level loads (so-called persistent game object): previously the solution was simply DontDestroyOnLoad(gameObject), but this function will become deprecated, because it causes a lot of other problems. Instead, create a scene that is always loaded (I like to call it ManagerScene), and add your GameManager object to that (this also solves the first issue), and then load all the other scenes additively (and remember to set them as the active scene, otherwise their lighting will be bad)
  • There are other scripts or child game objects on the object of the GameManager, so when it is a duplicate, Destroy(gameObject) kills an entire hierarchy of components: one solution is that you only kill the script itself by calling Destroy(this). But the nicer solution is if your GameManager script is the only script on a game object with the same name, GameManager. Again, the solution to the second issue usually helps with this one as well.

I realise that I probably threw a lot of information at you, but I do it in the hopes that you understand the idea in-depth. Feel free to ask if you have any doubts, and good luck!


Modification of the singleton code to make it auto-instantiating (and remove the Awake() part, it’s not needed anymore):

public static GameManager Instance {
    get {
        if (instance == null) {
            instance = new GameObject("GameManager").AddComponent<GameManager>(); // creates a game object and attached this script to it
        }
    return instance;
    }
}