[EXP] Unity 3D кастомный Inspector малой кровью. Атрибуты для инспектора.

[EXP] Unity 3D кастомный Inspector малой кровью. Атрибуты для инспектора.

Приветствую всех ценителей движка Юнити!

В прошлой статье я поделился своим опытом и мыслями касательно кастомного редактора для MonoBehaviour, в котором можно реализовывать всякое... Но кроме порой запутанного и времязатратного решения, дающего огромный визуальный и технический функционал, есть более простой вариант, заключающийся в использовании атрибутов, который позволяет систематизировать и представлять данные за считанные секунды.

Атрибуты в юнити определяют "поведение" классов/свойств и заключаются в квадратные скобки. Если нужно указать несколько атрибутов за раз, то они перечисляются через запятую: [attribute1, attribute2, attribute3].

Примеры использования атрибутов

Я создал тестовый скрипт в Юнити, в котором указаны наиболее частые атрибуты. Ниже вкратце опишу их суть, а для удобства повествования разделю на группы.

using System.Collections.Generic; using UnityEngine; [AddComponentMenu("Custom/Editor with Attributes"), RequireComponent(typeof(AudioSource)), SelectionBase] public class AttributesEditor : MonoBehaviour { [System.Serializable] //Отображает классы, структуры и позволяет их редактировать в инспекторе public struct SomeStruct { public int a; public int b; public int c; } [Header("Common")] [Tooltip("Введите свой текст сюда!")] public string _someString; //подсказка при наведении мышкой [SerializeField] private float _someFloat; //показывает приватную переменную [Space(10)] //отступ после _someInt [HideInInspector] public int _someInt; //прячет публичную переменную [Header("Interactive")] [ContextMenuItem("Add", nameof(Add), order = 0)] //добавляет действие в контекстном меню [ContextMenuItem("Subtract", nameof(Subtract), order = 1)] [ContextMenuItem("Randomize", nameof(Randomize), order = 2)] [ContextMenuItem("Reset", nameof(Reset), order = 3)] public int _value; [Space(10), Range(0, 10)] public float _slideFloat; //Слайдер от 0 до 10 [Header("Text Attributes")] [TextArea] public string _textField; //поле ввода текста [Space(10), Multiline] public string _textMultiline; //поле ввода текста [Header("Struct, Classes in list")] public List<SomeStruct> _someStructList = new List<SomeStruct>(); void Start() { } private void Add() => _value++; private void Subtract() => _value--; private void Randomize() => _value = Random.Range(0, 100); private void Reset() => _value = 0; }

Вот как выглядит скрипт с атрибутами в инспекторе:

Отображение скрипта в инспекторе
Отображение скрипта в инспекторе

Атрибуты класса:

• AddComponentMenu("Вкладка/Название скрипта") - добавляет скрипт в меню компонентов.

AddComponentMenu
AddComponentMenu

• RequireComponent(typeof(Компонент)) - автоматически добавляет требуемый компонент объекту вместе с скриптом.

• SelectionBase - при нажатии на дочерние объекты движок будет выделять родительский (на котором висит скрипт).

Визуальные атрибуты:

• Header("Заголовок") - создает заголовок перед группой переменных.

• Space(Величина отступа) - добавляет отступ после переменной

Атрибуты для свойств:

• Tooltip("Текст подсказки") - показывает подсказку при наведении мышкой.

Tooltip
Tooltip

• SerializeField - отображает приватную переменную в инспекторе.

HideInInspector - скрывает публичную переменную в инспекторе.

• TextArea - используется для string переменных. Добавляет поле для текста.

• Multiline - используется для string переменных. Добавляет поле для текста.

Функциональные атрибуты:

• ContextMenuItem("Название", "Метод в скрипте", order = порядковый номер) - вызывается контекстное меню при нажатии правой кнопки мыши.

ContextMenuItem
ContextMenuItem

• Range(от, до) - отображает слайдер для int или float.

• System.Serializable - помечает классы и структуры для их сериализации. Указав данный атрибут можно создать лист из Struct и редактировать его прямо в инспекторе.

Serializable
Serializable

Заключение

Вот такой инспектор, разбавленный заголовками, группами и простым функционалом может получиться, если мы будем использовать атрибуты и уделять внимание структуризации свойств. Иногда, чтобы расширить базовый функционал инспектора, совсем не обязательно прибегать к усложненным решениям, требующим особого внимания и глубоких знаний.

Старался не перегружать статью сложными терминами и надеюсь она окажется кому-то полезной. Если вы знаете какие еще атрибуты можно использовать на практике, был бы рад обмену опытом.

Благодарю за внимание) Будьте здоровы.

66
5 комментариев

задумывался как то над кастомными атрибутами, но пошарившись немного как то стало впадлу этим заниматься, чисто имхо, но этим всем можно заниматься когда проект более менее готовый и уже на стадии правки баланса или навешивания новых рюшечек, а вот во время запила демки/прототипа/новых механик, выглядит как лишняя работа

в общем, пока обошелся только хедерами чисто что бы поля разделять, но статья полезная

1

в общем, пока обошелся только хедерами чисто что бы поля разделять,

https://docs.unity3d.com/ScriptReference/SpaceAttribute.html
Делаешь своего наследника с константным значением (например, 18 как у EditorGUIUtility.singleLineHeight) и будут тебе разделители полей

1

кстати все еще не понимаю почему этого функционала нет в базовой версии движка, ведь запилить самому это все можно буквально за несколько часов