Reputation: 53
I have a basic question that can help new unity guys to learn faster. As you know that in unity we both use singleton and instance of a class. I have realised a thing that and I want to be sure about what I am thinking. Can you help me to be sure?
I use instance in some situations like this;
If I have a scene and I want to use instance as a layer to transfer some data between scripts. I create an empty game object and assign this code it as a component;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeInstance();
}
void MakeInstance()
{
if (instance == null)
{
instance = this;
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
I use singleton in some situations like this;
If I have a scene and I want to use singleton pattern as a layer to transfer some data between all scenes. I create an empty game object and assign this code it as a component;
public class GameplayController : MonoBehaviour
{
public static GameplayController instance;
void Awake()
{
MakeSingleton();
void MakeSingleton()
{
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject);
}
else if(instance != null)
{
Destroy(gameObject);
}
}
}
So, I wanted to be sure If I am on the right way or not? It worked until now, but will be there a problem in most advanced situations in the future?
Upvotes: 1
Views: 11280
Reputation: 5108
Your code is correct, that's the basic way to create a singleton in Unity.
When you speak of Instance vs Singleton I'm getting some vibes that you may not understand the concept: The idea with Singleton is that there will only be ONE (single) instance of the object.
So you have a static property; the static modifier on a class makes it non-instansiable with the new
keyword. When you add it to a property (like you've done) it means that you can access it from anywhere, without instansiating the containing class.
GameplayController.instance
In your MakeInstance() you verify that the instance isn't already assigned to an instance, and then set it to this instance.
To further follow the Singleton pattern you probably want to make sure your object isn't destroyed when you load a new scene:
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = this;
}
There shouldn't be any problems in the future; the Singleton pattern is a bad pattern however, but it has its usefulness in prototyping; it's simple.
Issues you may experience is that your code will have dependencies to your Singleton classes which will cause errors if you've forgotten to add the class to the Scene, or if you have an earlier scene where you instansiate these classes you have to start that Scene first when debugging, etc.
Personally I use a Singleton class to extend to assure same functionality across all Singletons and less bloat in every Singleton class etc:
using UnityEngine;
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
private static object _lock = new object();
public static T Instance
{
get
{
if (applicationIsQuitting)
{
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
"' already destroyed on application quit." +
" Won't create again - returning null.");
return null;
}
lock (_lock)
{
if (_instance == null)
{
var instances = FindObjectsOfType<T>();
if (instances.Length > 1)
{
Debug.LogError("[Singleton] Something went really wrong " +
", there are too many Singletons; deleting them: ");
for (int i = 1; i < instances.Length; i++)
{
Debug.LogError("Deleting " + instances[i].gameObject.name);
Destroy(instances[i].gameObject);
}
_instance = FindObjectOfType<T>();
return _instance;
}
if (instances.Length > 0)
_instance = instances[0];
if (_instance == null)
{
GameObject singleton = new GameObject();
_instance = singleton.AddComponent<T>();
singleton.name = "[Singleton] " + typeof(T).ToString();
DontDestroyOnLoad(singleton);
Debug.Log("[Singleton] An instance of " + typeof(T) +
" is needed in the scene, so '" + singleton +
"' was created with DontDestroyOnLoad.");
}
}
return _instance;
}
}
}
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
/// <summary>
/// When Unity quits, it destroys objects in a random order.
/// In principle, a Singleton is only destroyed when application quits.
/// If any script calls Instance after it have been destroyed,
/// it will create a buggy ghost object that will stay on the Editor scene
/// even after stopping playing the Application. Really bad!
/// So, this was made to be sure we're not creating that buggy ghost object.
/// </summary>
private static bool applicationIsQuitting = false;
public void OnDestroy()
{
applicationIsQuitting = true;
}
}
Which is then used like:
public class MySingleton : Singleton<MySingleton>
{
// Don't use the Awake method, Singleton uses it to initialize
void Start() {
Debug.Log("I'm a Singleton, access me through MySingleton.Instance");
}
}
Upvotes: 2