2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UnityのインスペクターでEnumの一部項目を隠す方法

Last updated at Posted at 2021-09-17

やりたい事

シリアライズされたEnumFieldの中身を変えずに、Editorで表示できる項目を制限したい:

// サンプルEnumの定義
public enum ColorEnum {
    None = 0,
    Red = 1,
    Green = 2,
    Blue = 3
}

そのままEditorで表示させる場合、すべての項目が選択可能

[SerializeField] ColorEnum myColor;

normal.png

このように、「HideEnumItem」という魔法Attributeをつける事で、Editorで表示された「myColor」から「None」と「Red」を隠したい

[HideEnumItem("None", "Red"), SerializeField] ColorEnum myColor;

filtered.png

「HideEnumItem」という魔法Attributeは下記の「Custom Attribute」と「Custom Property Drawer」で用意する。

「Custom Attribute」を用意する

Custom Attribute」はc#標準機能で、「SerializeField」のようなAttributeを自作することができます。

まずは通常のScriptsフォルダで下記の「HideEnumItemAttribute.cs」ファイルを作成:

using System.Collections.Generic;
using UnityEngine;

// AttributeUsageで使用できる変数をクラスのフィールドに限定
[System.AttributeUsage(System.AttributeTargets.Field)]
public class HideEnumItemAttribute : PropertyAttribute
{
    // 隠したい項目を保存用
    public HashSet<string> Filter { get; private set; }
    public HideEnumItemAttribute(params string[] filters)
    {
        Filter = new HashSet<string>();
        for (var i = 0; i < filters.Length; i++) {
            Filter.Add(filters[i]);
        }
    }
}

「Custom Property Drawer」を用意する

Custom Property Drawer」はUnityEditorの機能で、Editorのインスペクター周りの描画をカスタマイズする事ができます。

上記のHideEnumItemAttributeを受け取って、指定された項目を隠す「HideEnumItemAttribute.cs」ファイルを作成(こちらはUnityEditorのAPIを使っているので、Editorフォルダに置く必要があります):

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

// 自作のAttributeを指定
[CustomPropertyDrawer(typeof(HideEnumItemAttribute))]
public class HideEnumItemDrawer : PropertyDrawer
{
    int selectedIndex;
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // Attribute取得
        var filterInfo = (HideEnumItemAttribute)attribute;
        // eunmValueIndex変換用
        var enum2index = new Dictionary<int, int>(property.enumNames.Length);
        for (int i = 0; i < property.enumNames.Length; i++)
        {
            var enumEntry = Enum.Parse(fieldInfo.FieldType, property.enumNames[i]);
            enum2index[(int)enumEntry] = i;
        }
        // 表示項目を加工
        var filteredItems = property.enumNames.Where(item => !filterInfo.Filter.Contains(item)).ToList();
        // Editor表示の同期
        selectedIndex = filteredItems.IndexOf(property.enumNames[property.enumValueIndex]);
        // シリアライズされた値が範囲外だった場合、最初の項目に設定
        if (selectedIndex < 0) {
            selectedIndex = 0;
            var mappedEnum = Enum.Parse(fieldInfo.FieldType, filteredItems[selectedIndex]);
            property.enumValueIndex = enum2index[(int)mappedEnum];
        }

        // オリジナルの代わりに、加工されたリストを描画
        using (var check = new EditorGUI.ChangeCheckScope())
        {
            selectedIndex = EditorGUI.Popup(position, label.text, selectedIndex, filteredItems.ToArray());
            if (check.changed)
            {
                // 元のEnum値に変換
                var mappedEnum = Enum.Parse(fieldInfo.FieldType, filteredItems[selectedIndex]);
                property.enumValueIndex = enum2index[(int)mappedEnum];
            }
        }
    }
}

まとめ

このように「Custom Attribute」と「Custom Property Drawer」を組み合わせることで、汎用的かつ効率的なEditor拡張ができるようになるので、重宝したいですね。因みに、このような便利な「Custom Attribute」をたくさん用意してくれてるUnityアセットが「Odin Inspector And Serializer」になります。興味ある方はぜひチェックしてみてください。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?