シリアライズされていないオブジェクトの中身は Debug モードの Inspector でも表示できないため
表示させるためにはそれ専用のなにかが必要になる
しかしながら、必要なオブジェクトごとにそれを作るのが面倒になるので、リフレクションを用いて
オブジェクトを解析してパラメータを表示できるクラスを作成した
※長くなるので、コードは最後に記述する
サンプル
先程のクラスを利用して TestClass の中身を表示させてみる
private Test TestClass = new Test(); public class Test { private int _intValue; private string _stringValue = ""; private bool _boolValue; private float _floatValue; private int? _nullableIntValue = 10; private TestSub _sub = new TestSub(); private Generic<int> _genericInt = new Generic<int>(); private Generic<string> _genericString = new Generic<string>(); private int[] _intArray = {0, 1, 2}; private List<int> _intList = new List<int>{0, 1, 2}; private Dictionary<string, int> _dictionary = new Dictionary<string, int> { {"a", 1}, {"b", 2}, {"c", 3}, }; private Dictionary<string, TestSub> _dictionaryClass = new Dictionary<string, TestSub> { {"a", new TestSub()}, {"b", new TestSub()}, }; } public class TestSub { private int _intValue; private string _stringValue = ""; private bool _boolValue; private float _floatValue; private Inner _inner = new Inner(); private class Inner { private int _intValue; } } private class Generic<T> { private T Value; }
このように Inspector に表示される
見てわかるように、全部のフィールドが表示されるようになり、値の変更も可能になっている
コード
using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; public class ObjectDrawer { protected virtual BindingFlags Flags => BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; /// <summary> /// オブジェクトから生成 /// </summary> public void Draw(object obj, string label = "") { if (obj == null) { EditorGUILayout.LabelField("Object is null"); return; } var type = obj.GetType(); if (!type.IsClass) { Debug.Log("require class"); return; } if (string.IsNullOrEmpty(label)) { label = type.Name; } DrawClass(label, type, obj); } protected virtual object DrawClass(string fieldName, Type type, object value) { var foldout = DrawFoldOut(fieldName, fieldName); if (foldout) { using (new EditorGUI.IndentLevelScope()) { if (value == null) { EditorGUILayout.LabelField("Null"); } else { var fields = type.GetFields(Flags); using (new EditorGUILayout.VerticalScope()) { foreach (var field in fields) { DrawField(field, value); } } } } } return value; } protected virtual void DrawField(FieldInfo field, object obj) { if (IsSkipDrawField(field.FieldType)) { return; } var value = field.GetValue(obj); var v2 = DrawValue(field.Name, field.FieldType, value); if (v2 != value) { field.SetValue(obj, v2); } } /// <summary> /// Fieldの描画を無視するかどうか /// </summary> protected virtual bool IsSkipDrawField(Type type) { return false; } private object DrawValue(string fieldName, Type type, object value) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { value = DrawNullable(fieldName, type, value); } else if (value == null) { EditorGUILayout.LabelField(fieldName, "null"); } else if (IsDrawOverride(type, value)) { value = DrawOverride(fieldName, type, value); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { value = DrawList(fieldName, type.GetGenericArguments()[0], (IList) value); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { value = DrawDictionary(fieldName, type, (IDictionary) value); } else if (type.IsArray) { value = DrawArray(fieldName, type.GetElementType(), (Array) value); } else if (type.IsEnum) { value = DrawEnum(fieldName, type, (Enum) value); } else if (type == typeof(bool)) { value = DrawBool(fieldName, (bool) value); } else if (type == typeof(int)) { value = DrawInt(fieldName, (int) value); } else if (type == typeof(uint)) { value = DrawUint(fieldName, (uint) value); } else if (type == typeof(float)) { value = DrawFloat(fieldName, (float)value); } else if (type == typeof(string)) { value = DrawString(fieldName, (string) value); } else if (type == typeof(Vector2)) { value = DrawVector2(fieldName, (Vector2) value); } else if (type == typeof(Vector2Int)) { value = DrawVector2Int(fieldName, (Vector2Int) value); } else if (type == typeof(Vector3)) { value = DrawVector3(fieldName, (Vector3) value); } else if (type == typeof(Vector3Int)) { value = DrawVector3Int(fieldName, (Vector3Int) value); } else if (type == typeof(Vector4)) { value = DrawVector4(fieldName, (Vector4) value); } else if (type == typeof(Color)) { value = DrawColor(fieldName, (Color) value); } else if (type == typeof(AnimationCurve)) { value = DrawAnimationCurve(fieldName, (AnimationCurve) value); } else if (type == typeof(Gradient)) { value = DrawGradient(fieldName, (Gradient) value); } // stringとかクラスが色々あるので最後にクラスチェック else if (type.IsClass) { value = DrawClass(fieldName, type, value); } else { EditorGUILayout.LabelField(fieldName, "invalid Type: " + type.Name); } return value; } protected virtual object DrawNullable(string fieldName, Type type, object value) { var baseType = Nullable.GetUnderlyingType(type); var hasValue = value != null; if (hasValue) { return DrawValue(fieldName + "?", baseType, value); } EditorGUILayout.LabelField(fieldName, "null"); return value; } /// <summary> /// 描画処理の上書きするかどうか /// </summary> protected virtual bool IsDrawOverride(Type type, object value) { return false; } /// <summary> /// 描画処理の上書きするかどうか /// </summary> protected virtual object DrawOverride(string fieldName, Type type, object value) { return value; } protected virtual Array DrawArray(string fieldName, Type type, Array value) { var foldout = DrawFoldOut(fieldName, fieldName + "[" + value.Length + "]"); if (foldout) { using (new EditorGUI.IndentLevelScope()) { using (new EditorGUILayout.VerticalScope()) { for (var i = 0; i < value.Length; i++) { var v = value.GetValue(i); var v2 = DrawValue(i.ToString(), type, v); if (v2 != v) { value.SetValue(v2, i); } } } } } return value; } protected virtual IList DrawList(string fieldName, Type type, IList value) { var foldout = DrawFoldOut(fieldName, fieldName + "[" + value.Count + "]"); if (foldout) { using (new EditorGUI.IndentLevelScope()) { using (new EditorGUILayout.VerticalScope()) { for (var i = 0; i < value.Count; i++) { var v = value[i]; value[i] = DrawValue(i.ToString(), type, v); } } } } return value; } protected virtual IDictionary DrawDictionary(string fieldName, Type type, IDictionary value) { var foldout = DrawFoldOut(fieldName, fieldName + "[" + value.Count + "]"); if (foldout) { var valueType = type.GetGenericArguments()[1]; using (new EditorGUI.IndentLevelScope()) { var keys = new object[value.Keys.Count]; value.Keys.CopyTo(keys, 0); for (var i = 0; i < keys.Length; i++) { var key = keys[i]; using (new EditorGUILayout.HorizontalScope()) { var v = DrawValue(key.ToString(), valueType, value[key]); if (!v.Equals(value[key])) { value[key] = v; } } } } } return value; } protected virtual Enum DrawEnum(string fieldName, Type type, Enum value) { return EditorGUILayout.EnumPopup(fieldName, value); } protected virtual bool DrawBool(string fieldName, bool value) { return EditorGUILayout.Toggle(fieldName, value); } protected virtual int DrawInt(string fieldName, int value) { return EditorGUILayout.IntField(fieldName, value); } protected virtual object DrawUint(string fieldName, uint value) { return EditorGUILayout.FloatField(fieldName, value); } protected virtual float DrawFloat(string fieldName, float value) { return EditorGUILayout.FloatField(fieldName, value); } protected virtual string DrawString(string fieldName, string value) { return EditorGUILayout.TextField(fieldName, value); } protected virtual Vector2 DrawVector2(string fieldName, Vector2 value) { return EditorGUILayout.Vector2Field(fieldName, value); } protected virtual Vector2Int DrawVector2Int(string fieldName, Vector2Int value) { return EditorGUILayout.Vector2IntField(fieldName, value); } protected virtual Vector3 DrawVector3(string fieldName, Vector3 value) { return EditorGUILayout.Vector3Field(fieldName, value); } protected virtual Vector3Int DrawVector3Int(string fieldName, Vector3Int value) { return EditorGUILayout.Vector3IntField(fieldName, value); } protected virtual Vector3 DrawVector4(string fieldName, Vector4 value) { return EditorGUILayout.Vector4Field(fieldName, value); } protected virtual Color DrawColor(string fieldName, Color value) { return EditorGUILayout.ColorField(fieldName, value); } protected virtual AnimationCurve DrawAnimationCurve(string fieldName, AnimationCurve value) { return EditorGUILayout.CurveField(fieldName, value); } protected virtual Gradient DrawGradient(string fieldName, Gradient value) { return EditorGUILayout.GradientField(fieldName, value); } private bool DrawFoldOut(string key, string label) { var foldout = EditorPrefs.GetBool(key, false); var f = EditorGUILayout.Foldout(foldout, label); if (f != foldout) { EditorPrefs.SetBool(key, f); } return f; } }