Singleton Sorrow

In my 2D platformer I have a Dialogue Manager object and a Canvas to display the dialogue. I want to persist them from scene to scene. In order to do this I created a parent object with this script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Singleton : MonoBehaviour
{
    private static Singleton instance;
    public static Singleton Instance { get { return instance; } }
    void Awake()
    {
        if (instance == null)
            instance = this;
        else if (instance != this)
            Destroy(gameObject.GetComponent(instance.GetType()));
        DontDestroyOnLoad(gameObject);
    }
}

It does persist, but when I switch scenes I have two instances in my hierarchy. I have this Parent Object (With the dialogue manager and canvas) in every scene. But I want the original one to persist and the other one to be destroyed on entering the room. I need to have them in every room because of saving and loading.

I hope someone can help me understand what I should do differently to solve this.

Here you go:

    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static T instance = null;
        private static readonly Object syncRoot = new Object();

        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        if (instance == null)
                        {
                            instance = GameObject.FindObjectOfType(typeof(T)) as T;
                            if (instance == null)
                                Debug.LogError("SingletoneBase<T>: Could not found GameObject of type " + typeof(T).Name);
                        }
                    }
                }
                return instance;
            }
        }
    }

It doesn’t look like you are checking if the instance does not equal null.

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

}

Thanks that works like a charm!

Im not sure how to work with this kind of inheritance. Next up on my learning list

1 Like

For singleton-ish stuff I would highly recommend NEVER placing something in scene. That always just leads to sorrow and mass future disasters and confusions.

@Terraya 's solution above is definitely really nice and simple, but I like to take it one step simpler and do away with the inheritance because I believe it provides no value in this context and only confuses what is actually happening.

This is always my go-to solution:

Simple Singleton (UnitySingleton):

Some super-simple Singleton examples to take and modify:

Simple Unity3D Singleton (no predefined data):

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

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:

public void DestroyThyself()
{
   Destroy(gameObject);
   Instance = null;    // because destroy doesn't happen until end of frame
}

There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

1 Like

Thanks, I will look into that. It may be a bit advanced for me tbh. But it does seem like a much better way to go.