Unityで実装する際、結構な頻度でManager
クラスが必要だったりするので簡単なSingleton
クラスを作成しました。
一言にSingleton
クラスといっても、Attribute
の設定やら初期設定やら色々有るとは思いますが、今回自分が作成したのは以下の3パターンのみです。
今回実装したSingletonクラス一覧
- 全てのクラスで継承可能な
Singleton
クラス。- インスタンス生成時は必ず引数なしのコンストラクタが呼び出されます。
- 引数ありのコンストラクタが使いたい場合は別途Initialize関数でも作ってください。
- 全ての
MonoBehaviour
を継承したいクラスで継承可能なMonoSingleton
クラス。Scene
上で同じクラスを保持しているオブジェクトがあるかを確認し、ない場合はインスタンス生成します。- インスタンス生成が必要な際は、まず空の
GameObject
を作成し、AddComponent
で自身を追加します。 - つまりこちらも引数なしのコンストラクタが呼び出されます。
- 引数ありのコンスタクタを使いたい場合は(ry
- Scene遷移時に削除されないようにした
MonoSingleton
を継承したクラス、PersistentMonoSingleton
.MonoSingleton
を継承し、Scene
遷移時に削除されないようにしただけ。Scene
に依存するのか、生存し続けるのかわからなくなりそうだったのでクラス分けしただけです。
サンプルコード
今回のサンプルはかなりシンプル。
ただUpdate
関数内でひたすらInstance
取得を行うだけ。
また、各Singleton
クラスでは生成時にログ吐く用に設定してあります。
using System.Collections;using System.Collections.Generic;using UnityEngine;/// <summary>/// Singleton manager sample./// </summary>public class SingletonManager : MonoBehaviour{/// <summary>/// Update this instance./// </summary>private void Update(){// Get instance of singleton every frame to check.SampleSingleton singleton = SampleSingleton.Instance;SampleMonoSingleton monoSingleton = SampleMonoSingleton.Instance;SamplePersistentMonoSingleton persistentMonoSingleton = SamplePersistentMonoSingleton.Instance;if(singleton == null){Debug.LogError("SampleSingleton is null.");}if(monoSingleton == null){Debug.LogError("SampleMonoSingleton is null.");}if(persistentMonoSingleton == null){Debug.LogError("SamplePersistentMonoSingleton is null.");}}}
using System.Collections;using System.Collections.Generic;using UnityEngine;using TC;public class SampleSingleton : Singleton<SampleSingleton>{public SampleSingleton(){Debug.Log("Constructor called for " + GetType().FullName);}}
using System.Collections;using System.Collections.Generic;using UnityEngine;using TC;public class SampleMonoSingleton : MonoSingleton<SampleMonoSingleton>{public SampleMonoSingleton(){Debug.Log("Constructor called for " + GetType().FullName);}}
using System.Collections;using System.Collections.Generic;using UnityEngine;using TC;public class SamplePersistentMonoSingleton : PersistentMonoSingleton<SamplePersistentMonoSingleton>{public SamplePersistentMonoSingleton(){Debug.Log("Constructor called for " + GetType().FullName);}}
実装サンプル
実際のソースコード
using System.Collections;using System.Collections.Generic;using UnityEngine;namespace TC{/// <summary>/// Singleton class for all non MonoBehaviour class./// </summary>public abstract class Singleton<T> where T : new(){private static T instance;public static T Instance{get{if(instance == null){instance = new T();}return instance;}}/// <summary>/// Creates new instance if need./// </summary>/// <returns><c>true</c>, if instance is successfully loaded or created, <c>false</c> otherwise.</returns>public static bool CreateIfNeed(){if(instance != null){return false;}// Create instance by calling Getter.return Instance != null;}}/// <summary>/// Singleton class for all Monobehaviour class./// </summary>public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour{// Callback on when Instance is requested.protected static System.Action onRequestInstance = null;// Callback on when Instance is newly created.protected static System.Action onCreateInstance = null;// Callback on when Instance is found from scene and set to Instance.protected static System.Action onUpdateInstance = null;private static T instance;public static T Instance{get{if(instance == null){T[] validInstances = GameObject.FindObjectsOfType<T>();if(validInstances == null || validInstances.Length <= 0){// Create new instance.GameObject gameObject = new GameObject();// At this moment, instance settings will not be applied.// Each settings such as name will be updated on Awake.instance = gameObject.AddComponent<T>();if(onCreateInstance != null){onCreateInstance();}}else{// Load instance from scene.instance = validInstances[0];if(validInstances.Length > 1){Debug.Log("More than 1 instance is created. Destroying duplicate instances.");for(int i = 1; i < validInstances.Length; i++){Destroy(validInstances[i].gameObject);}}if(onUpdateInstance != null){onUpdateInstance();}}}if(onRequestInstance != null){onRequestInstance();}return instance;}}/// <summary>/// Creates new instance if need./// </summary>/// <returns><c>true</c>, if instance is successfully loaded or created, <c>false</c> otherwise.</returns>public static bool CreateIfNeed(){if(instance != null){return false;}// Create instance by calling Getter.return Instance != null;}/// <summary>/// Awake this instance./// </summary>protected virtual void Awake(){InitializeInstance();}/// <summary>/// Initializes the instance./// </summary>protected virtual void InitializeInstance(){gameObject.name = this.GetType().FullName;}}/// <summary>/// Persistent singleton./// This class will not be destroyed on load./// </summary>public abstract class PersistentMonoSingleton<T> : MonoSingleton<T> where T : MonoBehaviour{/// <summary>/// Awake this instance./// </summary>protected override void Awake(){base.Awake();GameObject.DontDestroyOnLoad(Instance);}}}
実際のソースコードはこちらにUPしてあります。
https://github.com/table-cloth/tc-common/blob/develop/Assets/Scripts/Singleton.cs
0 件のコメント:
コメントを投稿