Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have seen several videos and tutorials for creating singleton objects in Unity, mainly for a GameManager, that appear to use different approaches to instantiating and validating a singleton.

Is there a correct, or rather, preferred approach to this?

The two main examples I have encountered are:

First

public class GameManager
{
    private static GameManager _instance;

    public static GameManager Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = GameObject.FindObjectOfType<GameManager>();
            }

            return _instance;
        }
    }

    void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

Second

public class GameManager
{
    private static GameManager _instance;

    public static GameManager Instance
    {
        get
        {
            if(_instance == null)
            {
                instance = new GameObject("Game Manager");
                instance.AddComponent<GameManager>();
            }

            return _instance;
        }
    }

    void Awake()
    {
        _instance = this;
    }
}

The main difference I can see between the two is:

The first approach will attempt to navigate the game object stack to find an instance of the GameManager which even though this only happens (or should only happen) once seems like it could be very unoptimised as scenes grow in size during development.

Also, the first approach marks the object to not be deleted when the application changes scene, which ensures that the object is persisted between scenes. The second approach doesn't appear to adhere to this.

The second approach seems odd as in the case where the instance is null in the getter, it will create a new GameObject and assign a GameManger component to it. However, this cannot run without first having this GameManager component already attached to an object in the scene, so this is causing me some confusion.

Are there any other approaches that would be recommended, or a hybrid of the two above? There are plenty of videos and tutorials regarding singletons but they all differ so much it is hard to drawn any comparisons between the two and thus, a conclusion as to which one is the best/preferred approach.

share|improve this question
    
What is said GameManager supposed to do? Does it have to be a GameObject? – bummzack 20 hours ago
    
It's not really a question of what the GameManager should do, rather how to ensure there are only ever one instance of the object and the best way to enforce that. – CaptainRedmuff 20 hours ago

Here's a quick summary:

                 Create object   Removes scene   Global    Keep across
               if not in scene?   duplicates?    access?   Scene loads?

Method 1              No              No           Yes        Yes

Method 2              Yes             No           Yes        No

PearsonArtPhoto       No              Yes          Yes        No
Method 3

So if all you care about is global access, all three get you what you need. Use of the Singleton pattern can be a bit ambiguous about whether we want lazy instantiation, enforced uniqueness, or global access so be sure to think carefully about why you're reaching for the singleton, and choose an implementation that gets those features right, rather than using a standard for all three when you only need one.

(eg. if my game will always have a GameManager, maybe I don't care about lazy instantiation - maybe it's only global access with guaranteed existence & uniqueness I care about - in which case a static class gets me exactly those features very concisely, with no scene loading considerations)

...but definitely don't use Method 1 as written. The Find can be skipped more easily with Method2/3's Awake() approach, and if we're keeping the manager across scenes then we very likely want duplicate-killing, in case we ever load between two scenes with a manager already in them.

share|improve this answer
    
Note: it should be possible to combine all three methods to create a 4th method that has all four features. – Draco18s 17 hours ago

It depends, but usually I use a third method. The problem with the methods that you used is that in the event that the object is included to begin with, it will not remove them from the tree, and they can still be created by instantiating too many calls, which could make things really confusing.

public class SomeClass : MonoBehavior {
    private static SomeClass _instance;

    public static SomeClass Instance { get { return _instance; } }


    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(this.gameObject);
        } else {
            _instance = this;
        }
    }
}

The problem with both of your implementations is that they do not destroy an object that is created later. It could work, but one could throw a monkey wrench into the works that could result in a very difficult to debug error down the line. Make sure to check in Awake if there is an instance already, and if so, destroying the new instance.

share|improve this answer
    
You might also want OnDestroy() { if (this == _instance) { _instance = null; } }, if you want to have a different instance in each scene. – Dietrich Epp 10 hours ago

Another option might be to split the class into two parts: a regular static class for the Singleton component, and a MonoBehaviour that acts as a controller for the singleton instance. This way you have full control over the singleton's construction, and it will persist across scenes. This also lets you add controllers to any object that might need the singleton's data, instead of having to dig through the scene to find a particular component.

public class Singleton{
    private Singleton(){
        //Class initialization goes here.
    }

    public void someSingletonMethod(){
        //Some method that acts on the Singleton.
    }

    private static Singleton _instance;
    public static Singleton Instance 
    { 
        get { 
            if (_instance == null)
                _instance = new Singleton();
            return _instance; 
        }
    } 
}

public class SingletonController: MonoBehaviour{
   //Create a local reference so that the editor can read it.
   public Singleton instance;
   void Awake(){
       instance = Singleton.Instance;
   }
   //You can reference the singleton instance directly, but it might be better to just reflect its methods in the controller.
   public void someMethod(){
       instance.someSingletonMethod();
   }
} 
share|improve this answer
    
This is very nice! – CaptainRedmuff 15 hours ago

I'd just like to add that it may be useful to call DontDestroyOnLoad if you want your singleton to persist across scenes.

public class Singleton : MonoBehavior 
{ 
    private static Singleton _instance;

    public static Singleton Instance 
    { 
        get { return _instance; } 
    } 

    private void Awake() 
    { 
        if (_instance != null && _instance != this) 
        { 
            Destroy(this.gameObject); 
        } 
        else 
        { 
            _instance = this;
            DontDestroyOnLoad(this.GameObject);
        } 
    } 
}
share|improve this answer
    
That's very handy. I was just about to post a comment on @PearsonArtPhoto's response to ask this exact question :] – CaptainRedmuff 19 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.