エディター拡張について
めちゃくちゃ参考になるスライド。
インスペクター拡張についてです。内容は初歩的なことです。 とりあえず、インスペクター拡張を試した基本的なサンプルを。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class InspectorExtension : MonoBehaviour { public int testInt; [SerializeField] private string testString; [SerializeField] private int[] testIntList = new int[] { 0, 0, 0 }; public void Start() { Debug.Log(testInt); Debug.Log(testString); foreach(var value in testIntList) Debug.Log(value); } }
using System.Collections.Generic; using UnityEditor; using UnityEngine; [CustomEditor(typeof(InspectorExtension))] public class InspectorExtensionEditorScript : Editor { private InspectorExtension targetScript; private SerializedProperty testString; private SerializedProperty intList; private int[] intListCache = new int[] { 0, 0, 0 }; private void OnEnable() { targetScript = target as InspectorExtension; testString = serializedObject.FindProperty("testString"); intList = serializedObject.FindProperty("testIntList"); //シリアル化されているデータで初期化する for(int i = 0; i < intList.arraySize; ++i) intListCache[i] = intList.GetArrayElementAtIndex(i).intValue; } public override void OnInspectorGUI() { //publicなフィールドにはtargetプロパティを用いてアクセスすればいい GUILayout.BeginHorizontal(); GUILayout.Label("Int"); targetScript.testInt = (int)GUILayout.HorizontalSlider(targetScript.testInt, 0, 100); GUILayout.Box(targetScript.testInt.ToString()); GUILayout.EndHorizontal(); //privateなシリアル化可能メンバにアクセスするにはserializedObjectを使う EditorGUILayout.BeginHorizontal(); GUILayout.Label("String"); testString.stringValue = GUILayout.TextField(testString.stringValue); EditorGUILayout.EndHorizontal(); //配列(リスト)のサイズを固定し、インスペクターで要素のみ変更可能にしてみる GUILayout.Label("IntList"); GUILayout.BeginHorizontal(); for(int i = 0; i < 3; ++i) { intListCache[i] = (int)GUILayout.HorizontalSlider(intListCache[i], 0, 100); GUILayout.Label(string.Format("[{0}]:{1}", i, intListCache[i])); } GUILayout.EndHorizontal(); for(int i = 0; i < intList.arraySize; ++i) { var intvalue = intList.GetArrayElementAtIndex(i); intvalue.intValue = intListCache[i]; } //serializedObjectの変更を適用する serializedObject.ApplyModifiedProperties(); } }
このインスペクター拡張では、シリアル化可能なpublic/privateフィールドを操作しています。 また、インスペクターで操作できる配列のサイズを固定にしています。 publicなフィールドを弄る場合はtargetを必要な型にキャストして使えばいいのですが、privateフィールドの場合そのままではアクセスできません。こういう場合はserializedObjectを使ってアクセスします。
この実装の問題は、メンバへのアクセスがちょっと面倒なことです。アクセスが面倒な理由は簡単で、拡張するコンポーネントと別ファイルでインスペクター拡張スクリプトを記述しているからです。プリプロセッサでUnityエディタ上でのみ定義されるクラスとしてインスペクター拡張を定義すればいい感じになります。
とりあえず
- インスペクター拡張は、拡張したいコンポーネントに直に定義する(プリプロセッサでビルド時に含まれないようにする)とメンバへのアクセスが楽
- カスタムウィンドウ等はEditorフォルダ以下に配置しておけばビルドターゲットに含まれないのであまり気にしなくていい
って感じでしょうか。