DeviArt
DeviArt

Reputation: 469

Unity singleton manager classes

In Unity, whats a good way to create a singleton game manager that can be accessed everywhere as a global class with static variables that will spit the same constant values to every class that pulls those values? And what would be the way to implement it in Unity? Do I have to attach it to a GameObject? Can it just be there in a folder without being in the scene visually?

Upvotes: 37

Views: 32890

Answers (9)

YOUNES BELHIT
YOUNES BELHIT

Reputation: 24

 using UnityEngine;

 public class Singleton<T> : MonoBehaviour where T : Singleton<T>
 {   


   public static T instance { get; private set; }

    protected virtual void Awake() {

    if (instance == null)
    {
        instance = (T)this;
        DontDestroyOnLoad(gameObject);
        OnInit();
    }
    else if (instance != this)
    {
        Destroy(gameObject);
    }
  }

  protected virtual void OnInit()
  {

  }


}

GameManage :

class GameManager : Singleton<GameManager> {


}

Upvotes: 0

Fattie
Fattie

Reputation: 12625

Engineers who are new to Unity often don't notice that

you can't have a "singleton" in an ECS system.

It is meaningless.

All you have in Unity is GameObjects, at, XYZ positions. They can have components attached.

It would be like trying to have "a singleton" or "inheritance" in .... Photoshop or Microsoft Word.

Photoshop file - pixels at XY positions
Text editor file - letters at X positions
Unity file - GameObjects at XYZ positions

It is "just that simple".

So, in a game you will have "general" behaviors where there is only "one" of the thing. (So obviously there is only "one sound effects engine" , "one screen", "one scoring system" and so on.) A normal programmer would think of those as "singletons", but Unity just has nothing to do with singletons and no connection to singletons.

So if you have "a tank" or "a tree" of course it's normal you may have dozens of those things. But "the sound effects engine" or "the networking system" are "general, only-one-of-them" systems.

Hence, trivially, in Unity "the sound effects engine" or "the networking system" very simply sits on a game object, and, you (obviously) just have the one of them.

Those "general, only-one-of-them" items just sit on the preload scene.

You absolutely have to have a preload scene anyway, in every Unity project.

