LoginSignup
1

More than 1 year has passed since last update.

【Unity】エディタ拡張でSortingLayerのフィールドを表示する

Posted at

このメニューを出したい

image.png
標準のエディタ拡張APIでは、Sorting Layerを編集するポップアップを出す手段がありません。
これを手動で出せるようにするというお話です。

方針

実はSortingLayerのリストを表示するAPIがEditorGUI.SortingLayerField()として存在しているのですが、internalに指定されているために直接使用することができなくなっています。
当初はそのままコピペして動かそうと思ったのですが、結局別のinternalなメンバーにアクセスする必要が出てきてしまったので、EditorGUI.SortingLayerField()を直接リフレクションで呼び出すことにしました。

Unityでinternalなメンバにアクセスするにはasmrefを使う方法なんかもあるのですが、今回は相手がUnityEditor.dllなので使えず。素直にリフレクションを使います。

実装

エディタ描画の度にリフレクションさせるとエディタのパフォーマンスに影響しそうな気がするので、初回だけデリゲートを動的生成して2回目以降はキャッシュを使います。

SortingLayerEditorUtility.cs
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace Ruccho.Utilities
{
    public static class SortingLayerEditorUtility
    {

        private static GUIStyle boldPopupStyle;
        private static GUIStyle BoldPopupStyle
        {
            get
            {
                if (boldPopupStyle == null)
                {
                    boldPopupStyle = new GUIStyle(EditorStyles.popup);
                    boldPopupStyle.fontStyle = FontStyle.Bold;
                }
                return boldPopupStyle;
            }
        }

        private delegate void SortingLayerFieldDelegate(Rect position, GUIContent label, SerializedProperty layerID,
            GUIStyle style, GUIStyle labelStyle);

        private static SortingLayerFieldDelegate sortingLayerFieldDelegate = default;

        private static bool HasPrefabOverride(SerializedProperty property)
        {
            return property != null && property.serializedObject.targetObjects.Length == 1 && property.isInstantiatedPrefab && property.prefabOverride;
        }

        public static void SortingLayerFieldLayout(GUIContent label, SerializedProperty layerID)
        {
            var hasPrefabOverride = HasPrefabOverride(layerID);
            var style = hasPrefabOverride ? BoldPopupStyle : EditorStyles.popup;
            var labelStyle = hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label;
            SortingLayerFieldLayout(label, layerID, style, labelStyle);
        }

        public static void SortingLayerFieldLayout(GUIContent label, SerializedProperty layerID, GUIStyle style, GUIStyle labelStyle)
        {
            Rect rect = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight, style);
            SortingLayerField(rect, label, layerID, style, labelStyle);
        }

        public static void SortingLayerField(Rect position, GUIContent label, SerializedProperty layerID)
        {
            var hasPrefabOverride = HasPrefabOverride(layerID);
            var style = hasPrefabOverride ? BoldPopupStyle : EditorStyles.popup;
            var labelStyle = hasPrefabOverride ? EditorStyles.boldLabel : EditorStyles.label;
            SortingLayerField(position, label, layerID, style, labelStyle);
        }

        public static void SortingLayerField(Rect position, GUIContent label, SerializedProperty layerID,
            GUIStyle style, GUIStyle labelStyle)
        {
            if (sortingLayerFieldDelegate == default)
            {
                var editorGuiType = typeof(EditorGUI);
                var sortingLayerFieldMethod =
                    editorGuiType.GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic);

                if (sortingLayerFieldMethod == null) return;

                sortingLayerFieldDelegate = (SortingLayerFieldDelegate)
                    Delegate.CreateDelegate(typeof(SortingLayerFieldDelegate), sortingLayerFieldMethod);
            }

            sortingLayerFieldDelegate?.Invoke(position, label, layerID, style, labelStyle);
        }
    }
}

ここまでやればSortingLayerEditorUtility.SortingLayerFieldLayout() または SortingLayerEditorUtility.SortingLayerField()で呼び出しが可能です。

参考

neue cc - C#での動的なメソッド選択における定形高速化パターン

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
1