Используйте ящики свойств с IMGUI для настройки Inspector
Примечание: Настоятельно рекомендуется использовать UI Toolkit для расширения Unity Editor, так как это более современное, гибкое и масштабируемое решение, чем IMGUI.
Ящики свойств могут быть использованы для настройки внешнего вида некоторых элементов управления в Окно Inspector с помощью атрибутов в ваших скриптах или путем управления тем, как Serializable как должен выглядеть класс.
Ящики Свойств имеют два вида применения:
- Настройте интерфейс для каждого экземпляра сериализуемого класса.
- Настроить GUI членов скрипта с настраиваемыми Атрибуты свойств.
Настройка интерфейса сериализуемого класса
Если у вас есть обычай Сериализируемые класс, вы можете использовать Ящик свойства чтобы контролировать, как он выглядит в Inspector. Рассмотрим сериализуемый класс Ingredient в примерах скриптов ниже (Примечание: Это не скрипты редактора. Классы атрибутов свойств должны быть помещены в обычный скриптовый файл):
C# (пример):
using System;
using UnityEngine;
enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class
[Serializable]
public class Ingredient
{
public string name;
public int amount = 1;
public IngredientUnit unit;
}
public class Recipe : MonoBehaviour
{
public Ingredient potionResult;
public Ingredient[] potionIngredients;
}
С помощью пользовательского отрисовщика свойств можно изменить внешний вид класса Ingredient во всех местах, где он появляется в Inspector. Сравните вид свойств Ingredient в инспекторе без пользовательского отрисовщика и с ним:
Прикрепить отрисовщик свойства к сериализуемому классу можно с помощью CustomPropertyDrawer атрибут и передайте тип сериализуемого класса, для которого он является отрисовщиком.
C# (пример):
using UnityEditor;
using UnityEngine;
// IngredientDrawer
[CustomPropertyDrawer(typeof(Ingredient))]
public class IngredientDrawer : PropertyDrawer
{
// Draw the property inside the given rect
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
// Draw label
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
var amountRect = new Rect(position.x, position.y, 30, position.height);
var unitRect = new Rect(position.x + 35, position.y, 50, position.height);
var nameRect = new Rect(position.x + 90, position.y, position.width - 90, position.height);
// Draw fields - pass GUIContent.none to each so they are drawn without labels
EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("amount"), GUIContent.none);
EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("unit"), GUIContent.none);
EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
Настройка GUI членов скрипта с помощью атрибутов свойств
Другое применение Свойств Drawer — это изменение внешнего вида членов в скрипте, которые имеют пользовательские Атрибуты Свойств. Предположим, что вы хотите ограничить плавающие или целые числа в вашем скрипте определенным диапазоном и показать их как слайдеры в Inspector. Используя встроенные PropertyAttribute, называемые RangeAttribute вы можете сделать именно это:
C# (пример):
// Show this float in the Inspector as a slider between 0 and 10
[Range(0f, 10f)]
float myFloat = 0f;
Вы можете сделать свой собственный PropertyAttribute Мы будем использовать код для RangeAttribute атрибут должен расширять пределы PropertyAttribute класс. При желании ваш атрибут может принимать параметры и хранить их в открытых переменных-членах.
C# (пример):
using UnityEngine;
public class MyRangeAttribute : PropertyAttribute
{
readonly float min;
readonly float max;
void MyRangeAttribute(float min, float max)
{
this.min = min;
this.max = max;
}
}
Теперь, когда у вас есть атрибут, вам нужно сделать Ящик свойства атрибут. Выдвижной ящик должен расширять свойства, имеющие этот атрибут. PropertyDrawer класс, и у него должен быть CustomPropertyDrawer атрибут, чтобы сказать ему, для какого атрибута это ящик.
Класс отрисовщика свойств должен находиться в редакторском скрипте, внутри папки Editor.
C# (пример):
using UnityEditor;
using UnityEngine;
// Tell the MyRangeDrawer that it is a drawer for properties with the MyRangeAttribute.
[CustomPropertyDrawer(typeof(MyRangeAttribute))]
public class RangeDrawer : PropertyDrawer
{
// Draw the property inside the given rect
void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// First get the attribute since it contains the range for the slider
MyRangeAttribute range = (MyRangeAttribute)attribute;
// Now draw the property as a Slider or an IntSlider based on whether it's a float or integer.
if (property.propertyType == SerializedPropertyType.Float)
EditorGUI.Slider(position, property, range.min, range.max, label);
else if (property.propertyType == SerializedPropertyType.Integer)
EditorGUI.IntSlider(position, property, (int) range.min, (int) range.max, label);
else
EditorGUI.LabelField(position, label.text, "Use MyRange with float or int.");
}
}
Обратите внимание, что по причинам производительности, функции EditorGUILayout не могут использоваться с выдвижными ящиками свойств.
Ссылки на объекты по умолчанию
Если вы объявляете открытый Object поля или закрытые, помеченные SerializeField, вы можете настроить ссылки по умолчанию для этих полей. Поля ссылки по умолчанию отображаются в окне Inspector, когда вы выбираете ассет скрипта в окне Project.
Примечание: Рекомендуется хранить каждый PropertyDrawer в отдельном файле с соответствующим имя. Это обеспечивает эффективное распределение ссылок на объекты по умолчанию, так как они могут быть назначены только одному PropertyDrawer. Когда в одном файле присутствует несколько типов, назначенный тип будет либо соответствовать имени файла, либо будет первым типом, определенным в файле.