LoginSignup
2
0

More than 3 years have passed since last update.

UnityEditor拡張 フィールドとして保持しているカスタムクラス内のprivateフィールドへのアクセスについて : 備忘録

Last updated at Posted at 2019-08-15

経緯

Unityのエディタ拡張でいろいろ便利な機能を作ろうとしたりした時、コンポーネントのフィールド中にカスタムクラスがあったとする、そのカスタムクラス内のprivateなメンバに対してInspectorから操作をしたいときのメモ
以下のスクリプト例 Sampleクラスのhogeフィールドへのアクセスをそのまま行おうとしてもprivateなメンバな為直接は操作できない

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif



namespace Sample
{
    /// <summary>
    /// サンプルクラス.
    /// </summary>
    public class Sample : MonoBehaviour
    {
        /// <summary>
        /// 何かしらのデータクラス.
        /// </summary>
        [System.Serializable]
        public class HogeParam
        {
            [SerializeField] int id;
            public int Id => id;

            public HogeParam(
                int argId)
            {
                id = argId;
            }
        }


        [SerializeField] string characterName;
        [SerializeField] HogeParam hoge;


#if UNITY_EDITOR
        [CustomEditor(typeof(Sample))]
        class SampleEditor : Editor
        {
            public override void OnInspectorGUI()
            {
                var component = target as Sample;

                EditorGUILayout.LabelField("エディタ拡張だべ");

                component.characterName = EditorGUILayout.TextField("キャラ名", component.characterName);

                 // privateなメンバなためアクセスできない,プロパティもゲッターのみなので値のセットはできない.
                //component.hoge.Id = EditorGUILayout.IntField("ID", component.hoge.Id);

            }
        }
#endif
    }
}

RTAプレイヤー的最速解決方法

最も手っ取り早く解決するのはそもそものHogeParamクラスのメンバフィールドをpublicにしてしまうかpublicプロパティを使って外部からアクセスできるようにする方法


using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif



namespace Sample
{
    /// <summary>
    /// サンプルクラス.
    /// </summary>
    public class Sample : MonoBehaviour
    {
        /// <summary>
        /// 何かしらのデータクラス.
        /// </summary>
        [System.Serializable]
        public class HogeParam
        {
            [SerializeField] int id;
            public int Id
            {
                get { return id; }
                set { id = value; }
            }

            public HogeParam(
                int argId)
            {
                id = argId;
            }
        }

        [SerializeField] string characterName;
        [SerializeField] HogeParam hoge;


#if UNITY_EDITOR
        [CustomEditor(typeof(Sample))]
        class SampleEditor : Editor
        {
            public override void OnInspectorGUI()
            {
                var component = target as Sample;

                EditorGUILayout.LabelField("エディタ拡張だべ");
                component.characterName = EditorGUILayout.TextField("キャラ名", component.characterName);
                component.hoge.Id = EditorGUILayout.IntField("ID", component.hoge.Id);
            }
        }
#endif
    }
}

publicなフィールドを持ちたくないマン的解決方法

人によってはフィールドをpublicにするなんてとんでもない! プロパティで自由に外部から操作できないパラメータも作りたい!けどInspector拡張からは操作できるようにしたいって人もいると思われるのでその場合はC#のReflrectionを利用すると解決できる

using UnityEngine;

 #if UNITY_EDITOR
 using System.Reflection;
 using UnityEditor;
 #endif



 namespace Sample
 {
     /// <summary>
     /// サンプルクラス.
     /// </summary>
     public class Sample : MonoBehaviour
     {
         /// <summary>
         /// 何かしらのデータクラス.
         /// </summary>
         [System.Serializable]
         public class HogeParam
         {
             [SerializeField] int id;

             public HogeParam(
                 int argId)
             {
                 id = argId;
             }
         }


         [SerializeField] string characterName;
         [SerializeField] HogeParam hoge;


 #if UNITY_EDITOR
         [CustomEditor(typeof(Sample))]
         class Class1Editor : Editor
         {
             public override void OnInspectorGUI()
             {
                 var component = target as Sample;

                 EditorGUILayout.LabelField("エディタ拡張だべ");

                 component.characterName = EditorGUILayout.TextField("キャラ名", component.characterName);

                 EditorGUILayout.LabelField("Hoge");
                 EditorGUI.indentLevel++;
                 // Reflectionを利用してパラメータを操作.
                 {
                     System.Type fieldType = component.hoge.GetType();
                     FieldInfo fieldInfo = fieldType.GetField("id", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
                     int tempId = (int)fieldInfo.GetValue(component.hoge);
                     fieldInfo.SetValue(component.hoge, (int)EditorGUILayout.IntField("ID", tempId));
                }
                EditorGUI.indentLevel--;
             }
         }
 #endif
     }
 }

image.png

無事Inspectorからカスタムクラス内部のprivateなメンバへのアクセスができた

あとがき

Reflectionは便利だが乱用するとソースの可読性とかそもそものアクセス制限が意味をなさなくなるのでゲームロジック本編での利用や濫用はやめたほうがいいと個人的に思ってる
その辺はプロジェクトの方針等との相談

僕としてはエディタ拡張のみOKかなぁと思ってる

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0