Все заметки

Игровой редактор

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

Сравнение кадров начальной версии игры и доработанной
Тянет скорее на ремастер. Даже мыло появилось

Но на самом деле движок умеет уже довольно много. В целом, он умел достаточно еще два года назад. При желании можно написать и другую игру, но есть одна вещь, которая меня постоянно останавливает – отсутствие игрового редактора.

Для чего вообще нужен редактор

Чтобы проще было понять его предназначение, думаю можно привести одну аналогию. Рисовать SVG графику можно как верстая руками xml разметку в какой-нибудь IDE, так и использовать специальные инструменты вроде Adobe Illustrator или Corel Draw. Первый вариант сгодится только для чего-то совсем простого, состоящего из пары примитивов. Но для рисования сложного лого или целой иллюстрации этого будет недостаточно. Разве что вы фанат подобных сложностей и на досуге занимаетесь воссозданием города Винтерфелл в Minecraft в натуральную величину.

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

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

Редактор анимаций
Эта штука на выходе дает только кусочек JSON-а с описанием стейт машины для анимационной системы. А нужно гораздо больше

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

С чего бы начать

Поскольку редактору нужен доступ к файловой системе для чтения и редактирования конфига, то обычной страничкой в браузере тут не обойтись. Вроде как и есть различные File System API в вебе, но они работают в рамках ограниченных песочниц, а это мне не подходит.

Первое, что пришло в голову – создать полноценное веб-приложение с бэкендом на какой-нибудь ноде, который будет по запросу взаимодействовать с файлами проекта. Однако я с трудом представлял кейс когда подобное приложение запускалось бы за пределами localhost да и трудозатрат на разработку это подкидывает немало, поэтому я продолжил думать дальше и надумал приложение на Electron. View часть пишется как в обычном вебе, а для взаимодействия с файлами можно написать код на ноде и прокинуть его на фронт через контекст.

В остальном – это стандартное веб-приложение с реактом, вебпаком и прочими прелестями frontend разработки. Первый “Hello, wolrd!” выглядел довольно скромно, но дал прочную основу для дальнейшей разработки. Ведь все как обычно начинается с занудного подключения линтеров, юнит тестов, сборщиков, гит хуков и так далее.

Hello world на Electron
Пока что на редактор это не очень похоже

Почему бы не запихнуть движок и в редактор

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

Подключение движка в редактор
Дизайн левой в панели в стиле веб-брутализма – решение временное

Выбираем дизайн-систему

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

Если посмотреть на редактор того же Unity, то можно заметить, что интерфейс довольно загруженный. Одновременно на экране может отображаться куча списков, кнопок и форм, поэтому все эти элементы должны быть компактными и простыми. В конечном итоге я остановился на Ant Design. Мне понравилось у нее наличие compact темы, когда все элементы максимально ужимают свои размеры, плюс библиотека уже долго живет и все еще активно поддерживается.

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

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

А теперь пусть и движок поработает

Статическая отрисовка выбранного уровня перестала меня впечатлять довольно быстро, поэтому пришла пора добавить немного интерактива. Уровень может быть большим и если рисовать его целиком в окошке по центру, то разглядеть что-то будет затруднительно. Поэтому нужны инструменты масштабирования и перемещения камеры.

Каждый выбранный инструмент задает определенный контекст для редактора. В Paint, при выбранном карандаше, левый клик мыши приводит к появлению точки, ведро – к заливке всего холста, а лупа – к увеличению масштаба. Плюсом к этому может меняться внешний вид курсора, а если есть контекстное меню на правый клик, то и его содержимое может поменяться. В общем все это нужно заранее предусмотреть.

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

При клике на инструмент происходит отправка сообщений в шину о том, какой инструмент нужно выбрать. В ответ на это система менеджер инструментов добавляет в main object компонент с маппингом мыши на действия, характерные для выбранного инструмента.

Схема работы панели инструментов 1

При выборе нового инструмента, менеджер удаляет старый компонент и создает другой уже с новым маппингом управления на действия.

Схема работы панели инструментов 2

Таким образом, те же самые действия мыши приводят к отправке разных сообщений в шину в зависимости от выбранного инструмента. А уже эти сообщения слушают другие системы, каждая из которых обрабатывает соответствующей ей инструмент.

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

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

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