(Simple how-to: https://stackoverflow.com/a/35891919/294884 )

In the future Unity will include a "built-in preload scene" - when that day comes this will finally never be discussed again!

(Note - some of the languages you use to compile Components for Unity of course have OO concepts; but Unity itself has no connection to OO at all. Unity is like photoshop. You have "game objects" each at a certain 3D position.)

(Note - in the early days of Unity you'd see attempts at making code, say c#, which creates a game object on the fly, attempts to keep the game object unique, and "attaches itself" to the game object as a component. Apart from being completely bizarre/pointless, just FWIW it's theoretically not possible to ensure uniqueness (actually not even within a single frame). Again, it's moot because in Unity general behaviors just go on the preload scene.)

Upvotes: 2

Hassaan sohail
Hassaan sohail

Reputation: 47

Here is a simple code taken from Unity Tutorial. for better understanding open the link

using System.Collections.Generic;       //Allows us to use Lists. 

public class GameManager : MonoBehaviour
{

    public static GameManager instance = null;              //Static instance of GameManager which allows it to be accessed by any other script.
    private BoardManager boardScript;                       //Store a reference to our BoardManager which will set up the level.
    private int level = 3;                                  //Current level number, expressed in game as "Day 1".

    //Awake is always called before any Start functions
    void Awake()
    {
        //Check if instance already exists
        if (instance == null)

            //if not, set instance to this
            instance = this;

        //If instance already exists and it's not this:
        else if (instance != this)

            //Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GameManager.
            Destroy(gameObject);    

        //Sets this to not be destroyed when reloading scene
        DontDestroyOnLoad(gameObject);

        //Get a component reference to the attached BoardManager script
        boardScript = GetComponent<BoardManager>();

        //Call the InitGame function to initialize the first level 
        InitGame();
    }

    //Initializes the game for each level.
    void InitGame()
    {
        //Call the SetupScene function of the BoardManager script, pass it current level number.
        boardScript.SetupScene(level);

    }



    //Update is called every frame.
    void Update()
    {

    }

Upvotes: 0

Muhammad Sulaiman
Muhammad Sulaiman

Reputation: 11

Instead of creating one singleton for each class. I would suggest you to create a generic class for singleton. i use to follow this method which make my life very easy.

For More detail visit here

Or

Create Unity C# class in unity and use following code

/// <summary>
/// Inherit from this base class to create a singleton.
/// e.g. public class MyClassName : Singleton<MyClassName> {}
/// </summary>
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    // Check to see if we're about to be destroyed.
    private static bool m_ShuttingDown = false;
    private static object m_Lock = new object();
    private static T m_Instance;

    /// <summary>
    /// Access singleton instance through this propriety.
    /// </summary>
    public static T Instance
    {
        get
        {
            if (m_ShuttingDown)
            {
                Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                    "' already destroyed. Returning null.");
                return null;
            }

            lock (m_Lock)
            {
                if (m_Instance == null)
                {
                    // Search for existing instance.
                    m_Instance = (T)FindObjectOfType(typeof(T));

                    // Create new instance if one doesn't already exist.
                    if (m_Instance == null)
                    {
                        // Need to create a new GameObject to attach the singleton to.
                        var singletonObject = new GameObject();
                        m_Instance = singletonObject.AddComponent<T>();
                        singletonObject.name = typeof(T).ToString() + " (Singleton)";

                        // Make instance persistent.
                        DontDestroyOnLoad(singletonObject);
                    }
                }

                return m_Instance;
         }
      }
  }

  private void OnApplicationQuit()
  {
     m_ShuttingDown = true;
  }

  private void OnDestroy()
  {
    m_ShuttingDown = true;
  }
}

Upvotes: 0

Behnam Rasooli
Behnam Rasooli

Reputation: 722

One way to do it is to make a scene just to initialize your game manager like this:

public class GameManager : MonoBehaviour {
    static GameManager instance;

    //other codes

    void Awake() {
        DontDestroyOnLoad(transform.gameObject);
        instance = this;
    }

    //other codes
}

That's it, that's all you need to do. And then immediately after initializing the game manager, load the next scene and never come back to this scene again.

Have a look at this tutorial: https://youtu.be/64uOVmQ5R1k?list=WL

Edit: Changed GameManager static instance; to static GameManager instance;

Upvotes: 0

Bivis
Bivis

Reputation: 1407

I wrote a singleton class that makes easy to create singleton objects. Its is a MonoBehaviour script, so you can use the Coroutines. Its based on this Unity Wiki article, and I will add option to create it from Prefab later.

So you don't need to write the Singleton codes. Just download this Singleton.cs Base Class, add it to your project, and create your singleton extending it:

public class MySingleton : Singleton<MySingleton> {
  protected MySingleton () {} // Protect the constructor!

  public string globalVar;

  void Awake () {
      Debug.Log("Awoke Singleton Instance: " + gameObject.GetInstanceID());
  }
}

Now your MySingleton class is a singleton, and you can call it by Instance:

MySingleton.Instance.globalVar = "A";
Debug.Log ("globalVar: " + MySingleton.Instance.globalVar);

Here is a complete tutorial: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/

Upvotes: 1

LITM
LITM

Reputation: 51

If this class is just for accessing global variables then you don't really need a singleton pattern for this, or use a GameObject.

Simply create a class with public static members.

public class Globals
{
    public static int mStatic1 = 0;
    public static float mStatic2 = 0.0f;
    // ....etc
}

The other solutions are fine but overkill if all you need is global access to variables.

Upvotes: 2

rygo6
rygo6

Reputation: 1989

This is the setup I have created.

First create this script:

MonoBehaviourUtility.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

static public class MonoBehaviourUtility 
{

    static public T GetManager<T>( ref T manager ) where T : MonoBehaviour
    {
        if (manager == null)
        {
            manager = (T)GameObject.FindObjectOfType( typeof( T ) );
            if (manager == null)
            {
                GameObject gameObject = new GameObject( typeof( T ).ToString() );
                manager = (T)gameObject.AddComponent( typeof( T ) );
            }
        }
        return manager;
    }

}

Then in any class you want to be a singleton do this:

public class ExampleManager : MonoBehaviour 
{   
    static public ExampleManager sharedManager 
    {
        get 
        {
            return MonoBehaviourUtility.GetManager<ExampleManager>( ref _sharedManager );
        }
    }   
    static private ExampleManager _sharedManager;       
}

Upvotes: 0

Kay
Kay

Reputation: 13146

Like always: it depends. I use singletons of both kinds, components attached to GameObject and standalone classes not derived from MonoBehaviour. IMO the overall question is how are instances bound to the lifcycle of scenes, game objects, ... And not to forget sometimes it is more convenient to have a component especially referencing other MonoBehaviour objects is easier and safer.

  1. There are classes that just need to provide some values like for example a config class that needs to load settings from persistence layer when called. I design theese classes as simple singletons.
  2. On the other hand some objects need to know when a scene is started i.e. Start is called or have to perform actions in Update or other methods. Then I implement them as component and attach them to a game object that survives loading new scenes.

I designed component based singletons (type 2) with two parts: a persistent GameObject called Main, which holds all components and a flat singleton (type 1) called MainComponentManager for managing it. Some demo code:

public class MainComponentManger {
    private static MainComponentManger instance;
    public static void CreateInstance () {
        if (instance == null) {
            instance = new MainComponentManger ();
            GameObject go = GameObject.Find ("Main");
            if (go == null) {
                go = new GameObject ("Main");
                instance.main = go;
                // important: make game object persistent:
                Object.DontDestroyOnLoad (go);
            }
            // trigger instantiation of other singletons
            Component c = MenuManager.SharedInstance;
            // ...
        }
    }

    GameObject main;

    public static MainComponentManger SharedInstance {
        get {
            if (instance == null) {
                CreateInstance ();
            }
            return instance;
        }
    }

    public static T AddMainComponent <T> () where T : UnityEngine.Component {
        T t = SharedInstance.main.GetComponent<T> ();
        if (t != null) {
            return t;
        }
        return SharedInstance.main.AddComponent <T> ();
    }

Now other singletons that want to register as Main component just look like:

public class AudioManager : MonoBehaviour {
    private static AudioManager instance = null;
    public static AudioManager SharedInstance {
        get {
            if (instance == null) {
                instance = MainComponentManger.AddMainComponent<AudioManager> ();
            }
            return instance;
        }
    }

Upvotes: 51

Related Questions