Я «обычный» энтерпрайз программист, но недавно попробовал силы в Epic Mega Jam 2023. Опыт получился яркий, эмоциональный. Сразу захотелось поделиться. Вероятно, профессионал прочитает статью с рукой у лица, если вообще будет читать. Но текст больше для тех из нас, кто занят в смежных индустриях и неравнодушен к играм.
До этого имел некоторый опыт с Unity примерно в 2015, а позже, в 2018, делал небольшую 2D игру на LibGDX, это небольшой движок на Java. Java — мой основной язык, было интересно оценить знакомый инструмент в новом амплуа. Долго искал повод познакомиться с двигателем Unreal Engine, еще с появления Unreal Development Kit, да все как-то было не с руки.
В назначенный час посмотрел трансляцию, в которой раскрыли правила, специальные категории, критерии оценки и призы, конечно.
Стала известна тема: Antiquated future, «устаревшее будущее».
День 1: Поиск идеи
Сделал майнд-карту, стал писать что в голову взбредет.
Лично у меня «устаревшее будущее» моментально дает ассоциацию на стим- дизель- и прочие панки. Сперва в голову приходит именно сеттинг. Получается, задаем сеттинг и делаем игру в любом жанре? Может, и так, но мне показалось скучно.
Разнёс идеи: влево то что нравится меньше, вправо, то, что нравится больше.
Справа оказались идеи, которые связаны с парадоксами теории относительности. Вроде как, можно перепутать очередность событий, как в парадоксе шеста и сарая. Вот только как это превратить в игру, еще и за неделю?
Вооружившись карандашом и бумагой, стал думать, как это будет выглядеть в игре.
Суммарно пришел к такой идее:
Акт 1: Страшная опасность® нависла над солнечной системой, надо срочно разогнаться до околосветовой скорости. В этот момент откроется червоточина в прошлое, где...
Акт 2: ...собираем убер артефакт или энергию.
Акт 3. Пытаемся вернуться в свое время. Должна быть возможность промахнуться, тогда — на следующий круг.
День 2: Страх чистого листа
Открыл редактор, не знал, с чего начать. Это оказалось сложнее, чем с другими проектами из-за около нулевого количества знаний о предмете.
Ступор закончился только когда нашел подходящие видеоуроки, как раз о создании космо-симулятора. Unreal Engine 4 предлагал шаблон Flying Game, но в пятой версии его нет и я узнал о нем слишком поздно. Теперь понимаю, что делать, прохожу уроки, тревожность уменьшилась.
Блюпринты понравились, я хотел их попробовать для общего развития, плюс понять, советовать или нет знакомым-непрограммистам.
День 3: Адаптация
После курса первым делом сделал сам космос, скайсферу. Поиск вывел на видеоуроки по бесплатной программе Spacescape, которая заточена под создание таких текстур.
Как только уроки закончились, тревожность снова выросла — ничего не получается.
Разбираюсь, как:
Разогнать корабль до 99% скорости света, но не больше;
Замедлять разгон к концу;
Увеличивать мощность по мере сбора ресурсов.
Математику помню не очень хорошо, экспериментировал с графиками функций в Wolfram Alpha с подсказками от ChatGPT. Идея в том, что Linear Damping, далее буду называть его «торможение», растет до бесконечности при приближении к скорости света, т. е. скорость света — асимптота. Попутно поменял физику корабля на более «космическую», т. е., разогнались — и не тормозим, атмосферы-то нет.
День 4: Твердь
Обнаружил, что после изменений физики крайне сложно собирать ресурсы, на нужное место просто не попасть, проносит мимо. Из механик управления кораблём лучше всего подошла бы подобная Outer Wilds, но времени на этот этап не осталось, работаю с тем, что есть.
Для космического сеттинга нужны звезды, планеты, астероиды и фон. Фон уже готов, добавим планеты, для начала — как визуальное наполнение-ориентир, где искать ресурсы. Я не первый с такой задачей, есть много инструкций. Планета получается живая, облака летают. Понравился редактор материалов, выглядит как те же блюпринты, все элементы и взаимосвязи на виду. Чтобы легче было затормозить у планеты, сделал поле «притяжения» планеты, по свойствам — атмосферу. Корабль попадает внутрь, у него повышается торможение.
Столкнулся с ситуацией: повторяю действия из урока один к одному, в оригинале — работает, у меня — нет. Переделывал раза три, помог перезапуск редактора. Я только руками развёл. Неделя работы в Unreal Engine 5.3 показала, что инструмент надежный, но иногда вылетает с ошибкой или ведет себя неожиданным образом. Никаких претензий — софт настолько сложный, что сделать его абсолютно надежным невозможно. Особенно, постоянно добавляя новую функциональность, как Nanite.
День 5: Время разбрасывать камни
Вокруг планеты пусть крутятся астероиды. Мне они очень нравятся, как видно из предыдущего опыта с LibGDX.
Нашел мануал, как создать много случайно раскиданных астероидов с помощью Instanced Static Mesh — такая штука, которая добавляет кучу экземпляров одной модели, при этом экономит ресурсы. Результат, в статике выглядит так, как и задумывалось. Сам булыжник взял из библиотеки Quixel Megascans, бесплатной для использования в Unreal Engine.
Теперь анимация, астероиды должны вращаться. Вместе, по орбите, вращать получается, но не по отдельности. Снова нашел видео, статьи на форуме, но так и не заработало. Ещё минус 3 часа, астероиды астероиды вращаются, но... Прокрутившись пол-оборота, астероиды замирали. Причиной оказался покадровый инкремент Rotator, максимальное значение которого — 360. Городить деление с остатком не пришлось, решением стало использование функции Combine Rotators.
Для взаимодействия с конкретными объектами в сцене должен быть способ поместить ссылку на объект в переменную. Окей, гугл, ищем инструкцию. В блюпринте создаем переменную нужного типа, выбираем для нее объект по умолчанию. Но при типе переменной «Object Reference» выбор объекта в выпадающем списке недоступен. Получилось при типе переменной «Soft Object Reference». Это, как я понял, связано с очередностью создания объектов, если нет — поправьте, пожалуйста.
Планеты для сбора ресурсов разнес подальше, чтобы добавить разгон и торможение. Теперь их не видно, непонятно, куда лететь.
Пора зажигать звёзды. Добавляю сферу, накладываю материал с текстурой солнца. Выкрутил яркость свечения материала, рядом летать теперь сложно, аж глаза жжёт, но пусть игрок страдает.
День 6: Засада с коллизиями, удаление главного блюпринта
Стало понятно, что на второй и третий акты времени нет, и то придётся сильно сокращать. Концом первого акта становится появление червоточины и пролет сквозь нее на следующий уровень. По задумке, это происходит на околосветовой скорости. То есть, нужно создать объект перед игроком и ускорить в соответствующем направлении, иначе игрок не успеет ничего заметить, скорость света, ага. Как получать направление уже понятно из работы над кораблем, да и вектора с поворотами вспомнились по Unity. Создавать объекты из блюпринта оказалось несложно. Для отладки сделал себе спаун по средней кнопке мыши и так и забыл отключить.
Hidden text
Пытался в 2006-м крутить координаты матрицами на паскале, не получилось. Лет через 5 после этого читал статью на хабре, и «щелкнуло» — понял! Но исходники уже потерял и паскаль в принципе трогать расхотелось.
Далее импульс, берем скорость корабля и даем ускорение свеженькой червоточине. Скорость корабля умножаем на 1.0001, чтобы появившись, она чуть помедлила, и «наползла» на корабль. Поставил торможение у червоточины чуть повыше, чем у корабля, чтобы её можно было догнать.
Теперь дело за малым, получить событие пересечения объекта кораблем. Это несложно, так как уже знакомо по сбору ресурсов. Запускаю, не срабатывает. Нет пересечения. Или есть, но сразу при создании объекта... Потратив четыре часа и перепробовав десятки комбинаций, получил-таки нужное поведение. Использовал специальный канал (Object Channel), для фильтрации событий. Без этого работал или импульс, или пересечение.
В один «прекрасный» момент удалял лишний узел из блюпринта. Не знаю, как, но удалился сам главный блюпринт! Систему контроля версий для джема решил не использовать из-за недостатка времени, чтобы не разбираться с Git LFS или, тем более, Perforce. Бэкап делал 2 дня назад. Супер. В корзине нет. Пытаюсь восстановить восстановителями файлов — нету файла, причем, другой удаленный — находит и восстанавливает. Возможно, глюкануло на уровне файловой системы или самого SSD.
Уже смирившись, пошел искать в папке проекта. Автосейвы, по умолчанию сохраняют последние 10 изменений в папке Saved проекта... Пошел пить валерьянку (нет, конечно, еще кофе).
День 7. Время собирать камни
В последний день добавил заглушку на второй уровень с описанием идеи и занялся UI и звуком. С текстом и парой кнопок настройки проблем не возникло. Часов до семи вечера завершил работу над геймплеем и протестировал билд.
Отправил брату, он тоже протестировал, попросил добавить третью звезду и сделать их разного цвета. Ось Y в управлении инвертировать и поменять реверс на «тормоз», а то сложно долететь до планеты, слишком велика инерция. Первые две вещи сделал, инверсию оси вывел на отдельную кнопку, теперь каждый может летать как ему привычнее. А вот реверс оставил, если без текущей механики, то совсем челлендж пропадает. Только увеличил поле притяжения планеты в три раза как быстрое решение. Изначально хотел добавить поле притяжения звезды, послабее, но большее.
Нужна модель корабля, так как до этого использовалась чужая. Пару раз запускал Blender до этого, он установлен, попробуем. Открываю, в голове пусто — совершенно не помню, что тут делать. Окей, запасной вариант. Веб-версия SketchUp, я там домик себе проектировал. Снова не получается, эмоциональный перегруз. Вздохнув, открываю пыльную виртуальную машину с 3д пакетом 20-летней давности.
С закрытыми глазами, как на велосипеде — замкнутая кривая, выдавить в объем, отзеркалить, чуть подвигать грани — летающий кирпич готов. Отдельными элементами сделал двигатели и вкладыши в них. Вкладыши нужны, чтобы легче было назначить материал включенного двигателя. Ну не знаю, как это делать с цельной моделью, времени разбираться — ну совсем нет. Экспортирую в FBX, Unreal загружает все в ИКЕА-формате, т. е., отдельными элементами. Еще полчаса-час, плюнул, соединил всё кроме вкладышей двигателей в одну модель, вручную расположил внутри Viewport корабельного блюпринта, назначил материалы, чуть подвигал ускорители (Physics Thruster Component) — кирпич полетел. Отлично, тестируем. Тааак, снова появились проблемы с коллизиями, а времени до дедлайна 7 часов. Вместо одного события сбора ресурса у теперь три. Ну конечно, корабль + два элемента двигателя. Отключаю коллизии — сбор налаживается, как положено — одно событие на все.
Остался звук. В описании джема нахожу пару сервисов-спонсоров, один дал скачать пак звуков, второй предлагает посмотреть онлайн. Потратил на подбор 10 минут — цейтнот, а ведь планировал как минимум день на звук отвести. Материалы о разработке игр транслируют идею, что звук — чуть ли не половина ощущений в игре. А я очень ценю хороший звук, но не судьба. Настроил за час, качество — по принципу «хоть какой-то звук лучше, чем никакого».
Hidden text
18 лет назад озвучивал пролетающий космический корабль (в вакууме, конечно) пылесосом. Найти не смог, увы.
Итак, 2 ночи, вроде закончил. Со вздохом облегчения запускаю билд... Возникла неизвестная ошибка. ЧТО?! Перезапуски, перезагрузки, поиск, чтение логов. Проблема с версией MSBuild. Видимо, ставил софт для моделирования и поломал. Обновил в Visual Studio Installer — заработало, выдохнул.
Собрал, проверил, прошел. Работает. Осталось разобраться, как отправить. Тут почти не возникло проблем. Сделал описание, страничку, архив и т. д. Пару скриншотов. Короткий ролик на YouTube 30-60 секунд — без проблем, полетал, записал через встроенный в Windows оверлей Xbox. Пользовался им для записи с экрана много раз, но этот раз — особенный. Поэтому видео появляется как черный квадрат, в котором половина экрана от левого верхнего угла занята самим видео. Не понял причин, обрезал в видеоредакторе. Получилось криво, но мне уже всё равно, четвертый час ночи. В итоге требования по отправке заявки выполнил в 3:40. Можно поспать.
Эпилог
Участие в джеме оказалось приятным, драйвовым, эскапирующим опытом, выключающим на время из бытовых дел, глобальных вопросов и рефлексии.
Чуда не случилось, сделать в одиночку «Интерстеллар» за 7 дней не вышло. Советов по участию в геймджемах давать не буду, их и так полно в интернете.
Блюпринты предлагаю попробовать всем, классная штука. Сам в следующий раз возьмусь делать на C++. Unreal Engine использует сборщик мусора — надеюсь, будет понятно джависту.