Unity Editor の拡張機能には,ドロップダウンメニューの作成方法が複数用意されています。
このドロップダウンメニューには独自の仕様があり,特に同じ要素を2つ以上含む場合は注意が必要です。
本稿では,その仕様と対策について御説明いたします。
(Unity 2018.3.0f2)
EditorGUILayout.MaskField
今回は,こちらの関数で確認します。
文字列配列string[]
から項目を選択し,フラグを10進数int
で返します。
(もちろん,ToString()
関数によって文字列string
を取得する事も出来ます。)
using UnityEngine; // ここからエディター上でのみ有効 #if UNITY_EDITOR using UnityEditor; // エディター拡張クラス [CustomEditor(typeof(Extend))] public class ExtendedEditor : Editor {// Editor クラスを継承 // Extend クラスの変数を扱うために宣言 Extend extend; void OnEnable() {// 最初に実行 // Extend クラスに target を代入 extend = (Extend)target; } public override void OnInspectorGUI() {// Inspector に表示 // これ以降の要素に関してエディタによる変更を記録 EditorGUI.BeginChangeCheck(); // ラベルの作成 var label = "List"; // 初期値として表示する項目のインデックス番号 var selectedIndex = extend.index; // プルダウンメニューに登録する文字列配列 var displayOptions = Extend.list; // プルダウンメニューの作成 var index = Extend.list.Length > 0 ? EditorGUILayout.MaskField(label, selectedIndex, displayOptions) : 0; for (var i = 0; i < Extend.list.Length; i++) {// ビット演算で選択状態を判定 if ((index & 1 << i) != 0) {// 選択状態のインデックス番号をログ出力 Debug.Log(i); } } if (EditorGUI.EndChangeCheck()) {// 操作を Undo に登録 // Extend クラスの変更を記録 var objectToUndo = extend; // Undo メニューに表示する項目名 var name = "Extend"; // 記録準備 Undo.RecordObject(objectToUndo, name); // Undo に記録したい変数を登録 extend.index = index; } } } // ここまでエディター上でのみ有効 #endif // 同一オブジェクトへの複数追加を禁止 [DisallowMultipleComponent] public class Extend : MonoBehaviour {// エディター拡張の中身 // リスト public static readonly string[] list = { "か", "た", "た", "た", "き", "き" }; // 初期フラグは2進数で“100011” public int index = 35; }
配列の中身に御注目ください。
上記のスクリプトから生成したプルダウンメニューは,次の画像のようになります。
「かたたたきき」が「かたき」になってしまいました。
ここであえて,「き」を再選択してみます。
ログにインデックス番号を出力するよう記述していたため,index
の値に4
が追加された事が分かります。
for (var i = 0; i < extend.list.Length; i++) {// ビット演算で選択状態を判定 if ((index & 1 << i) != 0) {// 選択状態のインデックス番号をログ出力 Debug.Log(i); } }
この後は何度「き」を選んでも,5
の選択状態は解除されません。
同じように「た」を選ぶと1
が消えるため,「重複した要素はインデックス番号が最も小さい物のみ切り替わる」という事が分かります。
対策
プルダウンメニューに表示する項目名に,インデックス番号を加えます。
using UnityEngine; // LINQ の使用 using System.Linq; // ここからエディター上でのみ有効 #if UNITY_EDITOR using UnityEditor; // エディター拡張クラス [CustomEditor(typeof(Extend))] public class ExtendedEditor : Editor {// Editor クラスを継承 // Extend クラスの変数を扱うために宣言 Extend extend; void OnEnable() {// 最初に実行 // Extend クラスに target を代入 extend = (Extend)target; } public override void OnInspectorGUI() {// Inspector に表示 // これ以降の要素に関してエディタによる変更を記録 EditorGUI.BeginChangeCheck(); // ラベルの作成 var label = "List"; // 初期値として表示する項目のインデックス番号 var selectedIndex = extend.index; // ドロップダウンメニューの項目にインデックス番号を付与 System.Func<string, int, string> selector = (string name, int number) => $"{number}: \r{name}"; // プルダウンメニューに登録する文字列配列 var displayOptions = Extend.list.Select(selector).ToArray(); // プルダウンメニューの作成 var index = Extend.list.Length > 0 ? EditorGUILayout.MaskField(label, selectedIndex, displayOptions) : 0; for (var i = 0; i < Extend.list.Length; i++) {// ビット演算で選択状態を判定 if ((index & 1 << i) != 0) {// 選択状態の要素をログ出力 Debug.Log(Extend.list[i]); } } if (EditorGUI.EndChangeCheck()) {// 操作を Undo に登録 // Extend クラスの変更を記録 var objectToUndo = extend; // Undo メニューに表示する項目名 var name = "Extend"; // 記録準備 Undo.RecordObject(objectToUndo, name); // Undo に記録したい変数を登録 extend.index = index; } } } // ここまでエディター上でのみ有効 #endif // 同一オブジェクトへの複数追加を禁止 [DisallowMultipleComponent] public class Extend : MonoBehaviour {// エディター拡張の中身 // リスト public static readonly string[] list = { "か", "た", "た", "た", "き", "き" }; // 初期フラグは2進数で“100011” public int index = 35; }
今回は,LINQ のSelect
関数を使用しました。
元のリストには手を加えないため,選択した値の取得にも支障を来しません。
インデックス番号を付与した行には,文字列補間機能を使用しています。
C# のバージョンが 5 以下であれば,次のように記述してください。
// ドロップダウンメニューの項目にインデックス番号を付与 System.Func<string, int, string> selector = (string name, int number) => (number + ": \r" + name);
以上,エディター拡張の複数選択式プルダウンメニューに重複要素を表示する方法でした。
択一選択式プルダウンメニューの場合は,こちらの記事をお読みください。
重複した要素にのみ連番を振りたい場合は,こちらの記事が参考になるかもしれません。