Как я делал редактор уровней для 2.5D игры в Unity
Была идея сделать редактор уровней, чтобы ускорить создание контента для игры и в будущем дать возможность создавать уровни игрокам.
Уровень состоит из соединенных между собой платформ, стен, игровых объектов и декораций.
Платформы и стены: Я заранее сделал части моделей определенного размера под каждый биом и вариации углов между ними (от 5 до 45 градусов)
Игровые объекты: Есть множество объектов, которые должны быть на поверхности платформы или стены.
Ещё любой уровень должен обязательно иметь объект финиша.
Что вкратце сделал
- Менеджер объектов на сцене
- Undo/Redo базовых операций
- Разделить игровые объекты и объекты редактора уровня
- Генератор иконок
- Выделение объектов через клик либо зону
- Перемещение, вращение, изменение размера объектов через Runtime Transfrom Handles пакет
- Контекст меню для любого объекта (чтобы настраивать соотв. параметры для уникальных объектов кроме позиции, поворота и размера)
- Сохранение и загрузка уровня через файл
Менеджер объектов сцены
Начал с него. Менеджер пригодится, чтобы в будущем быстро искать объекты в сцене через словарь, а также для сохранения и загрузки уровня, не ломая связи между объектами. Любой созданный объект имеет InstanceId от Unity, но он непостоянный между сессиями и связи между объектами ломаются после загрузки уровня (например кнопка, которая активирует лифт). В моем менеджере у меня есть свой id, который растет с каждым новым созданным объектом на +1, словарь {id, GameObject} и все операции создания / удаления объектов я делаю через него. При создании объекта я добавляю в его имя постфикс id{x}, чтобы затем получить его обратно из имени.
Undo/Redo
Чтобы была возможность делать Undo/Redo, я добавил интерфейс ICommand и написал отдельный класс с историей для них, возможностью группировать несколько команд в один шаг для истории. Ниже прикрепляю мою базу для работы:
Undo/Redo лучше реализовать сразу, чтобы потом не рефакторить код в команды + можно по ходу разработки это все тестировать и сразу править баги. Реализовал команды создания, удаления, перемещения объектов. Решение сделать Undo/Redo оказалось довольно удобным для пользователей, но с точки зрения разработки я довольно много времени потратил на тестирование каждой новой команды.
Объекты для редактора уровня
Пришлось разграничить объекты в проекте под редактор и игру. У меня все объекты выделяются через рейкаст систему в Unity, поэтому нужен отдельно коллайдер для каждого, что можно выделить в редакторе. Я сделал префаб-варианты игровых объектов с их настройкой под редактор соответственно.
Чтобы хоть как-то разместить объект в сцене, я решил сделать палитру объектов в UI.
Для этого нужно было сделать конфиги (ScriptableObject) под каждый объект, где есть иконка, ссылки на игровой и редактора объекты (загружаю я их через Addressables). Чтобы не умереть от рутины, 200+ конфигов объектов создал через код, в том числе связка иконок в будущем через сравнение имен конфига и иконки.
Генератор иконок
Для иконок нужно было сделать генератор. В интернете не нашел подходящий, но, изучив бесплатные, сделал свой (пока только для URP). В моем решении ты сам выставляешь объекты в сцене и картинка получается с прозрачным фоном + сглаживание работает.
Выделение объектов
Необходимо как-то двигать, вращать объекты, но для начала их нужно выбрать. Сделал менеджер выделения объектов. Через него можно получить информацию о них + накидывается обводка. Для обводки объектов использовал этот ассет (работает через Post Processing и добавляет обводку при помощи Rendering Layer Mask, что довольно удобно)
Runtime Transfrom Handles
Добавил гизму, чтобы двигать, вращать и менять размер объектам. Использовал этот инструмент (но пришлось адаптировать и мелкие баги поправить)
Контекст меню объекта
Тут можно настроить любой объект и дописать отдельные контекст элементы для каждого при необходимости. На их реализацию ушло довольно немало времени, пришлось сделать свои UI элементы ввода с обратными событиями (Vector2, Vector3, float) + на каждый уникальный объект (мина, кнопка и т.п.) свой скрипт под контекст элемент и обработчик.
В целом когда продумывал редактор, то вдохновлялся Unity инспектором.
Сохранение и загрузка уровня
Для сохранения и загрузки я использую менеджер объектов. При сохранении он пробегается по всем объектам уровня и записывает данные каждого в такой класс:
Где AdditionalData это дополнительные параметры для уникальных объектов по типу мина, лифт и другие. InstanceId мне нужен для связки объектов между собой (кнопка-лифт).
Все данные уровня сохраняю в json формате, пока не знаю как лучше, но весомых проблем в этом не обнаружил.
Было интересно реализовать сохранение и загрузку событий для кнопок (UnityEvent), для этого пришлось сделать отдельный контекст элемент в UI +- как в Unity инспекторе. Пришлось использовать рефлексию, чтобы взять нужный метод по названию класса для добавления его в UnityEvent.
Итого
На реализацию альфа-версии редактора уровня у меня ушло 1.5 месяца, что довольно немало.
Планирую в будущем отполировать редактор и вшить в игру с поддержкой Steam Workshop. Сейчас же там только английская локализация, есть пару багов, но в целом уже достаточно, чтобы делать уровни (пока что я конвертирую из файла в префаб и мелочи правлю в Unity).
Если интересно дальше следить за небольшими новостями по разработке, приглашаю в мой ТГ - там пишу о разработке и билд редактора будет.
Делал редактор для игры Wheel Balance, демо версия уже доступна. Релиз 25го июня.
Надеюсь этот материал будет кому-то полезен!