インスペクタにboolの配列を出すとき、チェックボックスを横に並べて表示させる方法
boolの配列って普通こうなりますよね。
それを…
こうすると見やすくありませんか。これを紹介します。
以下のスクリプトをEditor>PropertyDrawerフォルダにでも入れます。
using UnityEngine; using UnityEditor; [CustomPropertyDrawer(typeof(SmartBoolArrayAttribute))] public class SmartBoolArrayDrawer : PropertyDrawer { /// <summary>インデント段階を保存</summary> private int lastIndentLevel; /// <summary>1行におく要素の数</summary> private const int ItemsInLine = 10; /// <summary>ラベルの幅</summary> private const int LabelWidth = 40; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { BeginProperty(position, property, label); int index = GetIndex(property); var targetRect = position; if (index % ItemsInLine == 0) { var labelRect = targetRect; labelRect.width = LabelWidth; labelRect.height = 18; EditorGUI.LabelField(labelRect, index.ToString()); } targetRect.y += -(index % ItemsInLine) * 2; targetRect.x += LabelWidth + index % ItemsInLine * ((position.width - LabelWidth) / ItemsInLine); targetRect.width = 18; targetRect.height = 18; EditorGUI.PropertyField(targetRect, property, new GUIContent()); EndProperty(); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return 0; } int GetIndex(SerializedProperty property) { var elem = property; var path = elem.propertyPath; var num = path.Substring(path.LastIndexOf('[') + 1); num = num.Substring(0, num.Length - 1); int index = 0; if (!int.TryParse(num, out index)) { Debug.LogWarningFormat("Failed to parse int from: {0}, originally: {1}", num, path); } return index; } /// <summary> /// プロパティの開始 /// </summary> /// <param name="position">OnGUIと同じ</param> /// <param name="property">OnGUIと同じ</param> /// <param name="label">OnGUIと同じ</param> protected void BeginProperty(Rect position, SerializedProperty property, GUIContent label) { EditorGUIUtility.labelWidth = 80 + EditorGUI.indentLevel * 20; label = EditorGUI.BeginProperty(position, label, property); this.lastIndentLevel = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; } /// <summary> /// プロパティの終了 /// </summary> protected void EndProperty() { EditorGUI.indentLevel = this.lastIndentLevel; EditorGUI.EndProperty(); } }
そして、次のようなファイル(大抵は属性をまとめたAttributes.csなど)を用意してEditorフォルダ以外の普通のスクリプトフォルダに置きます。
using UnityEngine; class SmartBoolArrayAttribute : PropertyAttribute {}
すると、
using UnityEngine; using UnityEditor; public class ExampleScript : MonoBehaviour { [SmartBoolArray] public bool[] flags; }
このようにすることで先ほどのことができます。
雑な解説
- 基本的なことは前回の1行プロパティドロアーの時と共通ですが、今回は属性にCustomPropertyDrawerを適用します。
- 属性は
[SmartBoolArrayAttirbute]
と指定してもいいですが、PropertyAttribute
を継承したクラス名がAttribute
で終わる場合、その属性を指定する側ではAttribute
は省略可能です。というか、Unity標準の[Range(0, 1)]
とかも元々は[RangeAttribute(0, 1)]
です。 - 配列に指定することを想定しているので、OnGUIに配列オブジェクトが渡ってくると思っていましたが、実際には、要素が1個ずつ(Element 0, Element 1, のように=インスペクタの1行分ずつ?)渡ってきます。
- 今回はflagsという名前の配列ですが、この場合要素0番目の
property.propertyPath
にはflags.Array.data[0]
という形式で文字列が入っているので、そこから要素番号を取得しています。(もっといい方法があればいいのですが) - 追記:↑は
property.displayName
(これも文字列で、こちらは"Element 0", "Element 1"のように格納)から取り出すこともできます。 GetPropertyHeight()
を0
でoverrideするという男気あふれる事をしていますが、これによって要素ごとに自動で位置を下げず、横に並べるということを実現しています。- しかし、
EditorGUI.PropertyField
にわたすRect
には幅高さを持たせないと、クリックしても反応しなくなってしまいます。 - 高さを0にしても若干下がるらしいので、y座標を少し上にあげています。
- 横を20個にする場合は少し工夫が必要?
GetPropertyHeight()
をマイナスにする必要があるかもしれないが…といったところで力尽きた。
素敵なbool配列ライフを!