Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】択一選択式プルダウンメニューにアイコンを設定する【エディター拡張】

Unity Editor の拡張機能には,ドロップダウンメニューの作成方法が複数用意されています。

その中には,メニューにアイコンを設定できる物があります。

本稿では,その使い方について御説明いたします。

(複数選択式プルダウンメニュー MaskField には,アイコンを設定する事は出来ません。)

(Unity 2018.3.0f2)

EditorGUILayout.Popup

配列string[]の要素を項目として,プルダウンメニューを作成する関数です。

docs.unity3d.com

まずは,完成したメニューをお見せします。

UnityEditor の Inspector ウィンドウで プルダウンメニューにアイコンが設定されている画像
メニューにアイコンが設定されている

コードは,下記のようになっております。

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;
    }

    // 仕切り
    static readonly string Divider = string.Empty;
    // 未選択状態
    static readonly string Unselected = "(Unselected)";

    public override void OnInspectorGUI()
    {// Inspector に表示
        // これ以降の要素に関してエディタによる変更を記録
        EditorGUI.BeginChangeCheck();

        // SerializedObject の内容を更新
        serializedObject.Update();
        // Inspector のコンポーネントに表示する項目名
        var text = "List";
        // ツールチップのテキスト
        var tooltip = "Popup list \"Items\" will be made out of this.";
        // ツールチップ入りラベルの作成
        var label = new GUIContent(text, tooltip);
        // 配列の中身も表示する
        var includeChildren = true;
        // リストを取得
        var property = serializedObject.FindProperty(nameof(extend.list));
        // 配列フィールドの作成
        EditorGUILayout.PropertyField(property, label, includeChildren);
        // SerializedObject の変更を適用
        serializedObject.ApplyModifiedProperties();

        // GUIContent から text を抽出してインデックス番号を付与した配列
        var textList = extend.list
            .Select((GUIContent content) => content.text)
            .Select((string name, int number) => $"{number}: \r{name}")
            .ToArray();
        // ドロップダウンの項目を作成
        var list = new GUIContent[extend.list.Length].ToList();
        for (var i = 0; i < extend.list.Length; i++)
        {   // GUIContent の代入
            list[i] = new GUIContent(textList[i], extend.list[i].image, extend.list[i].tooltip);
        }
        // リストに仕切りを追加
        list.Add(new GUIContent(Divider));
        // 未選択状態を追加
        list.Add(new GUIContent(Unselected));
        // Inspector のコンポーネントに表示する項目名
        text = "Items";
        // ツールチップのテキスト
        tooltip = "Select one item.";
        // ツールチップ入りラベルの作成
        label = new GUIContent(text, tooltip);
        // 初期値として表示する項目のインデックス番号
        var selectedIndex = (extend.list.Length == 0) ? -1
            : (extend.index < 0) ? (extend.list.Length + 1)
            : extend.index;
        // プルダウンメニューに登録する文字列配列
        var displayOptions = list.ToArray();
        // プルダウンメニューの作成
        var index = (extend.list.Length > 0) ? EditorGUILayout.Popup(label, selectedIndex, displayOptions)
            : selectedIndex;

        if (EditorGUI.EndChangeCheck())
        {// 操作を Undo に登録
            // Extend クラスの変更を記録
            var objectToUndo = extend;
            // Undo メニューに表示する項目名
            var name = "Extend";
            // 記録準備
            Undo.RecordObject(objectToUndo, name);
            // インデックス番号を登録
            extend.index = index;
        }

        // 未選択状態のインデックス番号を -1 とする
        extend.index = (index > extend.list.Length) ? -1
            : index;

        if ((extend.index != selectedIndex) && (extend.index >= 0))
        {// 選択した項目のインデックス番号と項目名をログに出力
            Debug.Log(extend.index);
            Debug.Log(extend.list[extend.index].text);
        }
    }
}
// ここまでエディター上でのみ有効
#endif

// 同一オブジェクトへの複数追加を禁止
[DisallowMultipleComponent]
public class Extend : MonoBehaviour
{// エディター拡張の中身
    // リスト
    public GUIContent[] list = { };
    // 初期値は“未選択”
    public int index = -1;
}

インデックス番号や未選択状態等は,個人的な好みとして追加しております。

文字列配列string[]にインデックス番号を付与する方法として,今回はLINQSelect関数を使用しました。

docs.microsoft.com

SerializedObject の代入に関しては,nameof演算子を使用しています。

C# のバージョンが 5 以下であれば,次のように記述してください。

// リストを取得
var property = serializedObject.FindProperty("list");

docs.microsoft.com

インデックス番号を付与するデリゲートには,文字列補間機能を使用しています。

C# のバージョンが 5 以下であれば,次のように記述してください。

// GUIContent から text を抽出してインデックス番号を付与した配列
var textList = extend.list
    .Select((GUIContent content) => content.text)
    .Select((string name, int number) => (number + ": \r" + name))
    .ToArray();

docs.microsoft.com

以上,択一選択式プルダウンメニューにアイコンを設定する方法でした。

(複数選択式プルダウンメニュー MaskField には,アイコンを設定する事は出来ません。)