История спасенного времени
Каждый уровень игры Spreadstorm состоит из небольших элементов, которые мы называем "узлами". Узлы связаны между собой и у каждого узла может быть не больше 4 соединений, что представляет собой довольно простой граф. Игроки могут перемещаться по узлам и взаимодействовать с некоторыми из них. Самый маленький, первый уровень в игре состоит из 22 узлов.
Когда работа над проектом только началась, стало очевидно, что расставлять каждый узел вручную в редакторе Unity и указывать каждую связь с соседями будет мучительно долго и непродуктивно.
К счастью, буквально первая глава книги "Game Programming Gems" дает два совета:
- отделяйте данные от поведения в своей игре;
- выносите отделенные данные в текстовые файлы, чтобы иметь возможность быстро их менять и играться с параметрами.
Воспользовавшись советом, был изобретен JSON-формат данных, который описывал уровень игры, каждый узел, соединения между ними и возможные взаимодействия, доступные игроку.
При запуске, игра загружает файл с описанием уровня, парсит файл с помощью Newtonsoft.JSON, конвертируя его во внутреннюю структуру игры, и далее генерирует по внутренней структуре уровень. Это была своего рода победа, потому что такой способ довольно-таки неплохо работал, позволял производить быстрые изменения и немедленно получать результат, но к примеру, файл с описанием первого уровня состоял из 112 строк.
С использованием текстовых файлов уровни создавались быстрее, потому что ты мог копировать повторяющиеся части описания и быстро вносить в них изменения. Но возникла другая проблема: ошибки. При любом, даже самом маленьком изменении возникала вероятность возникновения ошибки. Ты забыл изменить параметр, скопировал лишнее, недокопировал нужное - и уровень генерируется некорректно или игра вообще не запускается. И чтобы найти и исправить такую ошибку, требовалось невероятное количество времени. К тому же создание файла уровня с 50+ узлами копипастой было тоже достаточно медленным процессом.
Мы создали пять уровней, используя этот подход, и решили двигаться в сторону создания хотя бы простейшего варианта редактора уровней, который выглядел примерно так:
С его помощью можно было создавать узлы, соединять их, перемещать, изменять их тип и редактор уровня генерировал файл, который потом использовался игрой, чтобы сгенерировать уровень.
Тем не менее с этой версией редактора было тоже большое количество проблем. Он мог генерировать только структуру уровня, но другие вещи, как взаимодействия, враги, модули должны были вноситься в файл вручную (привет ошибки!). Да и структура создавалась не самым удобным образом. Ты должен был ввести штук пять параметров, чтобы получить простую линию из узлов. И если в процессе допускалась ошибка (например, случайно удалил не тот узел), то отменить действие не было возможности.
После того, как файл был завершен мы должны были его импортировать в движок, сгенерировать уровень, разместить освещение, декорации, все это запечь, протестировать и повторить по новой, если нужно внести какие-либо изменения. Несмотря на это, было создано 25 уровней, используя этот "Кусок инструмента".
Игра успешно вышла в Раннем доступе в Стиме и настала пора задуматься о создании нормальной версии редактора уровней, которая бы:
- давала бы возможность делать Undo и Redo любой операции;
- делала процесс максимально простым;
- избавляла от необходимости лезть в текстовые файлы по любому поводу и без;
- позволяла бы немедленно тестировать созданный уровень.
С Undo и Redo оказалось меньше всего проблем. Ты просто берешь замечательный паттерн проектирования Command и оборачиваешь в него все возможные операции редактора. И все магическим образом начинает работать.
Реализация возможности быстро тестировать созданные уровни была еще проще. По нажатию кнопки "Плейтест", ты просто сохраняешь результаты работы в файл, после чего этот файл загружается игрой, как это было раньше, только вместе со специальной сценой, в которой не содержится ни декораций, ни освещения.
А вот перенос всех возможностей игры в редактор вместе с упрощением процесса создания уровней отняли почти два месяца разработки. По большей части это был довольно рутинный процесс, прерываемый переосмыслением структуры некоторых элементов игры.
Однако результат полностью оправдал все ожидания. Если раньше создание одного простейшего уровня занимало добрых четыре часа времени, и изменения в него вносились потом с трудом, то с новым редактором уровень создавался буквально за минуты. И все остальное время можно было плейтестить и полировать уровень, доводя его до совершенства. Изменение параметров отдельных узлов получало немедленный визуальный фидбэк, что превратило создание уровней в приятный и интересный процесс. И даже добавление новых механик и типов узлов, несмотря на возросшее количество программирования (нужно запрограммировать поведение для игры и интерфейсы для редактора), стало происходить быстрее, так как уже в редакторе ты мог сразу посмотреть, как они работают.
Стоило ли сделать редактор раньше? И да, и нет. Да — потому что было потрачено гигантское количество времени на создание уровней вручную. Нет — так как редактор проще делать для состоявшейся игры и механик, которые точно в ней останутся и будут несильно меняться. Да и понять, какие процессы нужно хорошо оптимизировать, лучше всего после того, как ты немного пострадал.
Мораль истории такова: если вы чувствуете, что какой-то процесс достаточно рутинный и отнимает у вас все больше и больше времени, надо не бояться остановиться и потратить время на его оптимизацию.
И под конец небольшое видео о том, как сейчас выглядит процесс создания уровня для игры Spreadstorm: