- Home /
Unity C# Singleton?
I'm trying to make a simple singleton object, basically just exists and spams the console that it exists so I can confirm it works when switching scenes (using Application.LoadLevel(Scene)). This doesn't work yet, the Debug.Log fails to continue when loading the new scene and I'm kinda stuck. All the examples I've seen for Singletons look similar to this, just kinda banging my head into a wall. Any ideas?
using UnityEngine;
using System.Collections;
public class SimpleSingleton : MonoBehaviour
{
private static SimpleSingleton instance = null;
// Game Instance Singleton
public static SimpleSingleton Instance
{
get
{
return instance;
}
}
private void Awake()
{
// if the singleton hasn't been initialized yet
if (instance != null && instance != this)
{
Destroy(this.gameObject);
}
instance = this;
DontDestroyOnLoad( this.gameObject );
}
void Update()
{
Debug.Log( "SINGLETON UPDATE" );
}
}
Not really sure... but it looks like you are destroying the gameObject, then saying, to DontDestoyOnLoad it.. um... perhaps, instance = this;
should be this = instance;
also, the following would mean it has not been initialized yet (instance==null)
so you need to add, near the top... if(instance==null) instance=this;
I don't think that trying to assign to the this
pointer is the answer to that Glurth. But certainly you're right that all the stuff in Awake
after the conditional shouldn't be performed if the Destroy call has been made! I think the answer there is just to put it in an else
block.
Also I don't like the look of && instance != this
in that conditional. If true it would suggest that Awake is being called for a second time on the same object.
These changes would basically turn the code into what your second para says.
I tried the method at http://wiki.unity3d.com/index.php/Singleton, but maybe I'm misunderstanding something because it isn't behaving as I expect. Do I need a gameObject with the Singleton on it in every scene? I made a super simple Singleton object based on the URL above and Update() is only being called in the first Scene (where the object lives), and stopping in the second scene (where I currently do not have an object of the singleton). The object looks like:
public class SimpleSingleton : Singleton<SimpleSingleton>
{
protected SimpleSingleton() {} // guarantee this will be always a singleton only - can't use the constructor!
public string debug$$anonymous$$essage = "THIS IS A SA$$anonymous$$PLE SINGLETON";
void Update()
{
Debug.Log ( debug$$anonymous$$essage );
}
}
I'm not sure exactly what's going on there, if the Awake() function in the base class is being called then DontDestroyOnLoad() should be being called, and the object should persist through scene changes. You could start by adding Debug.Log calls to that Awake() function to check it is being called.
One thing that is wrong though is your protected constructor. The class is a $$anonymous$$onoBehaviour so you shouldn't define a constructor at all. It's possible that that's what's messing things up.
And no, you shouldn't need an instance in every scene.
I just tried placing a copy of this SimpleSingleton object in both Scene01 and Scene02, and replacing the debug$$anonymous$$essage with:
Debug.Log ( this.GetInstanceID() );
And I'm getting different values when switching between scenes.
Answer by mostwanted9192 · Feb 02, 2015 at 12:16 PM
I have made my own custom singleton pattern which I use for my games. Its very easy to use. Here's a code snippet which i would like to share with you.
#region SINGLETON PATTERN
public static BicycleHandler _instance;
public static BicycleHandler Instance
{
get {
if (_instance == null)
{
_instance = GameObject.FindObjectOfType<BicycleHandler>();
if (_instance == null)
{
GameObject container = new GameObject("Bicycle");
_instance = container.AddComponent<BicycleHandler>();
}
}
return _instance;
}
}
#endregion
P.S BicycleHandler is the script name of my current script which will be used for any object to make it singleton. And "Bicycle is the object name of my GameObject. Replace them according to yours. After that you will be able to use your singleton object like: scriptName.Instance.function();
This is the most elegant implementation I've found so far... But you should change the _instance scope to private.
private static BicycleHandler _instance;
Also, for multi-threaded environments, the get method should be synchronised between threads, so you can add this line before the get method:
[$$anonymous$$ethodImpl($$anonymous$$ethodImplOptions.Synchronized)] get { if (instance == null) {...
Answer by DTFlip · Feb 03, 2015 at 12:00 AM
Well one problem is I'm dumb, I had all my Singleton objects parented to a GameObject that wasn't set to DontDestroyOnLoad... so that fixed pretty much everything. Yay for being a dumb dumb >.<
Well one problem is I'm dumb,
Actually, it takes a genius to realize that about oneself. Obviously, I'm a complete idiot.
Answer by AndresBarrera · Feb 03, 2015 at 11:07 AM
Also, the function Destroy does not destroys the game object instantly. From the documentation: "Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering."
So in your Awake you should put a return statement to avoid executing the whole function. Try this:
private void Awake()
{
// if the singleton hasn't been initialized yet
if (instance != null && instance != this)
{
Destroy(this.gameObject);
return;//Avoid doing anything else
}
instance = this;
DontDestroyOnLoad( this.gameObject );
}
Answer by Brb_Code · Oct 26, 2017 at 10:46 AM
I have developed two version of singleton , both can destroy the component on editor without use the attribue [ExecuteOnEditMode].
GameSingleton only can be added on first built scene and can't be destroyed on load, persist all game. Singleton can be added on any scene but is destroyed on load. Obviously both only let one instance.
This is the Singleton sample:
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
instance = FindObjectOfType<T>();
if (instance == null)
Debug.LogError("Singleton<" + typeof(T) + "> instance has been not found.");
return instance;
}
}
protected void Awake()
{
if (instance == null)
instance = this as T;
else if (instance != this)
DestroySelf();
}
protected void OnValidate()
{
if (instance == null)
instance = this as T;
else if (instance != this)
{
Debug.LogError("Singleton<"+this.GetType() + "> already has an instance on scene. Component will be destroyed.");
#if UNITY_EDITOR
UnityEditor.EditorApplication.delayCall -= DestroySelf;
UnityEditor.EditorApplication.delayCall += DestroySelf;
#endif
}
}
private void DestroySelf()
{
if(Application.isPlaying)
Destroy(this);
else
DestroyImmediate(this);
}
}
The scripts are aviable on my gitHub, https://github.com/Brbcode/BrbAssets/tree/master/Singleton
You should use a generic constraint like this:
public class Singleton<T> : $$anonymous$$onoBehaviour where T : Singleton<T>
In your case i can create a class like this:
public class $$anonymous$$ySingleton : Singleton<SomeOther$$anonymous$$onoBehaviour>
{
}
In this case "T" will not be the same type as "this". By forcing the generic constraint on Singleton<T>
the type parameter can only be a class that is derived from Singleton<T>
It's still possible to create a second singleton with the type of another singleton which would also not work, but at least you can't pick an arbitrary $$anonymous$$onoBehaviour.
public $$anonymous$$ySingleton1 : Singleton<$$anonymous$$ySingleton1> { } // <-- works as intended
public $$anonymous$$ySingleton2 : Singleton<$$anonymous$$ySingleton1> { } // <-- problem here
I didn't realize about that problem, thank you to made me realize. I tried rewrite the code following your advice but i didn't find any change.
In order to solve the problem I have add a new check inside OnValidate funtion.
public $$anonymous$$ySingleton1 : Singleton<$$anonymous$$ySingleton1> { } // <-- works as intended
public $$anonymous$$ySingleton2 : Singleton<$$anonymous$$ySingleton1> { } // <-- It's removed when is added as component
It's the best solution that I've find.
using UnityEngine;
/// <summary>
/// Singleton only let one instace of Type T per scene.
/// <para>Note: Singleton instance can be destroyed.</para>
/// </summary>
/// <typeparam name="T">T inherits from $$anonymous$$onoBehavior</typeparam>
public class Singleton<T> : $$anonymous$$onoBehaviour where T : Singleton<T>
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
instance = FindObjectOfType<T>();
if (instance == null)
Debug.LogError("Singleton<" + typeof(T) + "> instance has been not found.");
return instance;
}
}
protected void Awake()
{
if (this.GetType() != typeof(T))
DestroySelf();
if (instance == null)
instance = this as T;
else if (instance != this)
DestroySelf();
}
protected void OnValidate()
{
if (this.GetType() != typeof(T)) //Change to solve the problem
{
Debug.LogError("Singleton<"+typeof(T)+ "> has a wrong Type Parameter. " +
"Try Singleton<" + this.GetType() + "> ins$$anonymous$$d.");
#if UNITY_EDITOR
UnityEditor.EditorApplication.delayCall -= DestroySelf;
UnityEditor.EditorApplication.delayCall += DestroySelf;
#endif
}
if (instance == null)
instance = this as T;
else if (instance != this)
{
Debug.LogError("Singleton<"+this.GetType() + "> already has an instance on scene. Component will be destroyed.");
#if UNITY_EDITOR
UnityEditor.EditorApplication.delayCall -= DestroySelf;
UnityEditor.EditorApplication.delayCall += DestroySelf;
#endif
}
}
private void DestroySelf()
{
if(Application.isPlaying)
Destroy(this);
else
DestroyImmediate(this);
}
}
Answer by OcarinhaOfTime · Feb 02, 2015 at 11:56 AM
Here you may find what you need (around 22 min): http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/creating-a-scene-menu. Here he makes the background music a "DontDestroyOnLoad" object to have the the same instance of object in multiples scenes and give some tips to guarantee that we have only one instance of this object.