PropertyDrawerなどGUILayout系が使えない環境でMonoBehaviourのインスペクタを描画する方法です。
インスペクタはGUILayout環境を前提としているので結構hackyなことをしています。意外と大変でした。
Unity2018.3.6
ソースコード
ソースコードは次の通りです。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; /// <summary> /// EditorGUI環境で特定のMonoBehaviourのInspectorのGUIを描画するためのクラス /// </summary> public class InspectorGUIDrawer { private class PropertyData { public SerializedObject so; public Dictionary<string, SerializedProperty> properties = new Dictionary<string, SerializedProperty>(); } private Dictionary<MonoBehaviour, PropertyData> _propertyDataPerObject = new Dictionary<MonoBehaviour, PropertyData>(); private PropertyData _property; private void Init(MonoBehaviour obj) { if (_propertyDataPerObject.TryGetValue(obj, out _property)){ return; } _property = new PropertyData(); var so = new SerializedObject(obj); so.Update(); _property.so = so; var iter = so.GetIterator(); iter.NextVisible(true); while(iter.NextVisible(false)) { var property = so.FindProperty(iter.propertyPath); _property.properties.Add(iter.propertyPath, property); } _propertyDataPerObject.Add(obj, _property); } /// <summary> /// Inspectorを描画する /// </summary> public void DrawInspectorGUI(Rect rect, MonoBehaviour obj) { if (obj == null) { return; } Init(obj); var so = _property.so; so.Update(); var iter = so.GetIterator(); iter.NextVisible(true); while(iter.NextVisible(false)) { var prop = _property.properties[iter.propertyPath]; EditorGUI.PropertyField(rect, prop, true); rect.y += EditorGUI.GetPropertyHeight(prop, true); rect.y += EditorGUIUtility.standardVerticalSpacing; } so.ApplyModifiedProperties(); } /// <summary> /// Inspectorの高さを取得する /// </summary> public float GetInspectorGUIHeight(MonoBehaviour obj) { if (obj == null) { return 0.0f; } Init(obj); var so = _property.so; var height = 0.0f; var iter = so.GetIterator(); iter.NextVisible(true); while(iter.NextVisible(false)) { var prop = _property.properties[iter.propertyPath]; height += EditorGUI.GetPropertyHeight(prop, true); height += EditorGUIUtility.standardVerticalSpacing; } return height; } }
使い方
このクラスをこんな感じで使います。
using UnityEngine; using UnityEditor; using System.Collections.Generic; [System.Serializable] public class Example { [SerializeField] private ExampleBehaviour _exampleBehaviour; } [CustomPropertyDrawer(typeof(Example))] public class ExampleDrawer : PropertyDrawer { private class PropertyData { public SerializedProperty exampleBehaviourProperty; } private Dictionary<string, PropertyData> _propertyDataPerPropertyPath = new Dictionary<string, PropertyData>(); private PropertyData _property; private InspectorGUIDrawer _inspectorGUIDrawer = new InspectorGUIDrawer(); private void Init(SerializedProperty property) { if (_propertyDataPerPropertyPath.TryGetValue(property.propertyPath, out _property)){ return; } _property = new PropertyData(); _property.exampleBehaviourProperty = property.FindPropertyRelative("_exampleBehaviour"); _propertyDataPerPropertyPath.Add(property.propertyPath, _property); } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { Init(property); var fieldRect = position; fieldRect.height = EditorGUIUtility.singleLineHeight; using (new EditorGUI.PropertyScope(fieldRect, label, property)) { // MonoBehaviour以外のプロパティを描画 EditorGUI.PropertyField(fieldRect, _property.exampleBehaviourProperty); fieldRect.y += EditorGUIUtility.singleLineHeight; fieldRect.y += EditorGUIUtility.standardVerticalSpacing; } // MonoBehaviourのインスペクタを描画 _inspectorGUIDrawer.DrawInspectorGUI(fieldRect, _property.exampleBehaviourProperty.objectReferenceValue as MonoBehaviour); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { Init(property); float height = 0.0f; // プロパティの高さ height += EditorGUIUtility.singleLineHeight; height += EditorGUIUtility.standardVerticalSpacing; // インスペクタの高さ height += _inspectorGUIDrawer.GetInspectorGUIHeight(_property.exampleBehaviourProperty.objectReferenceValue as MonoBehaviour); return height; } }
結果