Skip to content

Instantly share code, notes, and snippets.

@codeimpossible
Created August 28, 2021 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeimpossible/06dea8032b54165df539789906fefac0 to your computer and use it in GitHub Desktop.
Save codeimpossible/06dea8032b54165df539789906fefac0 to your computer and use it in GitHub Desktop.
My own implementation of the Singleton pattern for Unity GameObjects
using System;
using UnityEngine;
namespace Noirlib {
/// <summary>
/// Inherit from this base class to create a singleton.
/// e.g. public class MyClassName : NoirSingleton<MyClassName> {}
/// </summary>
public class NoirSingleton<T> : MonoBehaviour where T : MonoBehaviour {
// Check to see if we're about to be destroyed.
private static bool _shuttingDown = false;
private static object _lock = new object();
private static T _instance;
private bool _started = false;
public static bool IsAssigned() => _instance != null;
/// <summary>
/// Access singleton instance through this propriety.
/// </summary>
public static T Instance {
get {
if (_shuttingDown) {
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
"' already destroyed. Returning null.");
return null;
}
if (_instance == null) {
lock (_lock) {
// Search for existing instance.
_instance = (T)FindObjectOfType(typeof(T), includeInactive: true);
// Create new instance if one doesn't already exist.
if (_instance == null) {
// Need to create a new GameObject to attach the singleton to.
var singletonObject = new GameObject();
_instance = singletonObject.AddComponent<T>();
singletonObject.name = typeof(T).ToString() + " (Singleton)";
DontDestroyOnLoad(singletonObject);
}
}
}
return _instance;
}
}
private void Awake() {
CheckInstance(SingletonAwake);
}
protected virtual void SingletonAwake() {
}
private void Start() {
// Make instance persistent.
_started = true;
CheckInstance(SingletonStart);
}
protected virtual void SingletonStart() {
}
private void OnApplicationQuit() {
_shuttingDown = true;
}
private void OnDestroy() {
// only destroy if we actually received a start message
_shuttingDown = _started && true;
}
private void CheckInstance(Action callback) {
if (_instance && _instance != this) {
Destroy(this);
return;
}
callback();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment