2
\$\begingroup\$

I have a GameObject in Unity, which I've attached this script to, in order to make it function as a Static Singleton :

using UnityEngine;
using System.Collections;

public class SceneStatics : MonoBehaviour {


    private static SceneStatics instance;

    public static SceneStatics Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new GameObject ("SceneStatics").AddComponent<SceneStatics> ();
                DontDestroyOnLoad(instance);
            }

            return instance;
        }
    }

    public void OnApplicationQuit ()
    {
        instance = null;
    }
}

I have two other scripts that I'd like to be able to access from scene to scene. What's the proper way to do that?

Do I attach my Inventory and Room scripts to the same game object as the SceneStatics? If so, how do I access them? Can I go from SceneStatics.Instance to one of the other scripts directly via GetComponent?

Alternatively, what happens if I add two child gameObjects (each containing one of the other scripts) to the SceneStatics?

Or is the intended use that I simply make any other static items I need properties of the SceneStatics class? (I.e., add in a Public static Inventory and Public static Room attributes)?

\$\endgroup\$
0

3 Answers 3

3
\$\begingroup\$

A really short way of ensuring there's only one instance of a script in the scene is to get it to destroy itself on creation if others are found.

public class UIManager : MonoBehaviour {

    void Awake()
    {
        // hyper-advanced singleton implementation
        if (FindObjectsOfType(typeof(UIManager)).Length > 1)
        {
            Debug.Log("UIM: Already found instance of script in scene; destroying.");
            DestroyImmediate(gameObject);
        }
    }
}

Does your class absolutely have to extend MonoBehaviour? If not, you might as well make it a static class.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, that's a good idea. Static class makes the most sense. \$\endgroup\$ Jul 25, 2012 at 2:17
  • 1
    \$\begingroup\$ This form of destruction results in an arbitrary survivor. If you change scenes and a new copy shows up, which one gets destroyed? The one with data already set or the new one with blank default values? If you don't know the answer, then the code is flawed. \$\endgroup\$ Nov 28, 2019 at 17:42
1
\$\begingroup\$

Here is an example of a proper Unity singleton implementation https://wiki.unity3d.com/index.php/Singleton. However, you can simplify the code for your needs. The article also contains an example of how to use this class.

In case of a dead link here is the code:

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;
    }
}

And an example of how to use it:

public class MySingleton : Singleton<MySingleton>
{
    // (Optional) Prevent non-singleton constructor use.
    protected MySingleton() { }

    // Then add whatever code to the class you need as you normally would.
    public string MyTestString = "Hello world!";
}

public class MyClass : MonoBehaviour
{
    private void OnEnable()
    {
        Debug.Log(MySingleton.Instance.MyTestString);
    }
}

So to use this class you need to inherit from it instead of MonoBehaviour. And you can access your class anywhere just by its name and getter Instance. Also, you can simplify this class with your needs. For example, you can get rid of the lock if you don't use multithreading. It will slightly speed up your code but you won't be able to safely use it in a multithreading environment.

\$\endgroup\$
1
  • \$\begingroup\$ This is currently a link-only answer, which are discouraged on StackExchange. Please consider editing your answer to contain at least a rough summary of the information you hope a reader will glean from this link, so they're not wholly out of luck if the link ever rots. \$\endgroup\$
    – DMGregory
    Nov 26, 2019 at 17:45
-1
\$\begingroup\$

Personally I think singletons are an abomination and I don't recommend them. But you can implement them however you like. There's no such thing as a 'proper' way.

If you only want 1 of something, just create a single instance. You don't need a code straitjacket to stop you adding more, and you'll probably find a use for more later. So why bother?

Do I attach my Inventory and Room scripts to the same game object as the SceneStatics?

Nobody can answer that without knowing what those scripts do or what the implications of such an attachment are.

Can I go from SceneStatics.Instance to one of the other scripts directly via GetComponent?

Yes, certainly. If a GameObject has multiple components then you can easily find one from the other.

What happens if I add two child gameObjects (each containing one of the other scripts) to the SceneStatics?

Nothing happens. You now have 3 game objects. To access one from the other will require a little more than a simple GetComponent, but that's all.

Is the intended use that I simply make any other static items I need properties of the SceneStatics class?

There's no intention here, just many different ways of reaching a goal. I try to avoid statics in Unity as (a) they're generally just globals in disguise, and (b) you lose the potential benefit of being able to use the Inspector to edit the values. Instead I'll just have one GameObject with one instance of the component and will create it in the scene that needs it. In the very rare occasions I need something to persist throughout I just have 1 instance in the first scene and use DontDestroyOnLoad.

\$\endgroup\$
5
  • \$\begingroup\$ Well, my intent is to create global classes I can access from wherever. My precursory googling indicated that Static GameObjects were the way to go. Is there a better way to handle global and intra-scene logic? \$\endgroup\$ Jul 24, 2012 at 22:32
  • \$\begingroup\$ Globals are generally considered a bad idea in programming, though to explain why would be beyond the scope of this answer. If you feel you need this functionality then statics give you that. \$\endgroup\$
    – Kylotan
    Jul 24, 2012 at 22:43
  • 2
    \$\begingroup\$ Globals are often misused; they are not inherently bad. I have a suite of singleton controller classes that need to persist between scenes and be easily accessed by GameObjects. Do you suggest something other than a global and/or static solution? I asked this question because I'm trying to find the best way forward, not because I'm dead set on using statics. \$\endgroup\$ Jul 24, 2012 at 23:33
  • \$\begingroup\$ I'm afraid I would disagree and say that a global variable or object is inherently bad. But that's not important here. My ideal solution for components that must outlast a single scene in Unity is to attach them to an object in the first scene and use DontDestroyOnLoad. \$\endgroup\$
    – Kylotan
    Jul 25, 2012 at 0:46
  • \$\begingroup\$ The code structure I'm using these days avoids singletons, but I'm not sure if I'm using 'statics' in the sense that you guys are it. I do have globally accessible objects inserted into static variables, but which objects are inserted into those variables is controlled by an initialization object that swaps in different modules for different platforms. \$\endgroup\$
    – jhocking
    Aug 20, 2014 at 15:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .