A Generic Singleton
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 43 of 64.
Section 3's singleton is five lines that every manager repeats: a static Instance, an Awake that sets it, the duplicate check. A generic base class writes them once. Each manager derives from it, naming itself as the type:
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this as T;
}
}
public class ScoreManager : Singleton<ScoreManager>
{
public int score;
public void Add(int points) { score += points; }
}
public class SoundManager : Singleton<SoundManager>
{
public void Play(string clip) { Debug.Log("Playing " + clip); }
}// in any script
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");A static member of a generic class belongs to each type made from it: Singleton<ScoreManager> and Singleton<SoundManager> are two types with an Instance each, so the managers never share one. ScoreManager.Instance is already typed ScoreManager, which is what T is for. Inside the base, this is only known as a Singleton<T>, so this as T hands it over as the manager it really is.
The base is abstract: Unity puts only the managers on objects. A manager that needs Awake of its own must not write a plain void Awake(). That hides the base's method (the compiler warns about it), Unity calls only the manager's, and Instance is never set. Override it and call the base first:
protected override void Awake()
{
base.Awake();
score = 0;
}Challenge
MediumGive both managers a base that survives scene loads.
- In
PersistentSingleton, writeprotected virtual void Awake(): the first becomesInstanceand stays (DontDestroyOnLoad); a later one destroys itself. WalletandMusicPlayerderive from it; delete theirInstanceand Wallet's Awake.MusicPlayeroverrides Awake:base.Awake(), then, if it is the Instance, logsNow playing: Adventure.
Press Play, visit the forest and come back: 1 coin. Then Check.
Try it yourself
using UnityEngine;
public abstract class PersistentSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
public static T Instance { get; private set; }
// Awake: keep the first one through scene loads, destroy any later one
}
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in ReachPractice on your own: Unity playground