Created
January 14, 2020 09:58
-
-
Save ronrejwan/7a4f0037effec3c9e8943542cf9cfbc9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region Using | |
using System.Linq; | |
using Assets.Scripts.Utils; | |
using UnityEngine; | |
using UnityEngine.SceneManagement; | |
#endregion | |
/// <summary> | |
/// Mono singleton Class. Extend this class to make singleton component. | |
/// Example: | |
/// <code> | |
/// public class Foo : MonoSingleton<Foo> | |
/// </code> | |
/// . To get the instance of Foo class, use <code>Foo.instance</code> | |
/// Override <code>Init()</code> method instead of using <code>Awake()</code> | |
/// from this class. | |
/// </summary> | |
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> | |
{ | |
private static T _instance; | |
[SerializeField] private bool _deactivateOnLoad; | |
[SerializeField] private bool _dontDestroyOnLoad; | |
private bool _isInitialized; | |
public static T instance | |
{ | |
get | |
{ | |
// Instance required for the first time, we look for it | |
if (_instance == null) | |
{ | |
var instances = Resources.FindObjectsOfTypeAll<T>(); | |
if (instances == null || instances.Length == 0) | |
{ | |
return null; | |
} | |
_instance = instances.FirstOrDefault(i => i.gameObject.scene.buildIndex != -1); | |
_instance?.Init(); | |
} | |
return _instance; | |
} | |
} | |
// If no other monobehaviour request the instance in an awake function | |
// executing before this one, no need to search the object. | |
protected virtual void Awake() | |
{ | |
if (_instance == null || !_instance || !_instance.gameObject) | |
{ | |
_instance = (T)this; | |
} | |
else if (_instance != this) | |
{ | |
Debug.LogError($"Another instance of {GetType()} already exist! Destroying self..."); | |
Destroy(this); | |
return; | |
} | |
_instance.Init(); | |
} | |
/// <summary> | |
/// This function is called when the instance is used the first time | |
/// Put all the initializations you need here, as you would do in Awake | |
/// </summary> | |
public void Init() | |
{ | |
if (_isInitialized) | |
{ | |
return; | |
} | |
if (_dontDestroyOnLoad) | |
{ | |
DontDestroyOnLoad(gameObject); | |
} | |
if (_deactivateOnLoad) | |
{ | |
gameObject.SetActive(false); | |
} | |
if (gameObject.IsNullOrDestroyed()) | |
{ | |
return; | |
} | |
SceneManager.activeSceneChanged += SceneManagerOnActiveSceneChanged; | |
InternalInit(); | |
_isInitialized = true; | |
} | |
private void SceneManagerOnActiveSceneChanged(Scene arg0, Scene scene) | |
{ | |
// Sanity | |
if (!instance || !gameObject || gameObject == null) | |
{ | |
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged; | |
_instance = null; | |
return; | |
} | |
// On scene change, do not nullify instance on the following conditions: | |
// 1) Singleton is marked "don't destroy on load" | |
if (_dontDestroyOnLoad) | |
{ | |
return; | |
} | |
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged; | |
_instance = null; | |
} | |
protected override void OnDisabled() | |
{ | |
} | |
protected override void OnEnabled() | |
{ | |
} | |
protected abstract void InternalInit(); | |
/// Make sure the instance isn't referenced anymore when the user quit, just in case. | |
private void OnApplicationQuit() | |
{ | |
_instance = null; | |
} | |
protected override void OnDestroyed() | |
{ | |
// Clear static listener OnDestroy | |
SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged; | |
StopAllCoroutines(); | |
InternalOnDestroy(); | |
if (_instance != this) | |
{ | |
return; | |
} | |
_instance = null; | |
_isInitialized = false; | |
} | |
protected abstract void InternalOnDestroy(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment