[Unity] インスペクタから編集可能なprivateフィールドにアクセスする
Unityではシリアライズ可能なフィールドは以下のようにインスペクタから編集することが出来ます。
MonoBehaviourを継承したクラスには[Serializable]属性が指定されているため、シリアライズすることが出来ます。
シリアライズ可能なクラスでは、publicまたは[SerializeField]属性が指定されたフィールドがインスペクタ上に表示され、編集可能になります。
すなわち、[SerializeField]属性が指定されていればprivateなフィールドでも編集可能になります。
では、エディタ拡張などで[SerializeField]属性が指定されたprivateフィールドにアクセスする場合はどうすればよいでしょうか?
例えば、以下のようなEnemyクラスを実装したとします。
using UnityEngine; using System.Collections; public class Enemy : MonoBehaviour { // Inspectorから編集可能なprivateフィールド [SerializeField] private int speed; [SerializeField] private int life; [SerializeField] private int attack; }
ここでエディタ拡張するために以下のようなEnemyEditorクラスを定義します。
using UnityEditor; [CustomEditor(typeof(Enemy))] public class EnemyEditor : Editor { public override void OnInspectorGUI() { serializedObject.Update(); var enemy = (Enemy)target; // 各フィールドはprivateなのでコンパイルエラー enemy.speed = EditorGUILayout.IntSlider(enemy.speed, 0, 50); enemy.life = EditorGUILayout.IntSlider(enemy.life, 0, 100); enemy.attack = EditorGUILayout.IntSlider(enemy.attack, 0, 25); serializedObject.ApplyModifiedProperties(); } }
しかし、Enemyクラスのフィールドは皆privateであるため、外側からアクセスできません。
したがって、上記のEnemyEditorクラスはコンパイルエラーとなります。
フィールドをpublicにすればアクセス可能になりますが、エディタ拡張のためにわざわざフィールドを公開してしまうのは好ましくありません。
このようにシリアライズされたフィールドにアクセスするためには、SerializedObjectを用います。
具体的な使い方は以下の通りです。
using UnityEditor; [CustomEditor(typeof(Enemy))] public class EnemyEditor : Editor { public override void OnInspectorGUI() { serializedObject.Update(); // serializedObjectからSerializedPropertyを取得 var speed = serializedObject.FindProperty("speed"); var life = serializedObject.FindProperty("life"); var attack = serializedObject.FindProperty("attack"); // SerializedProperty経由で値にアクセスするのでコンパイルエラーとならない speed.intValue = EditorGUILayout.IntSlider(speed.intValue, 0, 50); life.intValue = EditorGUILayout.IntSlider(life.intValue, 0, 100); attack.intValue = EditorGUILayout.IntSlider(attack.intValue, 0, 25); serializedObject.ApplyModifiedProperties(); } }
これでEnemyEditorクラスからEnemyクラスのフィールドにアクセスすることが出来ます。
インスペクタを表示してみると以下のようにEnemyEditorによってスライダーにより値が編集できるようになっていることを確認できます。
エディタ拡張でシリアライズ可能なフィールドにアクセスする場合は、基本的にSerializedObjectを通じてアクセスする習慣をつけておけば問題無いかと思います。