【Unity】편집기 확장으로 SortingLayer의 필드를 표시한다

13252 단어 Unity

이 메뉴를 내고 싶다




표준 편집기 확장 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 #에서 동적 메소드 선택에서 정형 가속 패턴

좋은 웹페이지 즐겨찾기