Programming in Unity: Use Singleton Pattern
I believe at lease some of you have met this situation (or similar) while developing your own games in Unity: There is a GameManager.cs
script attached to a gameObject
(probably named as "GameManager" as well):
public class GameManager : MonoBehaviour {
private const float StartingTime = 60f;
private int _time;
...
// some other variables and methods
...
public void RoundRestart() {
_time = StartingTime;
ResetSpawnPoint();
}
}
And you need to get it in an another script (Player.cs
, for example):
public class Player : MonoBehaviour {
private float _health = 100f;
...
// some other variables and methods
...
private void Update() {
if (health <= 0f) {
// RoundRestart() <- NEED TO CALL THIS METHOD IN GameManager
}
}
}
How to do that? Some of you might tried to create an GameManager
variable in the Player.cs
, find the GameManager
and assign to it:
GameManager _gm = GameObject.FindGameObjectWithTag("GameManager").GetComponent<GameManager>();
_gm.RoundRestart();
or some lazy bastards will create a serialized field and drag the object to the slot in Unity Editor:
public class Player : MonoBehaviour {
[SerializedField] GameManager _gm;
...
private void Update() {
if (health <= 0f) {
_gm.RoundRestart();
}
}
}
Seems like it solves the problem, nice. Now we have another problem: what if there are some other scripts (more than 10) also need the GameManager
script?
We can just copy the code we wrote for Player.cs
, then we created multiple references to GameManager
, which causes a lot of redunancy. To solve this problem without copy and paste the code around, we can use a design pattern: Singleton:
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton. (from Wikipedia - Singleton Pattern)
To make the GameManager
singleton is simple:
public class GameManager : MonoBehaviour {
private static GameManager Instance; // **<- reference link to GameManager
...
private void Awake() {
if (Instance == null) {
Instance = this;
}
else {
Destroy(gameObject);
}
}
...
}
That's it! The piece of code above creates a static reference of GameManager
instance (which is itself) and delete any duplicate instances. With this, getting a reference of your GameManager
is much easier, for example, to access a public
function in your GameManager
, instead of doing:
GameManager manager;
...
mamager.SomeFunction();
you can directly access it using:
GameManager.Instance.SomeFunction();
A note of using Singleton Pattern: DO NOT abuse singleton pattern! It is a pattern which usually been used for global configurations and sometimes it is considered as a "anti-pattern" (since it is basically a global variable but nicely written), such as GameManager
in our case. Only use singleton if you are sure your game has and only has exactly One instance of this object. For example, you should not use singleton pattern on Enemy
, or PickupItem
since those objects are very likely to have more than one.