Run kolobok run! Расширения редактора для клеточной системы

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

Введение в проблему

Препятствие, состоящие из 16 клеток. Вариант без расширения.​
Препятствие, состоящие из 16 клеток. Вариант без расширения.​

- Видишь клетки?

- Нет.

- И я не вижу, а они есть!

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

Материал статьи показывает, что, в целом, создать небольшой островок удобства внутри Вашего проекта на Unity достаточно просто и, что самое главное, доступно.

​Демонстрация работы расширения.
​Демонстрация работы расширения.

Реализация

Во-первых, для реализации расширений внутри Unity предусмотрен специальный класс Editor, от которого мы радостно и наследуемся. Для того, чтобы редактор понимал к чему это расширения, необходимо указать атрибут [CustomEditor]. Здесь мы подсказываем редактору, что применять скрипт необходимо к классам типа GameObjectBase, где, как вы помните (все же перечитали пост про клеточную систему?), хранится описание клеток. Незамысловатое true разрешает редактору докапываться и к наследникам от этого базового класса.

Run kolobok run! Расширения редактора для клеточной системы

Активация по выделению или метод OnEnable()

Стоит отметить для уже знакомых с Unity разработчиков, что в Editor'e метод жизненного цикла OnEnable() работает иначе. Он также выполняется при активации объекта, но в данном случае активацией является непосредственное выделение или, если будет угодно, клик по редактируемому объекту. Мы же используем его для инициализации переменных и сохранения начальных значений внутри скрипта.

Run kolobok run! Расширения редактора для клеточной системы
  • Поле target предоставляет сама Unity. Это исследуемый объект, на который действует рассматриваемый скрипт редактора. _base же вытягивает из объекта нужный нам класс, хранящий описание клеток.
  • Поле _field - привносит в код немного рефлексии. Оно обращается внутрь класса через метод GetFieldFromBaseClass() и вытягивает из него приватное поле _cellsDescriptions для того, чтобы иметь влияние на массив клеток и изменять его. Да, это, вероятно, не совсем хорошая операция. Ведь зачем тогда нужны приватные поля? Однако, замечу, что редактировать рабочий скрипт, чтобы к нему было удобно обращаться через расширения для редактора - идея не лучше. Приходится мириться с компромиссом: на ваших глазах происходит раскулачивание приватного поля :(
Попытка вытянуть из базовых классов необходимое поле.​
Попытка вытянуть из базовых классов необходимое поле.​
  • Массив _stdCellDescriptions хранит начальный набор клеток. Он здесь для реализации функции сброса настроек.
  • Массив булевых значений _matrix указывает на видимости столбцов. Дело в том, что при большом количестве клеток становится неудобно их редактировать, поэтому было решено сделать возможность отключения ненужного отображения. Мы остановились на отключении по столбцам, что выливается в компактную таблицу в инспекторе (см. дальше). Для этого массив хранит все столбцы клеток, а _maxX и _maxZ - это максимальные размеры в клетках по координатам X и Z соответственно. Проще один раз увидеть, чем сто раз услышать, правильно?

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

Табличка видимости, не влезающая в экран, для настройки клеток внутри одного кусочка локации.​
Табличка видимости, не влезающая в экран, для настройки клеток внутри одного кусочка локации.​

Впрочем, настраивать локацию по клеткам - затея довольно печальная в любом случае.

Инспектор - наш друг

Итак, начнём с настройки инспектора. Для обработки события изменения данных внутри инспектора Unity3D используется метод OnInspectorGUI(), внутри которого можно рисовать так необходимые нам кнопочки и таблички. Он вызывается каждый раз, когда производятся какие-либо манипуляции с интерфейсом инспектора. Объекты инспектора отображаются последовательно согласно вызываемым методам в OnInspectorGUI().

Соответствие скрипта и полей инспектора.​
Соответствие скрипта и полей инспектора.​

Классы EditorGUILayout и GUILayout содержат методы для создания кнопок, галок, полей, информационных сообщений и прочего. Располагаются где-то глубоко внутри самой Unity. Подробно останавливаться на этом не имеет смысла - картинка, отображающее работу скрипта, говорит сама за себя. Поэтому рассмотрим другие части реализации:

  • DrawDefaultInspector() - метод, отображающие стандартные настройки инспектора. Располагается внутри стандартного класса Editor, от которого наследуется наша надстройка.
  • FillVisibilityMatrix() - наш метод, отвечающий за красивую табличку в центре инспектора. Табличка эта не простая, а контролирующая видимость. Каждая кнопка отвечает за отображение своего столбика клеток.
Run kolobok run! Расширения редактора для клеточной системы
  • ControlSettings() - также наш метод, занимающийся настройкой цвета отображаемых клеток. Цвет зависит от типа клетки.
Run kolobok run! Расширения редактора для клеточной системы
  • ResetValues() - волшебная штука, спасающая при косяках. Сбрасывает все настройки на момент предыдущего вызова метода OnEnable().
  • SceneView.RepaintAll() - метод, отвечающий за обновление отображений внутри редактора сцены. Здесь он используется для того, чтобы изменение настроек внутри инспектора сразу передавались на сцену. Иначе изображение внутри редактора сцены обновляется только по событию самой Unity, происходящему при ковырянии внутри сцены.

На этом страдания внутри инспектора можно заканчивать и переходить к самому интересному и, на удивление, не более сложному. Отображению клеток.

Рисуем кубики на сцене

Эмоции человека, начавшего настраивать объекты на сцене с использованием расширения.​
Эмоции человека, начавшего настраивать объекты на сцене с использованием расширения.​

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

Run kolobok run! Расширения редактора для клеточной системы

Непосредственно перед отображением задаётся цвет средствами Unity (класс Handles). Затем стандартным методом рисуется заполненный прозрачный куб (CubeHandleCap) и полый куб (DrawWireCube) для контраста на границах.

Run kolobok run! Расширения редактора для клеточной системы

Теперь к вопросам как рассчитывается центр куба при помощи перебора клеток...

Run kolobok run! Расширения редактора для клеточной системы

В целом, здесь более или менее всё понятно. Стоит только отметить, что матрица видимости (_matrix) выполняется только для стандартных клеток на момент редактирования, которые сохранены в момент вызова OnEnable(). После чего выделяется клетка из текущего объекта _base и центр смещается, учитывая позицию клетки, позицию объекта и половину ребра клетки.

Режим редактирования дополнительно перерассчитывает центр куба в зависимости от изменения его координат на сцене (Handle.PositionHandle()) и записывает результат через рефлексию в объект. Всё.

Заключение

Внутрикомандный мем.​
Внутрикомандный мем.​

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

Делать процесс собственной разработки приятнее - очень приятно.

1010
Начать дискуссию