Bonjour. В последнее время всё больше и больше людей пишет о своих попытках вкатиться в геймдев или же о разработке игр сугубо для души. Вот и я решил запрыгнуть на этот хайп-трейн и рассказать о двух своих последних пет проектах, с помощью которых надеюсь получить достаточный опыт для устройства на работу в студию.
Чтож, с предисловием закончили. Поехали к сути.
Midnight Suns Project
Первым моим проектом стала попытка скопировать базу и скелет боевой системы "Marvel's Midnight Suns". Как по мне, крайне недооценённая игра. Интересная тактика, приправленная приятным визуалом, оказалась погребена под клеймом "Карточная помойка с мобилок". Ну ладно, не буду о грустном.
Первым делом я расчехлил свои сохранения и отыграл пару боёв, дабы выявить базовые элементы геймплея. Проведя глубочайшие исследования, я выявил следующие материалы для кальки:
- Навигация: Перемещение по арене с возможностью вращать камеру на 360°
- Карты: Визуализация и выбор навыков посредством карт
- Анимация: Проигрывание небольшой катсцены при использовании навыка
- Интерфейс
Я опущу душные и малоинтересные подробности о том, как пытался научить камеру вращаться, а персонажа бегать за мышкой. Вам ведь наверняка будет интереснее читать про страдания. Не так ли, маленькие садюги? Придётся подождать ещё немного, так как сейчас я хочу рассказать о логике, стоящей за картами и действиями юнитов.
Насколько мне известно, хорошим тоном в программировании является отделение данных от визуального представления. Корешками моей боевой системы выступают скилы, которые на старте боя создаются из шаблонов и закидываются в специальный контейнер. Скилы знают о том, как должны воздействовать на цель(нанести урон или исцелить), "количество" этого воздействия, по какому шаблону должен проходить выбор цели и сторону этой самой цели, а так же своё имя, описание, анимацию и прочие минорные вещи. Вершками же являются сами карты. Карты лишь отображают "цифры" скилла и никоим образом напрямую к нему не относятся.
Когда игрок щёлкает на понравившуюся ему карту отправляется событие, которое говорит нужному юниту, что был выбран скилл под таким-то индексом, игра же переходит в режим выбора цели. Приняв событие, персонаж рассчитывает расстояние, которое нужно пройти, чтобы добраться до цели, и закидывает действия "Движения" и "Применения скила" в специальную очередь выполнения. После выбора цели очередь выполнения начинает по порядку воплощать в жизнь все засунутые в неё инструкции. После опустошения очереди управление возвращается в руки игрока. Когда игроку надоест пинать болванчиков, ну или если у него кончатся очки действия, он должен передать ход противнику.
Ээээхххх… Противники. Приготовьтесь, сейчас будет очень сложное описание работы их искусственного интеллекта. Живём мы с вами в те времена, когда буквально за окном происходит бум искусственного интеллекта и нейросетей. Их развитие идёт семимильными шагами, и я не хотел отставать, а потому написал достаточно продвинутые алгоритмы поведения противников. В общем, враг атакует ближайшую цель…
Иногда я сам себя разочаровываю.
Ладно, я вроде как обещал страдания. Наступили они в тот момент, когда я работал над интерфейсом. В порядке бреда я решил сделать сегментированный счётчик энергии не набором отдельных кусочков, а шейдером. Тут стоит отметить, что это был мой первый опыт написания шейдеров. Вооружившись бутылкой и видеоуроками, я отправился покорять крепость под названием "ShaderGraph".
Через несколько десятков минут мой сегментированный кружок, переливающийся 50-тью оттенками жёлтого был готов. Сказать, что я был счастлив – не сказать ничего. Удивительно, как такие простые вещи, как градиентный кружок могут вызывать такие неподдельные и детские яркие эмоции. И тут вы зададитесь резонным вопросом, а где же обещанные страдания?
Через некоторое время, находясь в кураже от успеха моего прошлого опыта с шейдером, я решил самостоятельно сделать конусообразный шейдер, который должен был отображать радиус одного из алгоритмов выбора цели. Открыл я значит "ShaderGraph", нежно скопировал часть алгоритма построения круга, жёстко покрутил настройки, чтобы сделать его конусообразным, и успешно впал в ступор. Дело вот в чём, круг заполнялся, начиная с нуля градусов. Если выставить радиус конуса в 90°, то и круг будет заполнен на 90° и нужный мне "центр" будет находиться в точке 45°. Но мне-то нужно было, чтобы "центр" был в нуле. И тут началось веселье. Чего я только ни делал: пытался играться с дельтой разницы между радиусом конуса и нужного мне угла, пробовал домножать угол поворота на половину радиуса, менял алгоритм отрисовки круга, рисовал зеркальную копию круга, чтобы заполнять нужную мне половинку… Этот кошмар закончился только через несколько часов, когда я нашёл решение. Повернуть конус на 90°.
Я посмотрел на себя в отражении монитора, встал из-за стола, подошёл к окну, закурил… Много думал… Плакал…
Знаете, раньше я считал шейдеры чем-то магическим, неизведанным, таинственным и притягивающим. Однако реальность полна разочарований. Цитируя классика: "Это чистая математика". Перегон точек из одних координат в другие. Такова истинная суть шейдеров. Вот так, обременяя себя знаниями, разрушаешь свои надежды и мечты.
Вернёмся к проекту. Следующим шагом я решил реализовать небольшие катсценки, сопровождающие активацию скилла.
Работа над ними была достаточно весёлой. Активируешь нужные анимации, выставляешь нужные ракурсы камеры и настраиваешь переходы между ними, одним неосторожным движением руки удаляешь последние пол часа работы и в конце концов задаёшься вопросом: "А как собственно заставить противника получать урон в момент удара твоего подопечного?"
Мне в голову пришло три варианта решения проблемы:
- В скилле настраивать время, через которое произойдёт активация эффекта
- Использовать события, вызываемые в нужный кадр анимации
- Использовать события, вызываемые в нужный кадр катсцены
Я решил остановиться на последнем варианте. Катсцена откидывала событие о том, что на цель нужно воздействовать, а юнит, катсцена которого проигрывалась, принимал этот сигнал и решал, что делать дальше. И из-за этого, по неизвестным мне причинам, движок частенько кидал ошибки. При этом анимации и события работали как надо. Чудеса.
К этому моменту было реализовано почти всё, что я хотел. Персонажи передвигались и могли использовать скилы, замечательно работали ограничения на передвижение и использование карт, сами карты правильно отображались и "растягивались" по руке. Осталось добавить лишь частицы и, впервые в жизни, пост-процессинг.
Мой проект пользуется двумя системами частиц. Одна для ударов, вторая для лечения. Обе для придания навыкам импакта. Пост-процессинг же состоит лишь из блума, виньетки и контрастности.
Ну и на данный момент "Midnight Suns Project" выглядит вот так:
Tales of Copyright Project
Вторым и гораздо более серьёзным является проект, в котором я пытался скопировать боевую систему ранних игр серии "Tales of". Она мне казалась достаточно простой в реализации и невероятно интересной и динамичной в геймплее. "Простой в реализации…" Как же я ошибался. Ну и по уже сложившейся традиции я отправился игра… собирать информацию.
В процессе изучения я выделил несколько основных геймплейных моментов:
- По арене, вместе с персонажем игрока, перемещается "область" группы, в которую персонажи возвращаются после атаки или во время ожидания своего следующего действия
- Цепочки обычных атак состоят из максимум двух атак
- После завершения атаки юнит ненадолго оказывается в "замороженном" состоянии и не может двигаться и атаковать
- Своей целью, в основном, юниты выбирают ближайшего противника
- Подконтрольный игроку персонаж действует в полуавтоматическом режиме. То есть при нажатии на кнопку атаки персонаж сначала сближается с противником, затем наносит удар и после этого возвращается в "область" группы
Вооружившись бесплатными спрайтами из открытых источников, я отправился творить. У меня уже был достаточно обширный опыт работы с 2D проектами, а потому с базовыми управлением и перемещением проблем не возникло абсолютно никаких.
Ну ладно, не буду лукавить. Из-за того, что я попытался написать свой собственный аниматор для анимации персонажей, у меня появились небольшие графические проблемки.
Но не смотря на эту… "фичу", работа шла достаточно гладко. Я добавил возможность переключаться между членами группы, научил их драться, заставил двигаться камеру и добавил на поле боя приятный фон.
А потом пришла пора вдыхать в моих подопечных жизнь. Пришла пора учить их писать симфонию. Приготовьтесь, сейчас будет очень сложное описание работы их искусственного интеллекта.
На данный момент одним из самых популярных механизмов имитации интеллекта является "Behavior Tree"(Древо поведения). Древо состоит из множества нодов или ячеек, которые связаны друг с другом в нисходящем порядке. На картинке будет понятнее и нагляднее.
Ноды делятся на несколько основных групп:
- Корень: база всего древа, с которого начинается его работа
- Листья: именно эти ячейки и являются конкретными действиями обладателя интеллекта. Например, побежать в нужную точку или нанести удар
- Декораторы: такая надстройка над листьями, которая позволяет модифицировать их поведение. Например, выстрелить не один раз, а десять
- Селекторы: логический блок "ИЛИ". Решает в какую следующую ветку пойдёт обработка дерева. Например, выбирает какое использовать оружие, в зависимости от дистанции до цели
- Секвенции: логический блок "И". Последовательно выполняет все действия из своей ветки. Например, юнит подбегает к цели → юнит атакует цель → юнит отбегает от цели
Это только основные и самые широко использующиеся ячейки. В зависимости от проекта могут добавляться какие-то специфические модификации этих нодов. Так же у древа есть "Blackboard", в котором хранятся важные для принятия решений данные. Например, цель и дистанция до неё, ближайшее укрытие, точки интереса и т.д.
"Древа поведения" так распространены из-за того, что являются довольно гибкими и позволяют с лёгкостью изменять поведение условного юнита, ячейки можно активно перемещать внутри одного древа и использовать в другом, ну и напоследок, древо позволяет экономить память. О последнем чуть подробнее.
Искусственный интеллект можно реализовать и с помощью "State Machine". Грубо говоря, всё поведение юнита разделяется на "состояния". Например, "Преследует цель" или "Атакует цель". Активное состояние обрабатываются каждый кадр, что достаточно сильно бьёт по производительности, особенно если состояния являются достаточно комплексными. "Древо поведения" же позволяет запомнить конкретную ветку и, грубо говоря, единовременно обрабатывать лишь один "лист", что благоприятно сказывается на использовании ресурсов компьютера.
Ладно, закончим с духотой и перейдём к веселью. В "Unreal Engine" есть встроенные инструменты создания и редактирования "Деревьев поведения". Однако я работал на царском "Unity" и мне пришлось писать расширение редактора, которое позволило бы мне с удобством и радостью работать с ячейками древа. Как же хорошо, что на просторах интернета есть YouTube, в котором можно найти видосы по разработке практически чего угодно.
Я даже не буду пытаться объяснить, как работает отображение этого графа, т.к. сам его не до конца понимаю. Самое главное, что эта магия позволяет мне не без проблем работать с интеллектом подконтрольных болванов.
Для начала я научил их косплеить JoJo.
Затем они возомнили себя пружинками.
А под конец вовсе обзавелись разумом роя.
Однако я не сдался и уже через некоторое время система автоматического боя была готова.
Не уровень "F.E.A.R" конечно, но тоже не плохо. Юниты могут выбирать цель, оценивать расстояние до неё, атаковать, получать урон и умирать. Подконтрольный игроку персонаж может действовать в двух режимах: на автопилоте и в полуавтоматическом. Полуавтомат работает так же, как и автомат, вот только обновление древа происходит не по таймеру, а по вводу игрока.
В целом, я был рад проделанной работой. Однако мозгу требовался отдых, и я решил добавить в проект чисто номинальные "Режим исследования" и "Режим диалога". В первом режиме игрок бегает по открытому полу и наслаждается его красотами. Второй же режим радует пользователя глубочайшими и философскими беседами с деревянной табличкой.
В принципе, всё что я хотел реализовать в прототипе уже было готово. Конечно были ещё геймплейные фичи, которые я так и не воплотил в жизнь, но никаких сил не осталось. Смог добавить лишь пару аудиальных штришков. Режим исследования начал сопровождаться композицией "The Second Act" из "Tales of Phantasia", а дополнительную динамику бою придавала "Take Up The Cross" из той же игры. Для озвучки трёх моих персонажей я позвал известных профессионалов. Xander Mobus, Robbie Daymond и Max Mittelman с радостью подарили свои голоса персонажам моего пет проекта. Ну или я просто взял их "Ngh" из "Persona 5". С этими небольшими улучшениями я закончил работу.
Ну и на данный момент "Tales of Copyright Project" выглядит вот так:
Заключение
Ну что, ребят. Вот и подходит к концу мой рассказ. Над "Midnight Suns Project" я работал около двух недель по три четыре-часа в день. "Tales of Copyright" занял у меня уже чуть больше месяца. С такими темпами не знаю даже, когда смогу достичь того уровня просветления, который позволит мне устроиться на работу в студию разработки игр. Если ты, дорогой читатель, добрался до этой строчки и работаешь разработчиком игр, то напиши в комментариях о своём пути. С чего начинал, какими навыками овладел и как попал на эту галеру. Уверен, что не только мне, но и другим людям, желающим попасть в геймдев будет интересно почитать небольшую автобиографию и почерпнуть из неё важную информацию. Ну а я озвучу лишь одну финальную мысль.
Работать в одиночку ужасно тяжело. Каждый раз, когда не получается реализовать какую-ту интересную задумку появляется желание опустить руки. Рядом нет никого, кто мог бы поддержать и подсказать, в каком направлении стоит думать. Нет никого, кто был бы так же увлечён проектом и подталкивал к его развитию и завершению. Однако… Однако несмотря на все трудности я не намерен сдаваться. Всеми силами я буду стремиться к тому, чтобы в один день увидеть своё имя в титрах прекрасной игры.
Автор: Gryis
Оригинал: Сказание о двух прототипах игр