GetCSharpComponentを作ってみた感想

設計

Unity Advent Calendar 2019 3日目の記事です

経緯

キャラクターgameobjectにコンポーネントがいっぱいつくのが嫌になってきました。

  • Inspectorが埋まり、パラメータ編集したいコンポーネントを探すのがしんどい
  • GetComponentで取得でき実質public
  • MonoBehaviour継承すると知りたくもない関数がいっぱい継承され無駄
  • VisualStudio intellisenseに使わない関数わらわら出てきてうっとうしい

そもそもpureC#で済むならそっちでいいですよね。

そう思ってCharacterControllerみたいな神様にいっぱいメンバ変数という形でpureC#インスタンス持たせてました。しかし当然ながらキャラクターの外からアクセスしたいこともあります。

  • CharacterControllerにpublicプロパティ

だんだん不格好になってきました…CharacterController縛りも扱いにくいです。VechicleControllerだったらどうするんだ

pureC#インスタンスの入れ物としての役割+publicでアクセス許したい

そうだGetCSharpComponent関数作ろう

作ってみました

public class CSharpComponentContainer : MonoBehaviour
    {
        private readonly Dictionary<System.Type, object> _dic = new Dictionary<System.Type, object>();

        public void AddCSharpComponent<T>(T c)
        {
            var key = typeof(T);
            if (_dic.ContainsKey(key))
            {
                Debug.LogError($"すでに持ってる={key} name={name}");
            }
            else
            {
                _dic.Add(key, c);
            }
        }
        public T GetCSharpComponent<T>()
        {
            var key = typeof(T);
            if( _dic.ContainsKey(key))
            {
                return (T)_dic[key];
            }
            else
            {
                Debug.LogError($"ない={key} name={name}");
                return default(T);
            }
        }
        private void OnDestroy()
        {
            _dic.Clear();
        }
    }

わりと使い勝手いいです。AddCSharpComponent<Interface>とすれば実体を隠すこともできます。where T : System.IDisposableくらいは制約でつけてもいいかもしれません(OnDestroyでDipose呼び出し用

外部に公開しないクラスは相変わらずCharacterControllerが持ってます。

キャラクターとはメッセージシステム的なものでやり取りしては?

キャラクター自体、一つの境界付けられたコンテキストみたいなものなので、メッセージシステムを使うのもアリかなと思ってました

が、オフラインゲーム+個人開発でそこまで疎結合にするとコードが追いにくいデメリットの方が大きくなったので没にしました。