- Home /
Create a persistent GameObject using Singleton
Hi all! :) I need to have a GameObject that doesn't destroy when a new scene is loaded (or if the same scene is reloaded). So I went for the Singleton pattern, and took the Singleton.cs and MonoBehaviourExtended.cs files from the [**Unify Wiki**][1]
Then I created my singleton class:
using UnityEngine;
public class ControllerBehaviour : Singleton<ControllerBehaviour> {
protected ControllerBehaviour() {}
public float foo = 0;
}
Then I created a GameObject called Controller and I added that script to it. The problem is that it seems that the Controller GameObject destroys when the scene is reloaded using this instruction:
Application.LoadLevel(Application.loadedLevelName);
I say it because I have an object Ball that, when collides with another object (called Checkpoint), it increments the foo variable of the Controller object.
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name == "Checkpoint")
{
ControllerBehaviour.Instance.foo++;
Debug.Log("ControllerBehaviour.Instance.foo = " + ControllerBehaviour.Instance.foo);
}
}
Initially it works fine, but after the scene is reloaded, when that collision happens, I get the following Warning and Error to Console:
UnityEngine.Debug:LogWarning(Object) Singleton`1:get_Instance() (at Assets/scripts/Singleton.cs:21) Ball:OnTriggerEnter2D(Collider2D) (at Assets/scripts/Ball.cs:69)WARNING: [Singleton] Instance 'ControllerBehaviour' already destroyed on application quit. Won't create again - returning null.
Ball.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/scripts/Ball.cs:69) Why does it happen? I used the Singleton class from the [Unify Wiki][1], that contains the DontDestroyOnLoad() function. Thank you in advance for your help! :) [1]: http://wiki.unity3d.com/index.php/SingletonERROR: NullReferenceException: Object reference not set to an instance of an object
It seems that the 'dontdestroyonload' is only called if you actually get the singleton at least once, meaning it is only initialized when you use it. If you don't use it, change scenes and then use it, will have destroyed the gameObject of the singleton since it was never told not too.
Try accessing the Singleton before switching scenes. If this is the case, we should update the wiki if we find a solution.
Try accessing the Singleton before switching scenes. If this is the case, we should update the wiki if we find a solution.
Unluckly this is the case: I access the Singleton before reloading the scene. Thank you for your answer anyway! :)
Thank you for your tip. I'll try implementing the singleton this way and I'll let you know. :) Anyway it should work the Singleton class of Unify Wiki, so either I'm doing something wrong (very probable), or maybe something changed in Unity core so that it doesn't work anymore.
Ehi, I've just tried doing like you said and it works perfectly! Thank you very much joonturbo!
Answer by joonturbo · Nov 16, 2013 at 06:01 PM
I have a bit of a hack that I use a lot:
public class myClass : MonoBehaviour {
public static myClass i;
void Awake () {
if(!i) {
i = this;
DontDestroyOnLoad(gameObject);
}else
Destroy(gameObject);
}...
Then if youw ant to use it, from anywhere in code, do myClass.i.whatever. Added bonus is that fields are still available in the inspector
EDIT:Added the else statement to make it appropriate regarding the title (singleton)
Well, this is actually missing the point of singleton. A singleton means you want one and only one instance of the class. With your implementation, if a new instance is created, well it is there and if using FindObjectOfType, you expect to get the good one and you can be served with the wrong one, not understanding why the values are wrong.
void Awake () {
if(i == null) {
i = this;
DontDestroyOnLoad(gameObject);
}
else Destroy(this); // or gameObject
}
The else part will make sure that if an instance of that class already exists and is already assigned to the static reference, then you destroy the newly created.
Thank you for your tip! I'll add the else part then.
so will I from now on, it always felt like a 'hack', but with this it probably is a bit more proper :).
The Destroy(gameObject) in the else statement seems like a bad idea. The second time the scene is loaded, your game object will be destroyed, even if there only is a single one. Also, use DestroyImmediate ins$$anonymous$$d. See @YawJatah's answer below.
Answer by YawJatah · Feb 12, 2018 at 04:24 AM
Hi All, I know that this thread has been around for a while. I was having similar design conundrum and stumble about this thread. The answer by @joonturbo is 90% correct. But instead of using Destroy, you should use DestroyImmediate. The Unity documentation has big warnings with regards to using DestroyImmediate outside the context of an editor script (never set the second parameter to true or else the actually assets on your hard drive will be permanently deleted!). But without DestroyImmediate, this technique isn't a true Singleton pattern. The reason is that, Destroy, happens after the first update. This means that you second object isn't deleted until the whole scene has had a chance to run, and every other object has had it's awake, start, update (and all other unity method) called at least once. This is becomes problematic if you have reference to your singleton object, by another singleton object (and you haven't set the proper execution order, and even then you end up with a possible deadlock). Bref, to make this gameobject truly unique and avoid another object getting a handle on an invalid version of the object due to DontDestroyOnLoad, or another object with the script attached in the scene, use DestroyImmediate instead of Destroy, so that the secondary instance, gets destroy right away. The code ends up looking more like this:
public class PersistentGameObjectSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
#region Public Accessors
/// <summary>
/// Static instance of PersistentGameObjectSingleton which allows it to be accessed by any other script.
/// </summary>
public static PersistentGameObjectSingleton<T> Instance { get; private set; }
#endregion
#region Unity methods
/// <summary>
/// Things to do as soon as the scene starts up
/// </summary>
void Awake()
{
Logging.Log("{0} - Awoken. Initializing Singleton pattern. Instance Id : {1}", this.GetType().Name, gameObject.GetInstanceID());
if (Instance == null)
{
Logging.Log("{0} - Setting first instance. Instance Id : {1}", this.GetType().Name, gameObject.GetInstanceID());
//if not, set instance to this
Instance = this;
//Sets this to not be destroyed when reloading scene
DontDestroyOnLoad(gameObject);
}
else if (Instance != this)
{
Logging.LogWarning("{0} - Destroying secondary instance. Instance Id : {1}", this.GetType().Name, gameObject.GetInstanceID());
//Then destroy this. This enforces our singleton pattern, meaning there can only ever be one instance of a GlobalManager.
DestroyImmediate(gameObject);
return;
}
}
Note: I generalized the pattern using templates, so that you can easily use it on any other class. Hope this little tip helps any other person in the future who stumbles upon this thread.
Cheers,
Answer by BillyMFT · Aug 19, 2016 at 06:25 AM
Just a word of warning regarding a Unity bug that cost me a few hours. I'm using the same unify wiki singleton script above, and started getting the "already destroyed on application quit. Won't create again - returning null" error. It turned out that Unity had actually managed to save one of my dynamically created singleton objects into a scene file.
So in my hierarchy (while not in play mode) I had a game object that was clearly created by the script because it was named "(singleton) GameManager". For some reason it remained in the scene file when I stopped playing. I deleted it and everything was fine again.
I doubt that this is a bug in Unity. $$anonymous$$aybe you used ExecuteInEdit$$anonymous$$ode somewhere? ExecuteInEdit$$anonymous$$ode can have such sideeffects. If you run code (deliberately) at edit time things will be saved to the scene. ExecuteInEdit$$anonymous$$ode can be dangerous if used wrong.
Further more the singleton version on the wiki is a messy implementation. First of all it doesn't really support creating an instance manually in the scene because if it already exists, the code does not mark it with DontDestroyOnLoad. So it will be destroyed on scene change. It only calls DontDestroyOnLoad when there is no instance yet and it creates one on the fly.
Next is the locking is pointless. You can't use a $$anonymous$$onoBehaviour from other threads anyways. If the getter is called from another thread, FindObjectOfType will throw an exception when used from another thread. You also can't create a gameibject from another thread. So the whole locking is pointless for $$anonymous$$onoBehaviour singletons. I've posted a singleton implementation several times here on UA. Here's one of them.
Also when you want to use the singleton from editor code and you don't want to have the instance saved to the scene, set the DontSave flag in the objects hideflags.
I guess it could have been ExecuteInEdit$$anonymous$$ode. It's certainly not something I did intentionally but maybe one of the plugins I'm using caused this to happen. Thanks for the detailed response - I'll give your singleton a go.
Your answer
Follow this Question
Related Questions
Access variable in another object 1 Answer
project wide variables and constants 2 Answers
Static variables and Design Fundamentals (singleton) 1 Answer
Global variables questions 5 Answers