Как заставить поля Vector3 вести себя как поля из Transform в CustomEditor

На следующем gif вы можете увидеть разницу между тем, как поля Vector3 ведут себя в инспекторе Transform и моих MonoBehaviours.

Как заставить поля Vector3 вести себя как поля из Transform в CustomEditor

Transform — это даже CustomEditor Я тоже писал с помощью EditorGUILayout.Vector3Field().

[CustomEditor(typeof(Transform), true)]
[CanEditMultipleObjects]
public class AdvancedTransformEditor : Editor
{
    //Unity's built-in editor
    private Editor _defaultEditor;
    private Transform _transform;

    private void OnEnable()
    {
        //When this inspector is created, also create the built-in inspector
        _defaultEditor = CreateEditor(targets, Type.GetType("UnityEditor.TransformInspector, UnityEditor"));
        _transform = target as Transform;
    }

    private void OnDisable()
    {
        //When OnDisable is called, the default editor we created should be destroyed to avoid memory leakage.
        //Also, make sure to call any required methods like OnDisable
        var disableMethod = _defaultEditor.GetType().GetMethod("OnDisable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (disableMethod != null) disableMethod.Invoke(_defaultEditor, null);
        DestroyImmediate(_defaultEditor);
    }

    public override void OnInspectorGUI()
    {
        EditorGUILayout.LabelField("Local Space", EditorStyles.boldLabel);
        _defaultEditor.OnInspectorGUI();

        serializedObject.Update();

        //Show World Space Transform
        EditorGUILayout.Space();
        EditorGUILayout.LabelField("World Space", EditorStyles.boldLabel);

        _transform.position = EditorGUILayout.Vector3Field("Position", _transform.position);

        EditorGUI.BeginDisabledGroup(true);
        EditorGUILayout.Vector3Field("Rotation", _transform.eulerAngles);
        EditorGUILayout.Vector3Field("Scale", _transform.lossyScale);
        EditorGUI.EndDisabledGroup();

        serializedObject.ApplyModifiedProperties();
    }
}

Это работает только при наличии _defaultEditor.OnInspectorGUI();, поэтому что-то в исходном редакторе Unity для компонента Transform должно делать что-то другое.

Когда я пытаюсь сделать то же самое в любом другом CustomEditor за MonoBehaviour

// without a CustomEditor
public class Example : MonoBehaviour
{
    public Vector3 example;
}

и

// Width the custom editor
public class ExampleMinWidth : MonoBehaviour
{
    public Vector3 example;
}

[CustomEditor(typeof(ExampleMinWidth))]
public class ExampleMinWidthEditor : Editor
{
    private SerializedProperty example;

    private void OnEnable()
    {
        example = serializedObject.FindProperty("exmaple");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value);

        // I tried both also simply using a PropertyField
        //EditorGUILayout.PropertyField(example);
        serializedObject.ApplyModifiedProperties();
    }
}

или пропуск строки _defaultEditor.OnInspectorGUI(); в AdvancedTransformEditor поле Vector3 складывается для определенной ширины Инспектора.

Как я могу добиться того же поведения для своих полей, что и для компонента Transform — не свертываться, а оставаться на той же строке?


Обновлять

  • Я попробовал это с GUILayout.MinWidth(), но это ничего не изменило.

  • Как было предложено, я также пробовал

    example.vector3Value = EditorGUILayout.Vector3Field("Example", example.vector3Value, GUILayout.ExpandHeight(false));
    

    (также для PropertyField()), но это ничего не изменило.

  • А на пробу тоже делал с ExpandWidth(false)...результат не очень радует :D

    Как заставить поля Vector3 вести себя как поля из Transform в CustomEditor

  • Я даже пробовал GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight), но это заставляет поле по-прежнему сворачиваться, но «загружаться»/перерисовываться в поле ниже.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
3 174
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Unity3d имеет свой исходный код, доступный на GitHub, где вы можете увидеть реализацию компонента Трансформировать.

TransformInspector.cs:

/ Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License

using UnityEngine;

namespace UnityEditor
{
    [CustomEditor(typeof(Transform))]
    [CanEditMultipleObjects]
    internal class TransformInspector : Editor
    {
        SerializedProperty m_Position;
        SerializedProperty m_Scale;
        TransformRotationGUI m_RotationGUI;

        class Contents
        {
            public GUIContent positionContent = EditorGUIUtility.TrTextContent("Position", "The local position of this GameObject relative to the parent.");
            public GUIContent scaleContent = EditorGUIUtility.TrTextContent("Scale", "The local scaling of this GameObject relative to the parent.");
            public string floatingPointWarning = LocalizationDatabase.GetLocalizedString("Due to floating-point precision limitations, it is recommended to bring the world coordinates of the GameObject within a smaller range.");
        }
        static Contents s_Contents;

        public void OnEnable()
        {
            m_Position = serializedObject.FindProperty("m_LocalPosition");
            m_Scale = serializedObject.FindProperty("m_LocalScale");

            if (m_RotationGUI == null)
                m_RotationGUI = new TransformRotationGUI();
            m_RotationGUI.OnEnable(serializedObject.FindProperty("m_LocalRotation"), EditorGUIUtility.TrTextContent("Rotation", "The local rotation of this GameObject relative to the parent."));
        }

        public override void OnInspectorGUI()
        {
            if (s_Contents == null)
                s_Contents = new Contents();

            if (!EditorGUIUtility.wideMode)
            {
                EditorGUIUtility.wideMode = true;
                EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
            }

            serializedObject.Update();

            Inspector3D();
            // Warning if global position is too large for floating point errors.
            // SanitizeBounds function doesn't even support values beyond 100000
            Transform t = target as Transform;
            Vector3 pos = t.position;
            if (Mathf.Abs(pos.x) > 100000 || Mathf.Abs(pos.y) > 100000 || Mathf.Abs(pos.z) > 100000)
                EditorGUILayout.HelpBox(s_Contents.floatingPointWarning, MessageType.Warning);

            serializedObject.ApplyModifiedProperties();
        }

        private void Inspector3D()
        {
            EditorGUILayout.PropertyField(m_Position, s_Contents.positionContent);
            m_RotationGUI.RotationField();
            EditorGUILayout.PropertyField(m_Scale, s_Contents.scaleContent);
        }
    }
}
Ответ принят как подходящий

Я нашел соответствующие строки в Трансформинспектор

if (!EditorGUIUtility.wideMode)
{
    EditorGUIUtility.wideMode = true;
    EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - 212;
}
  • EditorGUIUtility.wideMode выполняет две функции: Возвращает определяет, находится ли редактор в настоящее время является в широкоформатном режиме, и набор указывает, должен ли редактор для этого компонента/следующих строк вести себя так же, как в широкоформатном режиме. Таким образом, они просто заставляют свои поля «быть» только в широкополосном режиме.

  • После этого необходимо использовать «фиксированный» EditorGUIUtility.labelWidth, а именно уменьшенный на ширину, которую 3 поля Vectror3 будут занимать в широком режиме (Unity использовала 212)

Другие вопросы по теме