adressmoeistranici
@adressmoeistranici
Делатель

Как реализовать в инспекторе подобный регулятор?

1a575179ecf648639366134d7fadbabe.png
как реализовать подобный регулятор в скрипте?
  • Вопрос задан
  • 139 просмотров
Решения вопроса 1
BasmanovDaniil
@BasmanovDaniil
Геймдизайнер-телепат
В API такого слайдера нету, но до него можно доковыряться декомпилятором:
UnityEditor.ShadowCascadeSplitGUI
namespace UnityEditor
{
    using System;
    using System.Linq;
    using UnityEngine;

    internal static class ShadowCascadeSplitGUI
    {
        private static readonly Color[] kCascadeColors = new Color[] { new Color(0.5f, 0.5f, 0.6f, 1f), new Color(0.5f, 0.6f, 0.5f, 1f), new Color(0.6f, 0.6f, 0.5f, 1f), new Color(0.6f, 0.5f, 0.5f, 1f) };
        private const int kPartitionHandleExtraHitAreaWidth = 2;
        private const int kPartitionHandleWidth = 2;
        private const int kSliderbarBottomMargin = 2;
        private const int kSliderbarHeight = 0x18;
        private const int kSliderbarTopMargin = 2;
        private static readonly GUIStyle s_CascadeSliderBG = "LODSliderRange";
        private static readonly int s_CascadeSliderId;
        private static DragCache s_DragCache;
        private static DrawCameraMode s_OldSceneDrawMode;
        private static bool s_OldSceneLightingMode;
        private static SceneView s_RestoreSceneView;
        private static readonly GUIStyle s_TextCenteredStyle;

        static ShadowCascadeSplitGUI()
        {
            GUIStyle style = new GUIStyle(EditorStyles.whiteMiniLabel) {
                alignment = TextAnchor.MiddleCenter
            };
            s_TextCenteredStyle = style;
            s_CascadeSliderId = "s_CascadeSliderId".GetHashCode();
            s_OldSceneDrawMode = DrawCameraMode.Textured;
        }

        public static void HandleCascadeSliderGUI(ref float[] normalizedCascadePartitions)
        {
            GUILayout.Label("Cascade splits", new GUILayoutOption[0]);
            GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.Height(28f), GUILayout.ExpandWidth(true) };
            Rect position = GUILayoutUtility.GetRect(GUIContent.none, s_CascadeSliderBG, options);
            GUI.Box(position, GUIContent.none);
            float x = position.x;
            float y = position.y + 2f;
            float num3 = position.width - (normalizedCascadePartitions.Length * 2);
            Color color = GUI.color;
            Color backgroundColor = GUI.backgroundColor;
            int index = -1;
            float[] destinationArray = new float[normalizedCascadePartitions.Length + 1];
            Array.Copy(normalizedCascadePartitions, destinationArray, normalizedCascadePartitions.Length);
            destinationArray[destinationArray.Length - 1] = 1f - normalizedCascadePartitions.Sum();
            int controlID = GUIUtility.GetControlID(s_CascadeSliderId, FocusType.Passive);
            Event current = Event.current;
            int activePartition = -1;
            for (int i = 0; i < destinationArray.Length; i++)
            {
                float num8 = destinationArray[i];
                index = (index + 1) % kCascadeColors.Length;
                GUI.backgroundColor = kCascadeColors[index];
                float width = num3 * num8;
                Rect rect2 = new Rect(x, y, width, 24f);
                GUI.Box(rect2, GUIContent.none, s_CascadeSliderBG);
                x += width;
                GUI.color = Color.white;
                Rect rect3 = rect2;
                string t = string.Format("{0}\n{1:F1}%", i, num8 * 100f);
                GUI.Label(rect3, GUIContent.Temp(t, t), s_TextCenteredStyle);
                if (i == (destinationArray.Length - 1))
                {
                    break;
                }
                GUI.backgroundColor = Color.black;
                Rect rect4 = rect2;
                rect4.x = x;
                rect4.width = 2f;
                GUI.Box(rect4, GUIContent.none, s_CascadeSliderBG);
                Rect rect5 = rect4;
                rect5.xMin -= 2f;
                rect5.xMax += 2f;
                if (rect5.Contains(current.mousePosition))
                {
                    activePartition = i;
                }
                if (s_DragCache == null)
                {
                    EditorGUIUtility.AddCursorRect(rect5, MouseCursor.ResizeHorizontal, controlID);
                }
                x += 2f;
            }
            GUI.color = color;
            GUI.backgroundColor = backgroundColor;
            EventType typeForControl = current.GetTypeForControl(controlID);
            if (typeForControl == EventType.MouseDown)
            {
                if (activePartition >= 0)
                {
                    s_DragCache = new DragCache(activePartition, normalizedCascadePartitions[activePartition], current.mousePosition);
                    if (GUIUtility.hotControl == 0)
                    {
                        GUIUtility.hotControl = controlID;
                    }
                    current.Use();
                    if (s_RestoreSceneView == null)
                    {
                        s_RestoreSceneView = SceneView.lastActiveSceneView;
                        if (s_RestoreSceneView != null)
                        {
                            s_OldSceneDrawMode = s_RestoreSceneView.renderMode;
                            s_OldSceneLightingMode = s_RestoreSceneView.m_SceneLighting;
                            s_RestoreSceneView.renderMode = DrawCameraMode.ShadowCascades;
                        }
                    }
                }
            }
            else if (typeForControl == EventType.MouseUp)
            {
                if (GUIUtility.hotControl == controlID)
                {
                    GUIUtility.hotControl = 0;
                    current.Use();
                }
                s_DragCache = null;
                if (s_RestoreSceneView != null)
                {
                    s_RestoreSceneView.renderMode = s_OldSceneDrawMode;
                    s_RestoreSceneView.m_SceneLighting = s_OldSceneLightingMode;
                    s_RestoreSceneView = null;
                }
            }
            else if ((typeForControl == EventType.MouseDrag) && (GUIUtility.hotControl == controlID))
            {
                Vector2 vector = current.mousePosition - s_DragCache.m_LastCachedMousePosition;
                float num10 = vector.x / num3;
                bool flag = (destinationArray[s_DragCache.m_ActivePartition] + num10) > 0f;
                bool flag2 = (destinationArray[s_DragCache.m_ActivePartition + 1] - num10) > 0f;
                if (flag && flag2)
                {
                    s_DragCache.m_NormalizedPartitionSize += num10;
                    normalizedCascadePartitions[s_DragCache.m_ActivePartition] = s_DragCache.m_NormalizedPartitionSize;
                    if (s_DragCache.m_ActivePartition < (normalizedCascadePartitions.Length - 1))
                    {
                        normalizedCascadePartitions[s_DragCache.m_ActivePartition + 1] -= num10;
                    }
                    GUI.changed = true;
                }
                s_DragCache.m_LastCachedMousePosition = current.mousePosition;
                current.Use();
            }
        }

