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
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы