- Home /
The question is answered, right answer was accepted
Singleton usage wherever possible? GAWSANA in Unity?
GAWSANA == Global Access When Singletons Are Not Available.
Hi,
We're currently in the process of building a prototype to get up to scratch with the process of making a game and I'm just wondering what the best practice is with regards to Singletons. Essentially, would it make sense to make all the classes that should only be used once into a singleton, or is it unnecessary?
At the moment, the GameController (which controls the game state and a few other basic things) is one, but should I do the same for the PlayerController scripts? These are obviously only used once on the player, but is there any need to do this other than to make it easier to reference them on other objects (which would be a nice advantage!)?
I've also included the Singleton part of the GameController. Is this adequate? I've seen a few versions of 'Unity singletons' since and I'm not sure how the code below could cause any issues.
Thanks!
public class GameController : MonoBehaviour
{
// Create a singleton - only one instance of this class can be made
private static GameController _instance = null;
public static GameController Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.FindObjectOfType(typeof(GameController)) as GameController;
}
return _instance;
}
}
void Awake ()
{
_instance = this;
}
Singletons are perfect and beautiful in some pipelines (example, native XCode development.) Singletons are utterly useless in other pipelines. I have come to believe singletons are utterly useless in Unity.
An incredibly simple solution we use all the time now is explained here: http://answers.unity3d.com/questions/551297/how-can-i-instantiate-a-prefab-from-a-static-funct.html
I hope it helps someone reading.
@Fattie I disagree and believe that singletons have equal place in Unity as they do in other program$$anonymous$$g languages. The following clip from Unite'13 is a good example of such an occasion:
http://youtu.be/Ozc_hXzp_$$anonymous$$U?t=5m20s
Your Grid
class looks very similar to the singleton pattern but using Find
ins$$anonymous$$d of instantiation.
One way to workaround the current inability to auto-load is to place a simple automatic loading script in every scene to initialise some global state either at start of game, or even when debugging. I have been experimenting with this approach and it seems to be working out pretty well:
http://leahayes.wordpress.com/2013/09/18/automatic-initialisation-at-runtime-with-easy-maintenance/
I agree in the sense that singletons shouldn't be abused though since static state should be avoided wherever possible.
I have found that singletons are useless in unity - they lead only to confusion - for the reason that: the Unity paradigm (indeed the game engine paradigm) is to have components attached to gameObjects. You can't get around this.
Anything else is a contortion.
Secondly the entire reason d'etre of singletons (in say XCode native program$$anonymous$$g) is the concept of "one physically real thing". This is why singletons are used everywhere and always on iOS devices, for the "actual" accelerometer, the "actual" clock, the "actual" compass and so on. Whereas in Unity (/game engines generally), there very much is - everywhere and always - "real" objects already!!!!!!!
The whole very nature of the game engine paradigm. Like if you were a programmer from $$anonymous$$ars and you were first introduced to game engines, your first observation would be "how cool, you won't need singletons because the concept of a single existing real object is inherent - nice.:
Thirdly say (for some reason!) you insisted on using a singleton in unity. I have never seen a good, elegant, pattern that everyone agrees on. There are some incredibly torturous patterns. (The one in the example you linked to is horrible, it would be x'd out of any large project with a big $$anonymous$$m.) Particularly when people tortorously try to "instance = " on components!!
Fourthly from experience when working only on large projects, they are useless. When time is money it's a nonstarter as there is no advantage, at all, in any way -- so they just waste time. Indeed I sometimes have to (unfortunately for me!) come in and take over large catastrophe projects that have gone to hell:
there's no time for something as obscure and confusing and deba$$anonymous$$ble as singletons (with no advantage offered, whatsoever). I mean you could pay the five programmers to sit around for 1 day's wages and agree on a way to do singletons and then start trying to change them all like that .. Why? Better just to pay for the art department to make some more cool explosions.
If one was asked.... "here's something really confusing, and irregular, with utterly no benefit, that you can use is you want .." you wouldn't use it!
"Your Grid class looks very similar to the singleton pattern" well it couldn't be more different, because a singleton is a singleton and this is simply the idea of using a static to centralise, just as you say, Find.
(Actually I ran out of comment room so continued in the next! ....)
[1]: http://answers.unity3d.com/questions/441246/editor-script-to-make-play-always-jump-to-a-start.html
( ... cont.)
"One way to workaround the current inability to auto-load..."
I suggest you do not do this: why? -->
on every unity project, you have to have objects that are "always there". That is an unavoidable fact. So it means you must have a "pre-load-scene". Every non-trivial Unity project has this. I've never seen a Unity project without a "pre-load-scene". As I say in the other..
"Don't forget you must have in your project .. game objects which are absolutely always there -- this is inevitable in every Unity project.(Indeed -- this further means that, inevitably, you have a special "tiny scene" that is scene zero and has no purpose, at all, other than to introduce these "always there" game objects. So, you must launch your project from scene zero.)"
(As Jamora ses, "As to how you can easily start your game from that special "tiny scene", this question has a few ideas." Heh!)
If you are trying to avoid having a pre-load-scene, by, having clever code on every scene that checks if, your "pre-load-stuff" is there, and if not and it's the first case it launches it (presumably staying unique by checking who is oldest etc) ... it is torturous! I suggest, if it was a big commercial "time is money' project someone would just say "that is fascinating code, please absolutely delete it all everywhere, add a 'pre-load-scene' and commit" ;-)
$$anonymous$$now what I mean?
When you refer to the current inability to autoload. I$$anonymous$$O. Unity's paradigm of being able to mark items as dontdestroy, is not ideal. Since, 100% of projects need a "pre-load-scene", in fact unity should make that an inherent part of the unity paradigm. Thus, there should be inherently a special "pre-load area". Essentially scene zero, and, anything on there in fact is persistent throughout the whole game. At a stroke it would completely eli$$anonymous$$ate all issues related. Anyways my thoughts on the matter CHEERS!
I vote for the idea of Unity making that PRE_GA$$anonymous$$E
scene something persistence. Or at least, come up with something of better or equal goodness and tell us "hey, you should use this
to keep your persistence data alive ins$$anonymous$$d of co$$anonymous$$g up with obscured ways. We've battled-tested it, it works."
Answer by vexe · Oct 10, 2013 at 10:32 AM
First, buckle up. This is gonna be a hell of a ride! \\m/
The singleton pattern is indeed, one of the most miss-used and debated pattern amongst all other patterns.
They say it's evil, its evilness comes from the fact that most people use it because they're too lazy to pass their references to their classes, and they feel that it's easier to just have an easy global access to their variables, which smells like static (no need to say how evil statics are, if they're misused)
You can read all about what the experts have to say about it (which normally, a lot of us including me don't give a rat ass about lol), but they all circle around:
It's hard to perform tests on singletons.
They hide your class dependencies.
What if, at some point in the future you decided that you need another reference of your class?
So does this mean you shouldn't use a singleton? - You can use the singleton AS LONG AS YOU DON'T MISS-USE IT!
Why do I mean by that? - Well, singletons exist to give you the ability to have only one instance of your object at a time. They're NOT meant to be used only to provide easy global access. That's when you miss-use it.
Would it make sense to make all the classes that should only be used once into a singleton, or is it unnecessary?
Well, it's definitely not a must. But if for some reason you must have only one instance of your class, if you're 100% sure that you won't need more than
one, and you don't actually care about the global access (sweet-looking) feature, if you see that your object will live throughout your entire application, then by all means, USE IT! (DO. IT. Gus tone lol) WITHOUT FEAR (especially from those who scare you away from it for no reason). Otherwise, don't.
I will tell you of some other alternatives in a second, for now here's a nice Singleton implementation, taken from the wiki, and modified by me so that if you ever had more than one instance of your gameObject
, all the extra instances get destroyed and only one remains:
using UnityEngine;
public class MonoBehaviourSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static object mLock = new object();
private static T mInstance;
public static T Instance
{
get
{
lock (mLock) {
if (mInstance == null) {
// try to find it
T[] instances = FindObjectsOfType(typeof(T)) as T[];
// couldn't find any object
if (instances == null || instances.Length == 0) {
var instanceObj = new GameObject("(Singleton) " + typeof(T));
mInstance = instanceObj.AddComponent<T>();
Debug.Log("[Singleton]: An instance of `" + typeof(T) + "` is needed." +
" So gameObject `" + instanceObj.name + "` was created" +
" with `" + typeof(T) + "` component attached to it");
}
else {
// see if there's more than one, if so, do something about it
if (instances.Length > 1) {
Debug.LogWarning("[Singleton]: There is more than one instance of `" +
typeof(T) +
"` in your scene. Destroying all, keeping only one...");
for (int i = 1, len = instances.Length; i < len; i++) {
Destroy(instances[i]);
}
}
else if (instances.Length == 1) {
Debug.Log("[Singleton]: Found only one instance of `" +
typeof(T) +
"` in `" + instances[0].gameObject.name +
"` So singlation successful! :)");
}
mInstance = instances[0];
}
DontDestroyOnLoad(mInstance); // for preservation of this object through scenes
}
return mInstance;
}
}
}
public void Ping()
{
Debug.Log("[Singleton]: `" + this + "` is alive!");
}
protected virtual void Awake()
{
Ping(); // this is just so that DontDestroyOnLoad gets called on the gameObject that's gonna this script upon waking up - Calling Ping means accessing the singleton instance, doing so calls DontDestroyOnLoad at the end.
}
}
As you can see what's nice about this implementation, is that it inherits from MonoBehaviour
so you can enjoy coroutines, etc. The other cool thing as I mentioned, is that if more than one instance is found, all die but one. You don't have to worry about nulls. And it's also thread-safe.
USAGE:
public class GameController : MonoBehaviourSingleton<GameController>
{
// ...
}
Now from anywhere else you can: GameController.Instance.doStuff();
- If doStuff
is called regularly, you could avoid a few keystrokes by introducing a static method in your GameController
:
void static void DoStuff()
{
Instance.doStuff();
}
Now you can immediately: GameController.DoStuff();
So far I have no problems using this system whatsoever (From a not-very-long-time usage perspective)
FURTHER AWESOME REASONS TO USE THE SINGLETON:
Everybody is doing it.
The singleton pattern makes you invincible.
Singleton rhymes with "win" (or "fun" depending on your accent).
(from)
Now that we're done with that, let me introduce you to the first alternative, a new product, a product that will change your life (it's beer, huehue hueheu hue): It's Mr.Fattie's almighty super awesome immortal Grid system (@Fattie)
Take a look at it here.
Now, I was actually intending to open up a large question related to Singletons and this system, but I couldn't have the time. But since I wanted to do that, I went ahead and made a clean, nice implementation of Mr.Fattie's system, I renamed it Container
which I think is more expressive in terms of the meaning:
using UnityEngine;
public static class Container
{
public static AtlasManager AtlasManager { private set; get; }
public static GameController GameController { private set; get; }
public static InventoryManager InventoryManager { private set; get; }
// insert more stuff here...
public static GameObject HoldAll { private set; get; }
static Container()
{
HoldAll = SafeFindWithTag(Tags.holdAll);
Object.DontDestroyOnLoad(HoldAll);
AtlasManager = Add(AtlasManager);
InventoryManager = Add(InventoryManager);
GameController = Add(GameController);
// when you insert something new, don't forget to Add it
}
private static GameObject SafeFindWithTag(string tag)
{
var GO = GameObject.FindWithTag(tag);
if (GO == null)
ThrowError("[Container]: GameObject of tag `"
+ tag
+ "` was not found!");
return GO;
}
private static void ThrowError(string msg)
{
Debug.LogError(msg);
Debug.Break();
}
private static T SafeGetComponent<T>(GameObject from) where T : Component
{
T comp = from.GetComponent<T>();
if (comp == null)
ThrowError("[Container]: Component `"
+ typeof(T)
+ "` was not found in the GameObject `"
+ from.name);
return comp;
}
private static T SafeGetComponent<T>() where T : Component
{
return SafeGetComponent<T>(HoldAll);
}
public static T Add<T>(T member) where T: Component
{
Object.DontDestroyOnLoad(member);
return SafeGetComponent<T>();
}
public static void Ping(GameObject go)
{
Debug.Log("[Container]: Hear you loud and clear, `" + go.name + "`");
}
public static void Ping()
{
Debug.Log("[Container]: Everything's working fine. IT'S ALIVE!");
}
}
As you can see it's all clean, you got generics going on, minimal code and ease of usage.
USAGE:
Let's say you wanted to add an
AudioManager
to your game, you first create theAudioManager
class, attach it to a gameObject.Once you do that, you now come to the
Container
, and add a static property like you see above for yourAudioManager
- and add it to the system usingAudioManager = Add(AudioManager);
Which will add it toHoldAll
(I will explain about it in a sec)Now you can enjoy
Container.GameController.DoStuff();
(you can do the same static trick I did in the singleton to reduce keystrokes)
One thing I haven't mentioned, is the HoldAll
idea. What you do is, to have a gameObject
called HoldAll
whose soul purpose is to hold persistence data (like managers, controllers and whatnot ) across scenes. You would create this gameObject
in a scene, on its own! a Pre_Game
scene, from that point you have your data with you, and you can travel between your scenes with your data carried with you. But just make sure that the user don't have the ability to later come back to this scene, cause a lot of users had problems with that in that they had duplicates of the HoldAll
object, so they go around it creating counter-measures (Mr Fattie's new favorite word) by attaching scripts, that checks if they're more than one object, the other gets destroyed, etc. I personally don't find a reason for that, I just don't go back to that scene and that's it.
A good idea, would be to have a simple script attached to your HoldAll
gameObject, that simply does this:
void Start()
{
Container.Ping(); // must bring it alive before loading anything game-related
Application.LoadLevel(1);
}
And that's it really, you start with your PRE_GAME
scene, you Ping
the Container
just to bring it alive thus calling DontDestroyOnLoad. (Recall that, Container
has a static constructor, and that gets only called when you access anything in the Container
, that's why Ping
is enough for us)
Of course, this HoldAll
idea isn't restricted to the Container
system, in fact you should always use it (or something similar) to preserve/ keep your persistent data alive.
This Container system works really great, I haven't found any issues with it. Yeah Mr.Fattie, yeah Grid!
I can't really compare it with the Singleton
implementation I gave you because I don't have enough experience with either of those.
Oh and, almost forgot, the Tags
mentioned above (in Tags.holdAll
) is just a class I always use to manage my tags:
public static class Tags
{
public const string holdAll = "HoldAll";
// ... add new tags as you move along
}
The const
keyword makes the variable kinda static, and constant at the same time (you can't change it) - So you could access the tags like Tags.Player
, etc.
The final alternative I know about, is Mr.Jamora's Monostate
idea, found here. (@Jamora)
I haven't got the time to test it unfortunately, but I could tell you a couple of differences between it and the singleton. But first take a look at this, to see how it's implemented at its core (nice article btw). Now for the differences:
SINGLETON:
- Only
one
instance! (Max one object)Creational pattern.
Needs to be threadsafe!
Tough to inherit something.
Lazy initialization.
- Only
MONOSTATE:
- Only
one
state! (You could have more than one object, but all have the same state)Behavioral pattern.
Constructor is already thread-safe.
Could easily inherit.
Need to new up an object.
- Only
(Source)
I hope that was helpful to you, and to others investigating the matter in the future.
"Whether you think you can do it or not, you're right in both cases ;)"
EDIT: Just came across a very nice well-written book about design patterns in games. Here's the singleton part (Amazing stuff). I really liked every part in that book.
EDIT: Came up with a new system, "Verfices" - Check it out :D
Damn brotha, you really put a lot of your time into this. Definitely a +1, wish I could give more. It's kind of sad how many people view these but don't vote on them, I know how that feels first hand lol. $$anonymous$$eep up the good work though, you'll start catching moderators' attention and gaining a better reputation on UA. I'll definitely keep an eye on your questions and answers, and vote on anything helpful / constructive. I can tell you have what it takes to move to the top :)
Thanks man, really appreciate it. But I see a lot of debate on this subject, so I said it's about time I write something that covers the whole thing, mentioning all solutions alternatives. It's a bit long I agree, which is why I think it kinda drives you away from it, but once you start reading, it won't be too long till your realize you've finished reading it :D
Excellent answer. I particularly like the part where you explain the $$anonymous$$onostate =).
But seriously, I'll be referencing people here when they have questions about singletons.
I have no idea how I missed this answer originally, especially considering its length!
I'll hopefully take a good look later, thanks!
Answer by numberkruncher · Oct 10, 2013 at 09:31 AM
I should think that the following would be sufficient:
public class GameController : MonoBehaviour {
public static GameController Instance { get; private set; }
void Awake() {
Instance = this;
}
If you want to manage player controllers then something like the following might be useful:
public class PlayerManager : MonoBehaviour {
public static PlayerManager Instance { get; private set; }
// Players should add/remove themselves
public List<PlayerController> players = new List<PlayerContorller>();
void Awake() {
Instance = this;
}
}
public class PlayerController : MonoBehaviour {
void OnEnable() {
PlayerManager.Instance.players.Add(this);
}
void OnDisable() {
PlayerManager.Instance.players.Remove(this);
}
}
Answer by CHPedersen · Oct 10, 2013 at 09:32 AM
If there is need for just one version of the object across the entire lifespan of the application, then it makes sense to make the object a singleton. The nice part about a singleton is that its implementation hides away the troublesome concerns about whether an object has been created or not, so you never have to worry whether it is accessible or null at the moment you access it. Singleton implementations, when done right, are always globally accessible.
What worries me about your implementation is that your Singleton class does not have control over object instantiation itself. The value of the private singleton _instance is instead based on objects which are operable by the Unity API. So the class has no guarantee that its _instance might not become null outside its control at a later stage, if Unity decides to Destroy the object to which GameController is the attached script, for example. This could occur if a Scene change takes place and the object to which _instance refers isn't marked with DontDestroyOnLoad. Additionally, this Singleton implementation cannot guarantee that GameController is actually globally singleton. As far as this code is concerned, there might be more GameObjects which have a GameController attached, and _instance just becomes the first one encountered by GameObject.FindObjectOfType. These issues work to defeat the purpose of singleton. If you want true singletons, your singleton class must have full control itself over object instantiation and destruction.
Correction: The referenced _instance object wouldn't become null after destruction, but the singleton would prevent the class instance from being garbage collected, and next time you access it, you would get a $$anonymous$$issingReferenceException with the message "The object of type 'GameObject' has been destroyed but you are still trying to access it.". That's how Unity's runtime handles that situation. :)
Yeah, automatic instantiation is generally a good idea. In my game I have an "InitGameBehaviour" game object (connected to prefab) which automatically instantiates the game controller with the associated game configuration on scene load if a game controller has not already been instantiated. The advantage with this approach is that you can have logic run on game load without a setup scene.
http://leahayes.wordpress.com/2013/09/18/automatic-initialisation-at-runtime-with-easy-maintenance/
Thanks.
We're very much learning as we go, so I used the version above from a tutorial that actually introduced the concept.
I'm assu$$anonymous$$g the version here is much safer to use?
On scene load you should enumerate any player lists (when using DontDestroyOnLoad
) like so:
for (int i = 0; i < players.Count; ++i)
if (players[i] == null) // faux null due to `==` overload
players.RemoveAt(i--);
Well, I think the version you already posted looks fine already, actually. ;) The main paragraph of my post was mostly technical nitpickery. Ignoring their comments on multithreaded synchronization, your version is actually pretty close to what $$anonymous$$icrosoft did in their example.
$$anonymous$$y concern is simply that since the singleton itself can't guarantee that its instanced object actually exists or will get set to something concrete on first access, you have to make sure you guarantee it won't be used until the right time yourself. This means:
You have to make sure you don't access GameController.Instance before Unity has actually created and loaded the object. If you do, GameObject.FindObjectOfType won't find the object, so it returns null and then the singleton implementation assigns null to its instance, and then you get a nasty surprise when you try to access it.
You have to make sure you don't access GameController.Instance at some point in time where the object referenced by _instance has been destroyed by Unity's runtime. I.e. you must keep that GameObject alive externally, or the _instance becomes invalid.
You have to make sure only one GameObject with a GameController script attached exists when GameController.Instance is first accessed, or else, it will just get set to the first one encountered.
If you can guarantee these things yourself, then no problem. :)
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Access Inventory from player 1 Answer
Singleton Class Name Conflict 3 Answers
Preventing my game object from multiplying due to DontDestroyOnLoad() 2 Answers