Skip to content

Instantly share code, notes, and snippets.

@brenocogu
Last active December 20, 2022 18:38
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 brenocogu/41079ee0d093c3ad65dd67859a548e9f to your computer and use it in GitHub Desktop.
Save brenocogu/41079ee0d093c3ad65dd67859a548e9f to your computer and use it in GitHub Desktop.
[Unity3D] Generic singleton class initialization for MonoBehaviours
using UnityEngine;
using System;
using UnityEngine.SceneManagement;
/// <summary>
/// This class handles Singleton instance and managing. Just inherit from this and voyalla!
/// <para></para>
/// </summary>
/// <typeparam name="T"></typeparam>
public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
static Func<T> valueFactory = () =>
{
UnityEngine.Object[] oj = FindObjectsOfType(typeof(T), true);
T scriptType;
if (oj.Length == 0)
{
GameObject instant = new GameObject(typeof(T).ToString() + "_Static");
DontDestroyOnLoad(instant);
instant.AddComponent(typeof(T));
scriptType = instant.GetComponent<T>();
}
else
scriptType = ((MonoBehaviour)oj[0]).GetComponent<T>();
SceneManager.sceneLoaded += (scriptType as MonoSingleton<T>).CheckCopyCats;
return scriptType;
};
private static Lazy<T> lazyInstance =
new Lazy<T>(valueFactory);
public static T Instance
{
get
{
if (lazyInstance.Value == null)
lazyInstance = new Lazy<T>(valueFactory);
return lazyInstance.Value;
}
}
protected virtual void CheckCopyCats(Scene sc, LoadSceneMode mode)
{
UnityEngine.Object[] oj = FindObjectsOfType(typeof(T), true);
if (oj.Length <= 1)
return;
for (int i = oj.Length-1; i>0; i--)
{
if (Instance != ((MonoBehaviour)oj[i]).GetComponent<T>())
Destroy(((MonoBehaviour)oj[i]).gameObject);
}
}
}
@brenocogu
Copy link
Author

For Non-MonoBehaviour singletons please check this >> https://gist.github.com/brenocogu/8c06d7d710630bbbcd5a79bb932ae663

@brenocogu
Copy link
Author

[14/12/2022] Gist marked as "[PREVIEW]" due to unstable initialization with multiple singleton instance (due to the "Don't destroy on load"). This error only happens with a pre-set value for a MonoSingleton instance (i.e. a GameObject) within a scene that can be returned to at any give point in the application run-time (e.g: A MonoSingleton existent on the "Menu" Scene can be duplicated if the user returns to the menu)

@brenocogu
Copy link
Author

[20/12/2022] Gist fixed. Now MonoSingleton handles multiple instances of the same singleton. The script can now be used for both pre-set game-objects or instancing game-objects. Profiling with some stress test provided enough info to sustain that the CopyCat check method isn't a big performance killer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment