Hierarchyを汚さないポータブルなUnity向けSingletonの実装の話

はじめに

  • SceneのHierarchyを汚さないシングルトンなMonoBehaviour継承のクラスを実装したい時がある
  • Singletonを使うということに対する良し悪しについては言及しない

Unityで使うSingletonの悩み

  • MonoBehaviourを継承してメインスレッドのStart()とかUpdate()とか使いたいけどHierarchyにオブジェクトが出現するのは目障り
  • そもそも「使うときには適当なGameObjectにアタッチしてね」とか使いづらい(インスペクタから設定項目を触る必要のないスクリプトの場合)

よくあるSingletonの実装

  • (どこから拝借してきた実装か忘れてしまっていますすみません)
public class SingletonMonoBehaviour<T> : MonoBehaviour where T : SingletonMonoBehaviour<T>
    {
        protected static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = (T)FindObjectOfType(typeof(T));

                    if (instance == null)
                    {
                        Debug.LogWarning(typeof(T) + "is nothing");
                    }
                }

                return instance;
            }
        }

        virtual protected void Awake()
        {
            CheckInstance();
        }

        protected bool CheckInstance()
        {
            if (instance == null)
            {
                instance = (T)this;
                return true;
            }
            else if (Instance == this)
            {
                return true;
            }

            Destroy(this);
            return false;
        }
    }
  • 例えばこれを継承したクラスclass Obj:SingletonMonoBehaviour<Obj>は、Obj.Instanceという形でシングルトンなインスタンスにアクセスできる
  • 一方で、ヒエラルキにインスタンスがない場合は怒られる

keijiroさんのMidiBridgeのSingleton実装が好き


public class MidiBridge : MonoBehaviour { //<中略> static MidiBridge _instance; public static MidiBridge instance { get { if (_instance == null) { var previous = FindObjectOfType (typeof(MidiBridge)); if (previous) { Debug.LogWarning ("Initialized twice. Don't use MidiBridge in the scene hierarchy."); _instance = (MidiBridge)previous; } else { var go = new GameObject ("__MidiBridge"); _instance = go.AddComponent<MidiBridge> (); DontDestroyOnLoad (go); go.hideFlags = HideFlags.HideInHierarchy; } } return _instance; } } }
  • 取得時Hierarchyにインスタンスがない場合は自動的に作成する(Hierarchy上に表示されない
  • MonoBehaviourを継承したうえでそのクラス内でシングルトンが完結している
    • コンパクトなライブラリ作成や、シングルトンで実装したいものが一つしかないような場合はこちらがよさそう
    • インスタンス生成部分を先述のGenericsを使った親クラスと組み合わせるのもよさそう

まとめ

  • 1つのクラスだけシングルトンにしたいときや、コードのポータビリティを上げたいときにはkeijiroさんの実装がよさそう
  • インスペクタから操作する必要のないMonoBehaviourの場合はGameObjectのhideFragHideFlags.HideInHierarchyを代入して非表示にできるというのが学びでした

投稿者: hikatech

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です