Skip to content

Instantly share code, notes, and snippets.

@sassembla
Last active July 13, 2024 12:49
Show Gist options
  • Save sassembla/2de4e864bd0918a06761356398a0d02e to your computer and use it in GitHub Desktop.
Save sassembla/2de4e864bd0918a06761356398a0d02e to your computer and use it in GitHub Desktop.
automated singleton holder for Unity. auto-initialize on Player boot time and well isolated.
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class SingletonHolder : MonoBehaviour {
private List<Base> instances = new List<Base>();
private static SingletonHolder holderInstance;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void NewSingleton () {
GameObject o = new GameObject("SingletonHolder []");
holderInstance = o.AddComponent<SingletonHolder>();
GameObject.DontDestroyOnLoad(holderInstance);
}
public static T Get<T>() where T : Base, new() {
return holderInstance.GetInstance<T>();
}
public static Base[] GetAll () {
return holderInstance.instances.ToArray();
}
private T GetInstance<T>() where T : Base, new(){
foreach (var instance in instances) {
if (instance is T) {
return (T)instance;
}
}
var t = new T();
instances.Add(t);
NameUpdate();
/*
本来のUnityのMonoBehaviour.Start はUnityがInstanceを生成したときだけ呼ばれるので、メインスレッドから呼ぶという制約があるが、
このSingletonHolderにはその制約がない。
が、その場合、この Start が呼ばれるのはサブスレッドになってしまうため、インスタンス内でエラーが出ると思う。
そうなった場合、まずサブスレッドでこのメソッドを実行するのを見直してほしい。
*/
t.Awake();
t.OnEnable();
t.Start();
return t;
}
public static bool Delete<T>() where T : Base, new() {
return holderInstance.DeleteInstance<T>();
}
private bool DeleteInstance<T>() where T : Base, new() {
foreach (var instance in holderInstance.instances) {
if (instance is T) {
instances.Remove(instance);
NameUpdate();
return true;
}
}
return false;
}
private void NameUpdate () {
// update this instance's name.
holderInstance.gameObject.name = "SingletonHolder [" + string.Join(", ", instances.Select(i => i.GetType().ToString()).ToArray()) + "]";
}
/*
handler methods.
*/
private void Start () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.Start();
}
}
private void OnGUI () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.OnGUI();
}
}
private void Update () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.Update();
}
}
private void LateUpdate () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.LateUpdate();
}
}
private void OnApplicationQuit () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.OnApplicationQuit();
}
}
private void OnDisable () {
foreach (var instance in holderInstance.instances) {
if (instance == null) continue;
instance.OnDisable();
}
}
public class Base {
public virtual void Awake () {}
public virtual void OnEnable () {}
public virtual void Start () {}
public virtual void FixedUpdate () {}
public virtual void Update () {}
public virtual void LateUpdate () {}
public virtual void OnGUI () {}
public virtual void OnApplicationPause () {}
public virtual void OnDisable () {}
public virtual void OnApplicationQuit () {}
}
}
@sassembla
Copy link
Author

・MonoBehaviourのシングルトンが欲しい場合と、それ以外とを分割
・インスタンスに対してのInspectorを提供するのはとても面白そう。値の編集も可能。

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