framebunker is an
independent game studio
based in copenhagen

unity singletons


by Nicholas Francis
Apr 26, 2013

I wanted to share how we go about doing singletons in Unity for Static Sky. This is one of Unity’s less polished areas, but with a bit of up-front work it can actually get pretty nice.

Let’s assume our singleton is in the scene (akin to RenderSettings). We want to be able to see it and edit myValue in the inspector. It’s a MonoBehaviour on a GameObject. We want a performant way of getting it from other scripts as well. Something like:

class MyManager : MonoBehaviour {
	public int myValue;  
	static MyManager s_Instance;
	public static MyManager get { 
		get {
			return s_Instance;
		}
	}

	public void Awake () {
		s_Instance = this;
	}
}

Dull, but gets the job done. Now, let’s add some error checking to make this example a bit less contrived:

class MyManager : MonoBehaviour {
	static MyManager s_Instance;
	public static MyManager get { 
		get {
			if (!s_Instance)
				Debug.LogError ("Unable to find MyManager. Is it in the scene?");
			return s_Instance;
		}
	}

	public void Awake () {
		if (s_Instance != null)
			Debug.LogError ("There's already an instance of MyManager. Is it more than once in the scene?", this);
		s_Instance = this;
	}
}

This is closer to real-life, but that’s quite a bit of boilerplate to write for each different manager we have. Let’s see if we can’t make a superclass that both can run code and have access to type of the manager. Something like this:

class SceneManager<T> : MonoBehaviour where T : MonoBehaviour {
	static T s_Instance;
	public static T get { 
		get {
			if (!s_Instance)
				Debug.LogError ("Unable to find " + typeof (T).Name + ". Is it in the scene?");
			return s_Instance;
		}
	}
	
	public void Awake () {
		if (s_Instance != null)
			Debug.LogError ("There's already an instance of MyManager. Is it more than once in the scene?", this);
		s_Instance = (T)(object)this;
	}
}

There’s a bit of shenanigans going on when we assign the value to s_Instance, but at least it’s contained.

To make a new scenemanager, you can now do:

class MyManager2 : SceneManager<MyManager2> {
   public int myValue;
}

This gets you access to a typesafe getter of the instance, and all the error checking. The magic is deriving from a templated parent class where the template argument is the child class. This basically makes it possible for the parent class to contain both static values that don’t collide between the children (e.g. s_Instance), as well as knowing the type of the actual manager.

All this might seem a bit over-the-top, but once you begin to have global managers, having somewhere, anywhere, to stuff all the lifetime management code is super nice.

Later, I’ll show you how we do that – but for now just let me know if you have any comments.


by Andy
April 26, 2013

It is great to see that I am not the only person who does it like that. My base class is slightly longer, but the idea is exactly the same.


by framebunker
April 26, 2013

Andy shared some code in the comment above. We snipped it for brevity (sorry, Andy) but will try to come up with a better way to handle comments containing code (or long comments in general).


by Luis Correa
April 26, 2013

Thanks for this, I’ve been using Unity since v1 and find that while it’s very powerful and very easy to use it’s also very easy to shoot yourself in the foot when it comes to structuring a large project.
We also use singletons for our managers but sometimes have problems when they need to be persistent across scenes. We make the class create the GameObject and assign the Monobehavior when the instance is null and set the DontDestroyOnLoad on awake. This works well most of the time, but sometimes it leaks the objects into the scene when we stop the game in the editor. Specially if we use them in Coroutines and Invokes.
Another common problem we have not related to singletons is when we change shared material properties on runtime this changes persist when we stop the game making it an pain to discard those changes in the asset server all the time. Maybe we shoudn’t be changing share materials, but I’m afraid of the allocations Unity does when creating material instances.


by Nicholas Francis
April 26, 2013

@Luis – My best approach so far for shared stuff is to put them in an asset saved at Resources/ClassName.asset

Then you can select in project, edit in inspector, you can do Resources.Load to get it, you will never have more than one. The downside is that I’m not quite sure about exactly when assets that are referenced are loaded.

I have some ideas for how you could deal with materials, but need to try it out. One of the things I find helpful is to remember that runtime code can be quite different from running in the editor.


by Matt Diamond
April 26, 2013

As Luis Corres mentioned in his comment, if I don’t find the singleton instance I create a new GameObject to hold it, rather than error.

This isn’t just a matter of convenience for me. I’ve adopted the convention that singletons should NOT be in the scene beforehand. This means that I can be sure parameters in my singletons (which can control things like mouse tracking speed, GUI window sizes, spawn frequencies) are only set in code, never in the scene. I can track them in source control, and changes to them are global. (I could make some of them constants I suppose, but then I’d have to recompile if I want to tweak them, and the game can’t adjust them on the fly.)

The tradeoff is that I can’t use the editor on those parameters to set any per-scene settings. But this works for me because my games typically have only one scene for gameplay; the objects in each level are assembled at run time.

Of course I could have both scene parameters and global parameters if I wanted. But in that case I think its important not to mix them. When you edit a parameter in code you need to know whether this change will effect one scene, some scenes, or all. This could by enforced by having two kinds of singletons (scene parameters in the type of singleton above, global parameters in a singleton which instantiates itself when first invoked.)

As I said before, this approach works well for my type of games. Your mileage may vary.


by Jashan
April 26, 2013

Using a templated parent class is a really cool idea. I’m doing some more stuff in my Singletons but have the code copied all over the plate … so this will actually help me get stuff done in a cleaner way.

Thanks for posting it!


by Benoit FOULETIER
April 26, 2013

IMO data should be validated instead of checked constantly.
The duplicate instance check on Awake, why not, but the test on the accessor? yuck! unnecessary ifs all over the place. Sure you could #define it away in final, but then if you’re in the editor you’ll get a nice nullException in the console anyway. And as soon as you get one, you fix it, instead of checking against it until the end of time.

So recently I’ve adopted a new architecture that’s a bit out there, but allows us to access all our managers from one place, like so:
Manager.feedback.doThis();
Manager.animation.doThat();
… Intellisense goodness!

The way to do this is to have a stub class somewhere:
public static partial class Manager
{
}

and then in each manager you declare this:

public static partial class Manager
{
public static FeedbackManager feedback;
}

public partial class FeedbackManager : MonoBehaviour
{
void OnEnable() // helps survive compilation
{
Manager.feedback = this;
}
}

Sure redeclaring the partial is a little bit tedious, but then again I don’t write a new manager every day, but I do use Intellisense a lot! And the partial makes the “manager manager” project-agnostic.
Also I use OnEnable instead of Awake so my statics survive recompilation during play (I could use both but so far I’ve never needed to access this particular manager during Awake).

While writing this I’m realizing that if you wanted to use a base class with whatever checks you want, you could probably have a virtual setReference() or something to abstract away the location of the static reference.


by Emil “AngryAnt” Johansen
April 27, 2013

In I go! Third or fourth approach to singletons – mixing a bit of everything it seems.

I love the generic singleton pattern (kept it out of utech example code so far though), but I wonder why you don’t have it set up to be “where T : SceneManager”?

Regarding storing the reference, I usually go lazy and forgiving – meaning the instance property does a FindObjectOfType if the reference evaluates to null – rather than the instance registering itself. That also means I don’t give a **** if there are multiple managers in the scene at that point.

Why?
* I get to configure the manager in the scene – like you do.
** Yes I appreciate the idea of config being versioned in your source and we could take a religious discussion about whether config belongs in code or not, but that’d take a larger forum I think.
** Generally I say that if you opt out of having the Unity serialisation system do all your work for you, you better have a damn good reason.
* Being able to have multiple managers in existence at once means I can easily do very smooth handover for level changes etc.
** When I’m done, I just destroy the old manager which means the instance reference evaluates to null on next access, triggering a new FindObjectOfType call – no need to roll my own invalidation setup when I can use what’s already available.

Finally, I *always* strive to have my instance properties protected – turning all the public methods of the singleton static in stead – calling the instance property inside of those when needed, rather than passing the buck to every point in the code where I need to play with the singleton. Typing “.get” or “.Instance” or whatever gets old surprisingly fast.

Awesome work on this blog guys – great idea for some community contact, and I bet it serves as a great decoupler every once in a while 🙂 Keep it coming!


by Nicholas Francis
April 29, 2013

@Benoit. Good point on the if – I prefer having a nice error message than having a nullref somewhere down the line. Not sure about Manager.inputThingy vs. InputThingy.get, difference of style, I guess.

@Emil.

Real-world manager classes hide the .get behind statics, but I omitted it for the sake of brewity.

You can’t derive from SceneManager, as SceneManager is a template class, so you get compiler bitching.

I don’t want FindObjectOfType at runtime on a tablet 🙂


by Emil “AngryAnt” Johansen
April 30, 2013

@Nich
I should send you a snippet at some point, cause I’ve been deriving from the template manager class in my singletons 🙂

Note that the FindObjectOfType call only happens when the singleton instance is invalidated.


by Martijn “Pixelstudio”
June 14, 2013

Awesome stuff!

We came up with this : http://snipt.org/AqU5

edit: We need a better way to share code in comments, until then, I copied this to snipt since it was quite long -charles


by Jashan
June 29, 2013

This truly is an inspiring blog! Thanks to Benoit for the “OnEnable”-idea. So far, I’ve been using FindObjectOfType as fallback to survive compilation but OnEnable seems much more elegant (and also addresses Nicholas’ concern regarding performance).

@Nich: I do log an error when I can’t fallback (so far using FindObjectOfType, from now on using OnEnable … probably I’ll go with both 😉 ). Actually, I even log warnings when these fallbacks are used. But I think it’s really important to make your projects survive compilation (didn’t do it with one big project and it’s been a pain all along), so I think the OnEnable / FindObjectOfType “thingees” should always be present. At least in the editor 😉

Does posting source code already work in the comments section?

Add Your Comment