Singleton

Simplified global access, streamlined solution development and portable, reusable tool creation at your fingertips - just never, ever do a search for what it is on the internet.

Unless you have a background in “proper” programming I advise you never try to learn about a singleton by Googling it. I’m not calling you dumb. I’m calling every definition on the internet of the singleton design pattern overly complex and dumb. Go ahead if you don’t believe me and I guarantee you’ll come to the conclusion that “I’ll never ever need this” but I promise you they are super badass and you’ll find a bazillion uses for them.

So, what is a singleton? A singleton is a cellphone - pretty much. A singleton is just a way of making a “thing” easy to get a hold of. Programmer people are going to shout that it also ensures there's just one of these “things" but I consider that to be a bonus and not the main awesomeness of a singleton and, let’s be honest, that means nothing to anyone who is new to a singleton.

Let’s say you need audio in your game (yes, you need audio in your game), how can you reuse sound effects for your buttons, effects, impacts and more all over the place without adding each AudioClip to each GameObject or dragging tons of references to a main audio manager? What happens if your audio needs to change (it will always end up changing) and you have AudioClips all over the place? With a singleton you can load up an audio manager with all of your audio and music and leverage it by a call similar to: AudioManager.Instance.PlayButtonClick (). With this approach you can also easily drop this AudioManager into any other project and it can be reused since it has no specific links within the game and is a completely standalone system.

Solving problems

In Unity development you can think of a singleton as a GameObject that you can “reach” without having to drag a reference to in an inspector. The true power of a singleton is not in how it does what it does but in what it provides and how it lends itself towards more organized development that creates categorized problem solvers.

Most developers lump their work together with input and logic and effects and sound and whatever-else-is-needed and miss golden opportunities to solve problems in a way that they will never have to solve them again. If you break certain systems up into singletons you can fuel parallel development - an audio manager is created by Tom, while an input manager is created by Steve, and an effects manager is slapped together by Ron, all while Jim is making calls to these managers from his work on the hero character.

What happens if you have a game where your character can run about, drive a car, steer a boat and fly a plane? Do you shove detection for joystick buttons, keyboard, Vive controllers and Rift Touch controllers (or whatever else) into every single one of these objects? What happens when you need to support a new platform with crazy new input? With a singleton you could create an input manager that does all of your input detection and simply sends out events. You could then drop this input manager into any other project and hook onto the events again. If you need to pause gameplay during a dialog with a character you could simply call something like InputManager.Instance.DisableInput to false instead of finding out which vehicle is in operation and individually disabling control.

Nuts and bolts

In Surge, you create a singleton by extending the generic singleton class.

using UnityEngine;
using Pixelplacement;

public class AudioManager : Singleton<Audiomanager>
{
}

After you drop a singleton onto a GameObject in your hierarchy you simply access it by MyClassName.Instance. The “Instance” bit is a common practice and refers to the “the instance of the singleton”. After that you can go to town with grabbing access to public variables and references. For instance, here’s a reusable approach to an audio manager:

using UnityEngine;
using Pixelplacement;

public class AudioManager : Singleton<AudioManager>
{
	public AudioClip buttonClickSound;
	public AudioClip attackSound;
	public AudioClip injurySound;

	AudioSource _audioSource;

	void Awake ()
	{
		_audioSource = GetComponent<AudioSource> ();
	}

	public void PlayButtonClickSound ()
	{
		_audioSource.PlayOneShot (buttonClickSound);
	}

	public void PlayAttackSound ()
	{
		_audioSource.PlayOneShot (attackSound);
	}

	public void PlayInjurySound ()
	{
		_audioSource.PlayOneShot (injurySound);
	}
}

As you can see, anything in the game can play a button click sound by simply calling AudioManager.Instance.PlayButtonClickSound (). This also allows your sound designer to swap out sounds at any point without having to touch a million GUI buttons. Centralized, compartmentalized, and able to be developed in isolation; all ingredients to wrangling complexity while adding features.

Features

After you create a singleton and place it onto a GameObject in your project it will automatically register and initialzie itself at runtime. You will notice an “Initialialization” component will be added to the GameObject as well, this component ensures that a singleton is “ready to go” before anything else in your game so you will never get an error when calling for a singletone that is in your scene.

If you need to manually initialize a singleton you can do so with the RegisterInstance () method. This comes in handy for systems that are variations of others like multiple heroes or multipe audio managers with different sets of sounds to match themes.

When?

A singleton is a useful tool. It isn’t the only way to solve a specific problem but it’s there when you need it and when it fits. In general if you have a system that handles a specific task with assets or manages a group of things then a singleton will help get the job done. Just because you have a new hammer doesn't make everything a nail but a singleton is a handy thing to keep on the toolbelt.