Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Singleton Creating

Discussion in 'Scripting' started by Lancaster13, Mar 5, 2015.

  1. Lancaster13

    Lancaster13

    Joined:
    Dec 24, 2014
    Posts:
    25
    Hello guys,

    I´m a student of C# programming, and today I'm reading about Singletons, and Immortal Objects. One of the better example is the GameManager (The Backbone of game). The author write this code(Follow Below), but i guess its wrong, because the object that should be destroyed is not the the actual item, so he carry a lot of informations of another levels, such as Score, HP, Mana, Etc.I'm right or I'm wrong? If I'm wrong, explain me how i will keep the informations about the player, if the GameManager will destroyed to enter in the level? Thanks =D
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Controller : MonoBehaviour {
    5.  
    6.  
    7.     public static Controller Instance
    8.     {
    9.         get
    10.         {
    11.             return instance;
    12.         }
    13.     }
    14.  
    15.     private static Controller instance = null;
    16.  
    17.     public int Highscore = 0;
    18.     public bool IsPaused = false;
    19.     public bool InputAllowed = true;
    20.  
    21.     void Awake ()
    22.     {
    23.         if (instance)
    24.         {
    25.             DestroyImmediate(gameObject);
    26.             return;
    27.         }
    28.  
    29.         instance = this;
    30.  
    31.         DontDestroyOnLoad(gameObject);
    32.     }
    33.  
    34. }
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    I'm not completely sure what you're asking.

    The code you posted makes it so that the first Controller to Awake becomes a permanent and globally-visible object (it won't be destroyed on level load, and any script can get access to it through the public static property at the top of the class), but that if you ever get a second Controller for some reason, the second one will automatically destroy itself.

    This will allow you to carry any data stored in the Controller (Highscore, IsPaused, InputAllowed) into new scenes. Any data that's not stored in the controller (current score, HP, mana, etc.) won't be preserved (unless it's being preserved in some other way).

    Does any of that help?
     
  3. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,616
    well that's some code you have...

    if(instance) DestroyImmediate(gameObject) is wrong. That destroys your controller as soon as its created.

    my preferred method these days is thus... this doesnt require the object to exist in the scene, it will get created as soon as something tries to use it.

    Code (csharp):
    1.  
    2.  
    3. public class GameManager : monobehaviour
    4. {
    5. static GameManager _instance;
    6. static GameManager GetInstance()
    7. {
    8.     if(_instance == null)
    9.     {
    10.        _instance = new GameObject("_GameManager").AddComponent<GameManager>();
    11.        _instance.Initialise();
    12.     }
    13.  
    14.     return _instance;
    15. }
    16.  
    17. int score = 5;
    18.  
    19. void Initialise()
    20. {
    21.     //do startup stuff
    22. }
    23.  
    24. public static int GetScore()
    25. {
    26.     return GetInstance().score;
    27. }
    28.  
    29. public static void SetScore(int score)
    30. {
    31.     GetInstance().score = score;
    32. }
    33.  
    34. }
    35.  
    36.  
    37.  
    38.  
     
    vitalie8484 likes this.
  4. knr_

    knr_

    Joined:
    Nov 17, 2012
    Posts:
    258
    Hi lancaster,

    Singletons, if implemented correctly, will never be destroyed until the program is stopped.

    In my experience I have needed to use two separate implementations for singletons - one that is a MonoBehaviour singleton, and one that is just a C# singleton.

    One of the greatest pitfalls I have noticed is users who make something a MonoBehaviour based singleton just because they are accustomed to working with MonoBehaviours in Unity.

    The only time a singleton should be a MonoBehaviour singleton (this is my opinion obviously and could be debated) is if the singleton requires functionality that is embedded in the MonoBehaviour class (like coroutines).

    I will show you how to make both.

    First, the non-MonoBehaviour singleton:

    This code is taken directly from Microsoft's documentation, located here:

    https://msdn.microsoft.com/en-us/library/ff650316.aspx

    Code (CSharp):
    1. using System;
    2.  
    3. public sealed class Singleton
    4. {
    5.    private static volatile Singleton instance;
    6.    private static object syncRoot = new Object();
    7.  
    8.    private Singleton() {}
    9.  
    10.    public static Singleton Instance
    11.    {
    12.       get
    13.       {
    14.          if (instance == null)
    15.          {
    16.             lock (syncRoot)
    17.             {
    18.                if (instance == null)
    19.                   instance = new Singleton();
    20.             }
    21.          }
    22.  
    23.          return instance;
    24.       }
    25.    }
    26. }
    Now, with the above code you would change the name of the class from Singleton to something more descriptive, like GameManager. You may have more than one type of singleton in your project. For instance, you might have a GameManager to manage game stuff, a NetworkManager to manage network related functionality... in our case we also have a FacebookManager that hides the lower level Facebook API calls behind nice, simple functions that we can access from any place in code.

    Next up is the Singleton based off of a MonoBehaviour. This code is taken directly from:

    http://wiki.unity3d.com/index.php/Singleton

    Code (CSharp):
    1. using UnityEngine;
    2. /// <summary>
    3. /// Be aware this will not prevent a non singleton constructor
    4. ///   such as `T myT = new T();`
    5. /// To prevent that, add `protected T () {}` to your singleton class.
    6. ///
    7. /// As a note, this is made as MonoBehaviour because we need Coroutines.
    8. /// </summary>
    9. public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    10. {
    11.     private static T _instance;
    12.     private static object _lock = new object();
    13.     public static T Instance
    14.     {
    15.         get
    16.         {
    17.             if (applicationIsQuitting) {
    18.                 Debug.LogWarning("[Singleton] Instance '"+ typeof(T) +
    19.                     "' already destroyed on application quit." +
    20.                     " Won't create again - returning null.");
    21.                 return null;
    22.             }
    23.             lock(_lock)
    24.             {
    25.                 if (_instance == null)
    26.                 {
    27.                     _instance = (T) FindObjectOfType(typeof(T));
    28.                     if ( FindObjectsOfType(typeof(T)).Length > 1 )
    29.                     {
    30.                         Debug.LogError("[Singleton] Something went really wrong " +
    31.                             " - there should never be more than 1 singleton!" +
    32.                             " Reopening the scene might fix it.");
    33.                         return _instance;
    34.                     }
    35.                     if (_instance == null)
    36.                     {
    37.                         GameObject singleton = new GameObject();
    38.                         _instance = singleton.AddComponent<T>();
    39.                         singleton.name = "(singleton) "+ typeof(T).ToString();
    40.                         DontDestroyOnLoad(singleton);
    41.                         Debug.Log("[Singleton] An instance of " + typeof(T) +
    42.                             " is needed in the scene, so '" + singleton +
    43.                             "' was created with DontDestroyOnLoad.");
    44.                     } else {
    45.                         Debug.Log("[Singleton] Using instance already created: " +
    46.                             _instance.gameObject.name);
    47.                     }
    48.                 }
    49.                 return _instance;
    50.             }
    51.         }
    52.     }
    53.     private static bool applicationIsQuitting = false;
    54.     /// <summary>
    55.     /// When Unity quits, it destroys objects in a random order.
    56.     /// In principle, a Singleton is only destroyed when application quits.
    57.     /// If any script calls Instance after it have been destroyed,
    58.     ///   it will create a buggy ghost object that will stay on the Editor scene
    59.     ///   even after stopping playing the Application. Really bad!
    60.     /// So, this was made to be sure we're not creating that buggy ghost object.
    61.     /// </summary>
    62.     public void OnDestroy () {
    63.         applicationIsQuitting = true;
    64.     }
    65. }
    Now, you wouldn't use the code as it is; this simply defines what a MonoBehaviour singleton would look like. To actually make it into a specific type of singleton, you would create a new C# class that derives from it. For instance, if you want to make a CoroutineManager, you would do this (assuming that you have added the above class to your project somewhere):

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CoroutineManager : Singleton<CoroutineManager>
    5. {
    6.     protected CoroutineManager() { }
    7.  
    8.     IEnumerator Perform(IEnumerator coroutine)
    9.     {
    10.         yield return StartCoroutine(coroutine);
    11.     }
    12.  
    13.     /// <summary>
    14.     /// Place your lovely static IEnumerator in here and witness magic!
    15.     /// </summary>
    16.     /// <param name="coroutine">Static IEnumerator</param>
    17.     public static void Run(IEnumerator coroutine)
    18.     {
    19.         Instance.StartCoroutine(Instance.Perform(coroutine)); //this will launch the coroutine on our instance
    20.     }
    21. }
    22.  
     
  5. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    That's clearly exactly what it's supposed to do. The "if (instance)" part means that you only destroy it if instance has already been initialized, which will only be true if you already have one of these singletons floating around and the one that is currently running Awake is redundant.
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    I always disliked the boiler plate code for a Singleton.

    Especially since I would sometimes want Singletons that survived for the entirity of the game, and others that only lasted the entirity of a scene.

    So I wrote this 'Singleton' class that any singleton I want to create inherits from. It automatically becomes a singleton, and the boiler plate is all in one place.

    https://code.google.com/p/spacepuppy-unity-framework/source/browse/trunk/SpacepuppyBase/Singleton.cs

    I also wrote a special Singleton called 'SingletonManager', that comes with an inspector:
    https://code.google.com/p/spacepupp...pyBaseEditor/Inspectors/SingletonInspector.cs

    By default a SingletonManager instance is created on a GameObject that survives the entirity of the game. You can add simple singletons through this inspector directly to that GameObject. OR you can add instances to their own GameObject in a scene.

    Just like @rnakrani, it automatically creates a singleton if it doesn't exist when you call 'GetInstance'.
     
  7. knr_

    knr_

    Joined:
    Nov 17, 2012
    Posts:
    258
    You can definitely do either, although destroying a Singleton violates the design pattern of a Singleton.

    In the case of destroying a Singleton when a new scene is loaded (or when one is destroyed), what I do is have Reset() functions on my Singletons that do all the necessary cleanup for anything stored within the Singleton's.

    Also, instantiating and destroying classes fragments the dynamic memory that has been allocated to your program so if you don't have to destroy something then you should not destroy it. If there is anything you can do to "reset" something that has been instantiated rather than deleting the existing one only to create another later you should go down that route first.
     
    Last edited: Mar 5, 2015
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    It's more for if say you have a singleton that represents the level that's currently loaded. Well when that level gets unloaded... singleton no longer needed.

    There is nothing about the singleton pattern that says it must be immortal. It's only enforcing that one exists when one is needed.
     
  9. knr_

    knr_

    Joined:
    Nov 17, 2012
    Posts:
    258
    Ah, you're right, my bad.

    At that point it becomes an architectural decision on whether or not to have game-instance specific singletons are not.
     
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377