        private class DragCache
        {
            public int m_ActivePartition;
            public Vector2 m_LastCachedMousePosition;
            public float m_NormalizedPartitionSize;

            public DragCache(int activePartition, float normalizedPartitionSize, Vector2 currentMousePos)
            {
                this.m_ActivePartition = activePartition;
                this.m_NormalizedPartitionSize = normalizedPartitionSize;
                this.m_LastCachedMousePosition = currentMousePos;
            }
        }
    }
}


Как можно видеть из кода выше, используется обычный GUI.Box в комбинации с Event. Чтобы получить нечто похожее, придётся проделать много ручной работы, я бы на вашем месте не стал возиться, пока совсем не припрёт. Можно ещё попробовать через рефлексию попользовать ShadowCascadeSplitGUI, но не факт, что заведётся.

Вызывается оно из QualitySettingsEditor следующим образом:
private void DrawCascadeSplitGUI<T>(ref SerializedProperty shadowCascadeSplit)
{
    float[] normalizedCascadePartitions = null;
    Type type = typeof(T);
    if (type == typeof(float))
    {
        normalizedCascadePartitions = new float[] { shadowCascadeSplit.floatValue };
    }
    else if (type == typeof(Vector3))
    {
        Vector3 vector = shadowCascadeSplit.vector3Value;
        normalizedCascadePartitions = new float[] { Mathf.Clamp(vector[0], 0f, 1f), Mathf.Clamp((float)(vector[1] - vector[0]), (float)0f, (float)1f), Mathf.Clamp((float)(vector[2] - vector[1]), (float)0f, (float)1f) };
    }
    if (normalizedCascadePartitions != null)
    {
        EditorGUI.BeginChangeCheck();
        // ↓↓↓↓
        ShadowCascadeSplitGUI.HandleCascadeSliderGUI(ref normalizedCascadePartitions);
        // ↑↑↑↑
        if (EditorGUI.EndChangeCheck())
        {
            if (type == typeof(float))
            {
                shadowCascadeSplit.floatValue = normalizedCascadePartitions[0];
            }
            else
            {
                Vector3 vector2 = new Vector3();
                vector2[0] = normalizedCascadePartitions[0];
                vector2[1] = vector2[0] + normalizedCascadePartitions[1];
                vector2[2] = vector2[1] + normalizedCascadePartitions[2];
                shadowCascadeSplit.vector3Value = vector2;
            }
        }
    }
}

Заодно декомпильнул редактор компонента LODGroup, где есть похожий слайдер, но там код гораздо запутаннее.
UnityEditor.LODGroupEditor
UnityEditor.LODGroupGUI
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы