Опыт написания кастомного редактора, окна для инструментов, расширения для ускорение и автоматизации рутинных задач

Иногда эта сказка добрая — про пони и радугу. А иногда — про страшного бабайку. И очень важная часть данного движка, а именно расширения для редактора (custom inspectors) — как раз про бабайку. В статье я бы хотел поделиться опытом использования собственных расширений на примере нашей игры.

Некоторые из наиболее интересных наших расширений. Сколько на экран влезло

Начнём с определения. Вот, что говорится в документации про расширения: «Unity позволяет вам расширить редактор своими собственными инспекторами и окнами редактора (Editor Windows), и вы можете задать, как свойства должны отображаться и инспектора при помощи пользовательского Property Drawers».

То есть имеем три основных типа для расширения функциональности, наследуемые от базовых классов:

  • UnityEditor.Editor;
  • UnityEditor.EditorWindow;
  • UnityEditor.PropertyDrawer.

И сразу же первая загвоздка — все расширения делаются только с помощью кода. Никакого визуального программирования и блок-схем, WYSIWYG, перетаскивания кнопочек по формочкам. Только C #, только хардор. Изменил размер кнопки — будь добр пересобрать весь проект, чтобы увидеть изменения. Соответственно, написать новое расширение или поправить скаченное из Asset Store не программисту — практически непосильная задача.

Первый тип (Editor) используется для того, чтобы сказать Unity «как отобразить класс». Это может быть ScriptableObject или MonoBehaviour. Используется чаще всего, по крайне мере у нас. Второй (EditorWindow) — может быть использован для отображения почти любого содержимого в пределах нового окна, за которое он отвечает. Третий (PropertyDrawer) отвечает на вопрос «как отобразить параметр». Причём это может быть как один из стандартных типов параметров, так и свой собственный.

Пример кастомного окна редактора из документации

Для каждого из типов расширений можно найти по небольшому «Hello World» в документации. Но чтобы сделать действительно полезное, удобное и красивое расширение, придётся ещё постараться. Связано это, во-первых, с наличием огромного числа недокументированных и внутренних (Internal) функций движка, которые можно использовать.

Во-вторых, с большим количеством багов и общей неинтуитивностью подсистемы. В-третьих, почти все статьи про расширения на английском или вообще иероглифы. Если с английским лично я ещё могу справится, то китайский поддается только Google-переводчику, что слабо помогает общему усвоению информации. Именно поэтому сделать что-то сложнее двух дополнительных кнопок — сродни алхимии и чёрной магии. Но когда это нас останавливало?

В нашей, казалось бы, небольшой игре используется 22 собственных скрипта для расширений на приблизительно 2,5 тысяч строк кода в сумме. Приведу особо интересные примеры для каждого типа расширений.

PropertyDrawer

Здесь, как раз, ничего сильно интересного у нас нет. Просто для примера — отображение свойства неактивным, если объект на сцене. И возможность редактировать свойство, если объект является префабом.

Эта функция используется для свойств-идентификаторов объектов. Что-то типа ИД, необходимого для сериализации/десериализации структуры уровня. Защита от самого себя, чтобы не поменять идентификатор во время сборки уровня в редакторе. Если так сделать — уровень сохранится, но загружаться не будет.

Еще есть PropertyDrawer для класса «Координаты X и Y» — вместо двух строчек выводит в одну. Ещё один — для отображения коллекции string в виде выпадающего списка.

EditorWindow

Здесь уже интереснее. Кастомное окно у нас одно. Используется как основной способ редактирования уровня. Весь код я приводить, конечно, не буду. Из интересного можно выделить пару моментов.

Первый — получение картинки-превью префаба. То есть той картинки, которая отображается в самом редакторе Unity. Реализуется с помощью одного метода AssetPreview.GetAssetPreview(gameObject).

Второй — центрирование камеры в SceneView к выбранной ячейке

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

Дальше от него наследуются все остальные кастомные эдиторы. Самые «толстые» у нас — это ContentPackEditor, LevelEditor, LocalizationEditor, GameFieldEditor. Каждый от 200 до 300 строк кода. Опять же, приводить код каждого смысла не имеет. Расскажу только про интересные моменты.

Для ContentPackEditor нужны были функции визуальной сортировки элементов массива. И они в Unity есть, это ReorderableList в UnityEditorInternal. Вот статья по основам использования.

От себя я добавил сворачивание/разворачивание списка при клике на заголовок.

В LocalizationEditor надо было сделать что-то вроде таблицы, чтобы чётные и нечётные сроки выводились разным цветом. Решается это заведением двух разных стилей.

Вторым проблемным моментом было сделать поиск в уже добавленных ключах локализации и мгновенный вывод результатов в виде выпадающего списка под строкой поиска. Вот для этого найти решение было действительно непросто. В итоге нашёлся метод на каком-то китайском сайте с иероглифами. Хорошо, что код — он и в Африке (Китае) код.

Путём небольшой доработки напильником стало выглядеть вот так.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *