[Unity] プロパティをインスペクタから編集できるようにする
UnityのC#スクリプトにて、シリアライズ可能なフィールドはインスペクタから編集することができますが、プロパティはpublicにしても[SerializeField]属性を指定しても編集できません。
プロパティはフィールドとは違い、内部的にはメソッドとして扱われるためです。
メソッドはシリアライズできないため、プロパティも必然的にシリアライズできないことになります。
しかし、擬似的にプロパティをインスペクタから編集可能にする手段は存在します。
実装方針
今回は任意のタイミングでプロパティの値を編集可能にする方針で実装したいと思います。
エディタ拡張を用いれば値を編集するGUIを自由に配置できます。
プロパティに対して値表示や値指定を行うGUIを独自に配置すれば、本題の目的は実現できます。
プロパティを持ったEnemyクラスを例に具体的なスクリプトを記します。
Enemy.cs
using UnityEngine; using System.Collections; public class Enemy : MonoBehaviour { // バッキングフィールド private int speed; private string name; // プロパティ public int Speed { get { print("get Speed called."); return speed; } set { print("set Speed called."); speed = value; } } public string Name { get { print("get Name called."); return name; } set { print("set Name called."); name = value; } } }
EnemyEditor.cs
using UnityEditor; [CustomEditor(typeof(Enemy))] public class EnemyEditor : Editor { public override void OnInspectorGUI() { serializedObject.Update(); // 対象となるオブジェクト var enemy = target as Enemy; // プロパティ用のGUI追加 enemy.Speed = EditorGUILayout.IntField("Speed", enemy.Speed); enemy.Name = EditorGUILayout.TextField("Name", enemy.Name); serializedObject.ApplyModifiedProperties(); } }
EnemyクラスにはSpeed、Nameの2つのプロパティがpublicで定義されていますが、インスペクタには表示されません。
そこで、Enemyクラス用のエディタ拡張クラスEnemyEditorクラスを定義し、次に示す部分にて動的にGUIを配置しています。
EnemyEditor.cs
// プロパティ用のGUI追加 enemy.Speed = EditorGUILayout.IntField("Speed", enemy.Speed); enemy.Name = EditorGUILayout.TextField("Name", enemy.Name);
プロパティの型に対応したGUI配置メソッドを呼び出す必要があります。
Speedはint型なのでEditorGUILayout.IntField()、Nameはstring型なのでEditorGUILayout.TextField()で呼び出しています。
これで以下のように編集できるようになりました。
最後に
今回の方法を用いれば、多少手間ではありますがプロパティとGUIを連動させることができます。
しかし、ゲームを実行・停止するごとに値がリセットされてしまう、ひとつのプロパティの値を編集(set)するたびに他の編集可能なプロパティのsetが呼び出されるなど、問題点も存在します。
これらの問題を解決する方法は今のところ思いつきません・・・
より良い方法がありましたら改めてご紹介させていただきます。