Search Unity

Singleton Monobehaviour Script

Discussion in 'Scripting' started by Nima, Aug 9, 2011.

  1. Nima

    Nima

    Joined:
    May 2, 2011
    Posts:
    75
    I have a script that inherits from monobehaviour and have implemented it as a singleton.

    Code (csharp):
    1.  
    2. public class MyClass : MonoBehaviour
    3. {
    4.  
    5.     static MyClass mInstance;
    6.  
    7.     public static MyClass Instance
    8.     {
    9.         get
    10.         {
    11.             if (mInstance == null) mInstance = new MyClass();
    12.             return mInstance;
    13.         }
    14.     }
    15. }
    16.  
    Since this is a monobehaviour script, I am attaching it to a gameobject or else the monobehaviour functions such as Update() won't be called.

    Code (csharp):
    1.  
    2. MyScript myScript =  mygo.AddComponent<MyScript>();
    3.  
    The problem is now I have two instances of the script. One that I can access through MyScript.Instance, as well as the myScript instance itself. So how can I have a true singleton monobehaviour class with only one instance? The Unity documentation suggests not to use Constructors, or else I would initialize my Instance in there?
     
    Last edited: Aug 9, 2011
  2. Aoon

    Aoon

    Joined:
    Aug 4, 2011
    Posts:
    17
  3. KyleStaves

    KyleStaves

    Joined:
    Nov 4, 2009
    Posts:
    821
    I generally use prefabs for my singleton classes. However, you can do it without prefabs if you want - something like this should work:

    Code (csharp):
    1.  
    2. public class MyClass : MonoBehaviour
    3. {
    4.  
    5.     static MyClass mInstance;
    6.  
    7.     public static MyClass Instance
    8.     {
    9.         get
    10.         {
    11.             if (mInstance == null){
    12.                 GameObject go = new GameObject();
    13.                 mInstance = go.AddComponent<MyClass>();
    14.             }
    15.             return mInstance;
    16.         }
    17.     }
    18. }
    19.  
    If you check the docs, AddComponent creates a new instance of that component, adds it to the GameObject, and then returns that instance.
     
  4. Ntero

    Ntero

    Joined:
    Apr 29, 2010
    Posts:
    1,436
    You can't use New MonoBehaviour, and if you are using a Lazy Singleton you shouldn't have to connect it and create it, the Lazy Singleton should do that itself.

    Code (csharp):
    1.  
    2. public class MyClass : MonoBehaviour
    3. {
    4.  
    5.     static MyClass mInstance;
    6.  
    7.     public static MyClass Instance
    8.     {
    9.         get
    10.         {
    11.             return mInstance ? (mInstance = (new GameObject("MyClassContainer")).AddComponent<MyClass>());
    12.         }
    13.     }
    14. }
    15.  
    This will either use mInstance, or if it's null create the container GameObject and add the Singleton to it, and return that.

    Then do not ever add it to something, just call MyClass.Instance whenever you need it.
    Note: If you want it to persist accross scenes and not be destroyed and recreated add DontDestroyOnLoad(this); in the Awake Function.

    Another Option if you really want to add it to a particular object is to set mInstance in the MyClass's Awake function and if mInstance is not null Destroy any subsequent attempts to create an Instance of MyClass. But in that case do not Set mInstance in the Instance Property, as it's being set by Awake.
     
  5. Eiznek

    Eiznek

    Joined:
    Jun 9, 2011
    Posts:
    374
    How about super lazy?
    Code (csharp):
    1.  public class MyClass : MonoBehavior
    2. {
    3.         public static MyClass myInstance = null
    4.  
    5.         void Start()
    6.         {   myInstance = this; }
    7.  
    However I do like ntero's way incase it is not on an Object.
     
  6. Nima

    Nima

    Joined:
    May 2, 2011
    Posts:
    75
    This is exactly what I needed to do. Thanks for your input!
     
  7. LEGEND383

    LEGEND383

    Joined:
    Aug 1, 2012
    Posts:
    20
    Whilst this is an old thread, it's near the top of Google, so I figured I'd put this here for others to find.

    Code (CSharp):
    1. public class SingletonBehaviour<T> : MonoBehaviour where T: SingletonBehaviour<T>
    2. {
    3.     public static T instance { get; protected set; }
    4.  
    5.     void Awake()
    6.     {
    7.         if (instance != null && instance != this)
    8.         {
    9.             Destroy(this);
    10.             throw new System.Exception("An instance of this singleton already exists.");
    11.         }
    12.         else
    13.         {
    14.             instance = (T)this;
    15.         }
    16.     }
    17. }
    An example use would be as below:

    Code (CSharp):
    1. public class TestSingleton : SingletonBehaviour<TestSingleton>
    2. {
    3.     static int x = 0;
    4.    
    5.     public int TestFunction()
    6.     {
    7.         return instance.x;
    8.     }
    9. }
    10.  
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,333
    ... why's x static? And why's TestFunction not static?

    Now you'll have to do TestSingleton.instance.TestFunction to get at a static field.

    I really prefer the singleton instance to not be exposed, and provide static methods to access it's data. Also, the only reason to create a singleton is if you need the MonoBehaviour callbacks, otherwise it could just be a static class and do the same thing.
     
    AdmiralThrawn likes this.
  9. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    There is a much safer and complete implementation of a Singleton available on the Unity3D Wiki.
     
  10. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,333
    Why is that locking the singleton? The core API isn't thread safe, so that's just promoting a false sense of security.

    Urrr, it's also exposing the instance. As it's a singleton, you're probably doing something wrong if you're passing it to something. What, are you going to put a singleton in a list? Compare it to something? You're just bleeding the fact that it's a singleton into code that doesn't need to care about that. It's also more painful to turn it into a static class or not a MonoBehaviour if you don't need it to be a MonoBehaviour anymore.


    I'm really hoping that Unity rolls the wiki into the main community site soonish, because there's a lot of bad info hanging out there.
     
  11. LEGEND383

    LEGEND383

    Joined:
    Aug 1, 2012
    Posts:
    20
    @Baste My objective was more about abstracting the singleton part into a separate class that is easily used. Just drop the code file into your project, inherit from SingletonBehaviour and you're done.

    Obviously if you would prefer the instance to be private then just change the line:
    Code (CSharp):
    1. public static T instance { get; protected set; }
    for something like:
    Code (CSharp):
    1. protected static T instance;
    making it accessible to any children still (so you can provide access to data via static methods) but hidden from everything else.
     
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I agree with @Baste about the current wiki entry.

    It's even worse, with that wiki's implementation you could start off having multiple instances and you won't even notice until you try to get an instance. Afterwards, it would simply assign one of those multiple instances to the actual static variable while the others keep living.
    You could even keep instantiating those, if the singleton would actually modify the game state this could have extreme bad consequences.

    There should be only one instance at a time and the base class should be designed in a way that it doesn't allow to have multiple at a time.
     
    Last edited: Jul 23, 2016
    DonLoquacious likes this.
  13. jimroberts

    jimroberts

    Joined:
    Sep 4, 2014
    Posts:
    560
    The lock is probably a poor attempt to allow thread safe non Unity related member access. Which should probably be documented somewhere..

    Anyway, welcome to the horrible world of anti-patterns that people love to abuse. Singletons are basically singular instances of an object... The object is generally passed as a parameter or used directly via the public "Instance" variable. Static classes aren't objects, which is where they differ from each other. I think we can all agree that singletons are terrible and should never be used.

    I think they got lazy and decided to just log an error... :(
     
    Last edited: Jul 23, 2016
    AdmiralThrawn and Suddoha like this.
  14. romanzy

    romanzy

    Joined:
    Dec 16, 2014
    Posts:
    1
    Here is another implementation I came up with. Useful if you need to have a single global MonoBehaviour script accessible from anywhere. Here is the MonoSingleton class:

    Code (CSharp):
    1. using UnityEngine;
    2. public class MonoSingleton<T> where T : MonoBehaviour
    3. {
    4.     private static T _instance;
    5.     private static bool isFound;
    6.     private bool createMissingInstance;
    7.     static MonoSingleton()
    8.     {
    9.         isFound = false;
    10.         _instance = null;
    11.     }
    12.     public MonoSingleton(bool createNewInstanceIfNeeded = true)
    13.     {
    14.         this.createMissingInstance = createNewInstanceIfNeeded;
    15.     }
    16.     public T Instance
    17.     {
    18.         get
    19.         {
    20.             if (isFound && _instance)
    21.             {
    22.                 return _instance;
    23.             }
    24.             else
    25.             {
    26.                 UnityEngine.Object[] objects = GameObject.FindObjectsOfType(typeof(T));
    27.                 if (objects.Length > 0)
    28.                 {
    29.                     if (objects.Length > 1)
    30.                         Debug.LogWarning(objects.Length + " " + typeof(T).Name + "s were found! Make sure to have only one at a time!");
    31.                     isFound = true;
    32.                     _instance = (T) System.Convert.ChangeType(objects[0], typeof(T));
    33.                     return _instance;
    34.                 }
    35.                 else
    36.                 {
    37.                     Debug.LogError(typeof(T).Name + " script cannot be found in the scene!!!");
    38.                      if (createMissingInstance)
    39.                     {
    40.                         GameObject newInstance = new GameObject(typeof(T).Name);
    41.                         isFound = true;
    42.                         _instance = newInstance.AddComponent<T>();
    43.                         Debug.Log(typeof(T).Name + " was added to the root of the scene");
    44.                         return _instance;
    45.                     }
    46.                     else
    47.                     {
    48.                         isFound = false;
    49.                         return null; // or default(T)
    50.                     }
    51.                 }
    52.             }
    53.         }
    54.     }
    55. }
    To use it, define MonoSingletons inside a static class. For example:

    Code (CSharp):
    1. public static class Global
    2. {
    3.     public static MonoSingleton<GameProgress> progress = new MonoSingleton<GameProgress>(true); //true means that new GameObject with script GameProgress will be created if it is missing from the scene
    4.     public static MonoSingleton<CharacterController> characterController = new MonoSingleton<CharacterController>(false); //will return null if there is no character controller present in the scene.
    5. }
    And call from code:

    Code (CSharp):
    1. Global.progress.Instance.score++;
     
    zwcloud likes this.
  15. zwcloud

    zwcloud

    Joined:
    Mar 15, 2016
    Posts:
    377
    an improved version of romanzy's to ignore prefab objects when running in editor:

    Code (CSharp):
    1.  
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEngine;
    5.  
    6. public class MonoSingleton<T> where T : MonoBehaviour
    7. {
    8.     private static T _instance;
    9.     private static bool isFound;
    10.     private bool createMissingInstance;
    11.     static MonoSingleton()
    12.     {
    13.         isFound = false;
    14.         _instance = null;
    15.     }
    16.     public MonoSingleton(bool createNewInstanceIfNeeded = true)
    17.     {
    18.         createMissingInstance = createNewInstanceIfNeeded;
    19.     }
    20.     public T Instance
    21.     {
    22.         get
    23.         {
    24.             if (isFound && _instance)
    25.             {
    26.                 return _instance;
    27.             }
    28.  
    29.             Object[] objects = Resources.FindObjectsOfTypeAll(typeof(T));
    30.             #if UNITY_EDITOR//ignore prefab asset objects
    31.             List<Object> objectList = objects
    32.                 .TakeWhile(o => !UnityEditor.PrefabUtility.IsPartOfPrefabAsset(o))
    33.                 .ToList();
    34.             objects = objectList.ToArray();
    35.             #endif
    36.             if (objects.Length > 0)
    37.             {
    38.                 if (objects.Length > 1)
    39.                     Debug.LogWarning(objects.Length + " " + typeof(T).Name + "s were found! Make sure to have only one at a time!");
    40.                 isFound = true;
    41.                 _instance = (T) System.Convert.ChangeType(objects[0], typeof(T));
    42.                 return _instance;
    43.             }
    44.  
    45.             Debug.LogError(typeof(T).Name + " script cannot be found in the scene!!!");
    46.             if (createMissingInstance)
    47.             {
    48.                 GameObject newInstance = new GameObject(typeof(T).Name);
    49.                 isFound = true;
    50.                 _instance = newInstance.AddComponent<T>();
    51.                 Debug.Log(typeof(T).Name + " was added to the root of the scene");
    52.                 return _instance;
    53.             }
    54.  
    55.             isFound = false;
    56.             return null;
    57.         }
    58.     }
    59. }
    60.  
     
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,688
    Wow, that is some serious significant lines of code to do something so incredibly simple.

    I'm not even sure I can reason about all the different ways that code operates!!

    Why do you even care about editor vs game?!

    This stuff can be made FAR simpler, with exactly the same persistence and lifecycle abilities.

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance!

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
     
    zwcloud likes this.
  17. zwcloud

    zwcloud

    Joined:
    Mar 15, 2016
    Posts:
    377
    It depends, sometimes one wants to put the instance inside the scene asset to be able to assign objects to its fields via dragging in editor.
     
  18. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    How would you set it up if you want to use the inspector to drag GOs onto it? You obviously drag the class onto an empty GO in the editor but how do you get its instance? With this in your "Simple" version?:
    _Instance = gameObject.GetComponent<SingletonSimple>();
     
  19. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,688
    I would strive to have those GameObjects become part of whatever Prefab thing gets loaded by the above singleton stand-up process.

    This has a double benefit of grouping areas of concern into hierarchies of GameObjects, rather than producing a fragile spider web of interconnected stuff all over the scene.

    If it just wasn't possible, or reasonable, to include the referenced objects, then I would NOT go with a drag-it-in approach but rather use a service locator pattern where those in-scene GameObjects register themselves with the singleton construct they need above.
     
    Last edited: Feb 1, 2022
  20. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    I agree with Kurt here.

    Singletons are an anti-pattern. Maintaining clear separation of concerns and disciplined dependency strategies will make you a much better engineer in the long run. Singletons are just globals that push your codebase towards one big tangled mess that's a nightmare to test, maintain and change as it grows.
     
    sacredgeometry likes this.
  21. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,688
    Just for the record, to be clear, I love singletons, particularly in smaller rapid-setup projects.

    Singletons can trivially solve an incredibly wide range of important problems in game development. They are particularly excellent on eliminating the sheets of mindless boilerplate crap you have to do if you insist on going the instance routes: getters, setters, dragging stuff in EVERYWHERE (oh wait, I forgot one place), everybody passing everything around. Especially with new users, this boilerplate crap just confuses things unnecessarily.

    Yes, they have their drawbacks, but the utility and simplicity of static / singleton type constructs in a small game cannot be overstated. They are AWESOME.

    And when your small game grows to the point that singletons cause issues, you already will have needed to refactor other stuff, so just refactor out the problem singletons.

    Remember it is SOFT ware. That means it is SOFT, you can change it when a previously-chosen solution needs to be refactored.
     
    Last edited: Feb 1, 2022
    TreeHacks likes this.
  22. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    I'd agree if I more people understood that. If it's a small prototype then static ref all the things to get it over the line - They just seem to end up being a crutch for so many people and you end up with developers who have like 5+ years experience who still don't understand IoC or good dependency management because they just put singletons bloody everywhere.

    IMO they're a gotta know the rules before you can break them scenario. Learn why you shouldn't first, then once you know why you shouldn't, you can - but I grantee 99% of the articles you find online about how to use singletons don't ever touch on why you shouldn't.
     
    sacredgeometry likes this.
  23. SimRuJ

    SimRuJ

    Joined:
    Apr 7, 2016
    Posts:
    247
    What if I don't have any prefabs that would be connected to the singleton?

    I asked here how to find an inactive GO in the scene and was told to use a manager script that, well, keeps track of inactive GOs. I didn't find any information about what a "manager script" was supposed to look like, so I created a regular script (on an empty object) that I dragged the GOs onto in the inspector but was then told here that I should make the manager script a singleton (apparently that's the most common approach) because I then won't have to use "Find" to find it - which sounded great.

    Currently I've already got a static class that passes data around between classes (like a URL that's set once, then used by multiple scripts,...) but never wanted to make any of the GOs static through that to pass them around because it feels kind of "bad" to make GOs static. There are a couple of things a lot of my classes use (e.g. a certain "pause" function), so if I could keep that one in the manager script and also drag on the important bits in the inspector (instead of having to do it separately in 5 other classes), that would be awesome.

    But now I'm being told here that singletons are bad (sometimes), so now (I have to admit) I'm a bit confused what to use.

    I'm aware that it's good to keep certain things as independent from each other as possible but if you've got multiple classes that all have to use a single same thing (but otherwise all do different things and that you don't want to combine because of that), wouldn't it be better to have that thing in a central place, instead of repeating the same function (with the same "find" calls or inspector-drags) multiple times, which is also a pain in the .... if you have to change something about it?
     
  24. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,333
    I mean what you're running into is that different people have wildly different ideas about what's good design, so what some people think is the Correct Way to do things is something other people think is a Horrible Anti-Pattern.

    Here's how I would solve your issue, and what I think about this kind of issue;

    Do you only have one scene loaded at a time? In that case I'd just have a script who's purpose is to find the thing you're looking for. Then it'd be relatively simple pseudo-singleton. Add in error messages for possible error cases so you get actionable errors instead of nullrefs that you have to debug, and you have a pretty decent design:

    Code (csharp):
    1. public class ThingamajigFinder : MonoBehaviour {
    2.     private static ThingamajigFinder instance;
    3.     private GameObject thingamajig;
    4.  
    5.     private void Awake() {
    6.         if (instance != null)
    7.             Debug.LogError("More than one ThingamajigFinder in scene " + gameObject.scene.name);
    8.         instance = this;
    9.     }
    10.  
    11.     public static GameObject Thingamajig {
    12.         get {
    13.             if (instance == null) {
    14.                 Debug.LogError("There's no Thingamajig in scene " + SceneManager.GetActiveScene().name);
    15.                 return null;
    16.             }
    17.             if (instance.thingamajig == null) {
    18.                 Debug.LogError("The ThingamajigFinder in scene " + SceneManager.GetActiveScene().name + " doesn't have a thingamajig assigned!", instance.thingamajig);
    19.                 return null;
    20.             }
    21.             return instance.thingamajig;
    22.         }
    23.     }
    24. }

    Now, this is only a good way to do things if you've only got one scene loaded at a time. If you're in a multi-scene setup, you need to make decisions about what to do if two scenes with thingamajigs are loaded at the same time. I'd probably have a Dictionary<Scene, ThingamajigFinder> and have the method take a scene as a parameter and return the Thingamajig for that scene. But that's implementation details you need to adjust to your code base anyway.

    The big problem with this design is that you have added a bunch of overhead to making new scenes, as you can't just make a scene and then go, you have to remember to put all the correct scripts in the scene. This is somewhat alleviated by the new scene template thing you can use, so new scenes have all the correct prefabs and such, but it's still clunky. So only do it if you absolutely need to access GameObjects in the scene.

    For settings and such, I'd go with a ScriptableObject approach instead where every scene had it's related settings data (light settings, background music, whatever) stored in a file that was linked to the scene in some way. If you then let scenes that doesn't have any related data yet have sensible defaults, then you don't have to deal with the extra work of making scenes be correct.

    In the general case, never make a Singleton when a static class would do. There's three reasons to use a singleton over a static class, with varying validity:
    Reason 1: You need access to scene objects. This is valid. You'd probably be swapping out the singleton when you swap scenes, but that's fine
    Reason 2: You need the thing to receive Start/Update calls. That is a bit valid, but I'd argue that just having a static class and hook up to the PlayerLoopSystem is a better approach to this.
    Reason 3: You want to swap the singleton implementation for testing. Having this desire usually means that your runtime code is brittle, and you should fix that instead of bypassing it in tests.
     
  25. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    265
    Singletons in Unity are something that far too many developers tend to over-complicate. It gets to a point where it's hard to make sense of what order things will execute in, when it's safe to access the instance, etc.

    Just earlier today I finished writing up a rather lengthy Twitter thread covering an alternative way to implement them, which I believe simplifies things significantly (in addition to being a very little amount of code.)

    At some point it might make sense to reproduce it as a proper forum post with some additions, but for now the thread is here (or unrolled here if Twitter threads aren't your thing.)
     
    d3eds, reelie and theforgot3n1 like this.
  26. reelie

    reelie

    Joined:
    Apr 25, 2017
    Posts:
    10
    Excellent thread! I like it a lot and might be using it from now on!

    One question though. What's the purpose of the IPersistentObject interface? You're using it its Initialize() method within the static PersistentObjects.Initialize() method, but couldn't you just GetComponentsInChildren<MonoSingleton> instead?

    From my understanding, we don't want to have an object that is IPersistentObject without being a MonoSingleton, so we can safely remove the interface, can't we?

    Thanks a lot!
     
  27. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    265
    You certainly could, but then you would be locked into that particular implementation of a singleton class. IPersistentObject exists to give you more flexibility so you can have different kinds of persistent objects (i.e., if you have an existing component that you want to expose as a singleton, but it can't inherit from MonoSingleton because it's already inheriting from another base class). If that scenario doesn't apply to your code, and you only intend to use MonoSingleton, then you can essentially remove it, yes.
     
    reelie likes this.