Разработка ремейка методами чайника 6. Пушки и система повреждений
Добро пожаловать в новую часть еженедельного цикла статей о разработке лайт-ремейка легендарной серии игр Корсары. В прошлой статье я обещал заняться логикой пушек, и всего что с этим связано. Собственно сказано - сделано… ну как сделано… делается. И собственно о процессе разработки этого компонента игры и пойдет речь!
Единственное что, по мне сильно ударило то, что мой проект сравнили со Skull and Bones! Я целых 15 минут “кашлял кровью” от такого оскорбления!
Концепт
Кто играл в оригинальную игру, знает, что для выстрела по противнику игроку достаточно просто направить нужную часть корабля в сторону вражеского корабля и приказать сделать выстрел. После этого будет произведен выстрел с учетом направления движения и скорости. Но возникают случаи, когда мы не можем доверить компьютеру решать какой корабль более приоритетная цель. Для таких ситуаций применяется так называемый “капитанский” режим. В нем, камера перемещается на палубу корабля, и мы получаем возможность выбрать направление для запуска снарядов. Также необходимо учитывать расстояние до цели и подбирать подходящую высоту, благо игра подсказывает какая высота будет оптимальной.
Что мне не нравится в системе оригинала, так это то, как ручная наводка реализована. Мне приходилось прямо в разгар сражения снижать скорость игры, переключаться в другой режим, доходить до середины палубы чтобы лучше чувствовать выбранное направление, затем тратить несколько секунд на подбор высоты… В общем это совершенно ломает динамику игры, и хотелось бы увидеть что-то похожее на систему наводки из BF(Black Flag).
Впрочем возможно стоит оставить логику перемещения по кораблю не столько для геймплейной части, сколько для получения иммерсивного опыта. Но в таком случае, скорее всего вид “от первого лица” лучше заменить на полноценного персонажа… но в таком случае непонятно как поступать в случае попадания ядра по персонажу… В общем тут довольно спорный момент, и наверное его лучше обсуждать с комьюнити.
Таким образом, я принял решение оставить логику авто-стрельбы по противнику неизменной, а логику ручной наводки привести к реализации из BF.
Поиск решения для подбора траектории пушечного ядра
Сложно найти то, что ты не знаешь как называется. Даже если нужный тебе термин проскакивает в источниках которые ты изучаешь, далеко не факт что твой взгляд за него зацепится, и ты пойдешь гуглить информацию именно по нему. Так и получилось со мной, изучая информацию как бросить объект в определенную точку, я натыкался лишь на размытые мысли и слово “projectile”(ну а чего еще ожидать от размытого поискового запроса). И вот в определенный чудесный момент я вышел на это видео. Автор рассказывает как можно реализовать логику с предпросмотром траектории как в BF. Это конечно хорошо, но ручная наводка - лишь вспомогательная функция, да и AI должен будет наводиться автоматически. Поэтому нужно либо думать как переделать код на автоматический подбор вектора траектории, либо искать другое решение.
После изучения этого видео, получаем новую ветку для изучения - “projectile prediction”, и выходим в открытый интернет:
В общем, стало понятно, что с моими знаниями нужно искать реализацию непосредственно для UE, и я решил немного поиграться с новомодным ChatGPT. Указав что мне нужно, я попросил его расписать логику Blueprint-а. Как и ожидалось от передовой нейросети самого Илона, она дала мне ответ какие функции использовать и какие операции с векторами производить. Но вот только одна проблемка есть… то что она предложила - работало неправильно, у вектора получалась слишком большая сила, и шар улетал в соседнее село на сверхзвуковой скорости. Я разумеется просил её пофиксить эту проблему, но решения я так и не получил.
В общем покопавшись еще, я нашел статьи с ручным расчетом необходимого мне вектора, но мне было очень лень все это делать. Неужели в таком крутом движке нет нужной мне функции из коробки? Чисто из любопытства я ввел в поиске функций ключевое слово projectile, и нашел её: SuggestProjectileVelocity! Задаешь куда надо попасть, скорость снаряда, и она просто выдает тебе нужный вектор! Я решил посмотрел как её реализовывают другие разработчики, и вышел на видео, где еще и объясняют как сделать учет траектории движения цели. Отлично, можно приступать к написанию кода!
Реализация стрельбы из пушек
Тут все достаточно просто: пушки у нас помечены сокетами с префиксами “cannonl__”, “cannonr__” и т.д. Все что нам нужно, это их всех перебрать при инициализации, и распределить между группами переменных отвечающих за направление. Затем проверяем есть ли вражеские корабли в пределах зоны досягаемости, и если есть, то выбираем нужную группу переменных с пушками и делаем выстрел. Это все в общем-то неинтересно, интересно другое…
Если делать выстрел сразу всеми пушками, то выглядеть это будет неестественно, поэтому я решил сделать рандомную задержку выстрела для каждой пушки, и тут началось. Почему то, когда я ставил таймер на событие выстрела, по итогу стреляла только одна пушка. Оказалось, что UE перетирает таймеры, и запустить несколько инстансов в рамках одного актора - не получиться. Разумеется, для обхода данного недоразумения, сообществом разработчиков была реализована костылина! Под каждый таймер создается отдельный актор, который запускает в себе таймер, и по его окончании отправляет событие своему создателю и самозабвенно умирает.
Пока что не навешивал таймеров перезарядки, и не добавлял визуальных эффектов вроде дыма и всплесков воды. Все визуальные эффекты будут покрыты специальным плагином, когда у него появится официальная интеграция с Oceanology(да и жабка за 170 бачей пока что поддушивает…).
Система повреждений
И так, у нас теперь есть стрельба, но нет никаких эффектов от попадания по кораблю. И если реализовать отметину от попадания на корпусе - не проблема, то вот как реализовать порванные от ядер паруса? Пока я разрабатывал паруса, я немного разобрался с логикой текстурирования материала, и способами добавления прозрачности на него. Оставался только вопрос, как нарисовать зону прозрачности в нужной точке паруса. В процессе поиска я вышел на функцию “Find collision UV”, которая возвращает позицию на текстуре, в которую было произведено попадание. Казалось бы, дальше дело техники, но… UE постучалась, и сказала что со Skeletal Mesh эта функция больше не работает “By Design”...
Продолжая искать варианты решения задачи, я вышел на видео о рантайм рисовании на скелетной модели. Да благословят богини этого паренька, за то, что он разместил проект с примером в открытом доступе! Работает эта логика очень интересно, если не сказать костыльно, поэтому советую с ней ознакомиться.
Загружаем в проект нашу модельку паруса, вносим минорные правки в код, чтобы вместо краски мы наносили прозрачность и дело в шляпе!
Но решив включить морф симуляции ветра, я почти полностью потерял возможность рисовать прозрачность на парусе. При чем только на местах деформации, статичные части паруса по прежнему нормально рисуются.
Решив протестировать аналогичную логику через WPO(World Position Offset) в текстуре, я такой проблемы уже не наблюдал, но возникло странное смещение относительно моего выстрела. Если пострелять по парусу сбоку, становиться очевидно - проблема в коллизии.
Проблемы с коллизией паруса
Внимание вопрос: как заставить коллизию учитывать деформацию через морф таргеты или WPO? Ответ: никак! На этом можно заканчивать разработку игры. Спасибо что читали эти бесполезные статьи!
У скелетной модели нельзя привязать коллизию к конкретным вершинам, только к костям. Соответственно, нужно сделать так, чтобы вершины были закреплены за костями, и кости перемещались вместе с деформацией. На просторах ютуба я видел пример, как можно скопировать симуляцию ткани через расположение костей под каждую вершину в блендере. Я конечно очень возмущен, что мне снова приходиться к этому возвращаться, но благо с наработанным опытом, это было уже не так муторно как в первые разы.
Импортируем модель и анимации в UE, создаем физическую оболочку, и получаем ЭТО…
Почти 500 боксов с коллизиями роняют фпс до неадекватно низких значений. Ну может это только в редакторе так, и в игре проблем не будет? Разместив объект на карте, я действительно не заметил дропов фпс. До тех пор пока не выстрелил…
В общем стало очевидно что коллизию нужно делать условно на каждую 5-ю, если не 10-ю кость. Но через редактор UE это быстро не сделать под несколько сотен парусов… Возможно получится объединить морф таргеты с костями в одну анимацию, и тогда не будет такого перегруза. Но история об этом будет уже в следующей статье.
Мешаем анимации
Как вы должны помнить, мне очень важно чтобы у меня была возможность смешивать анимацию поднятия/спуска паруса с морфом силы ветра. Если этого не делать, то из-за специфики размещения парусов, они будут проходить сквозь мачты, что с учетом коллизии, может привести к очень неожиданным последствиям в виде летающего по карте корабля.
Был большой вопрос: как написать Animation Blueprint так, чтобы он делал смешивание правильно, и у меня была легкая возможность менять анимации для разных парусов. И этим вопросом разумеется задавался не только я, и в ответах до 2021 года говорилось, что нельзя сделать абстракцию для разных анимаций. Но к счастью, в 5.0 для этого были созданы шаблоны. И с помощью переменных можно указывать анимации которые ты хочешь использовать. Вот тестовый пример:
К следующей статье я планирую доделать логику повреждения парусов, добавить звуковых и визуальных эффектов при столкновении ядра с поверхностью. А также добавлю ручное управление стрельбой в нужном направлении. А на сегодня с меня хватит…!
Если вам понравилась статья, то буду благодарен за ваши комментарии, вопросы или советы!
Ну хоть кто-то решил доделать Skull n Bones...
БАН
Так может не гнаться за реализмом, а сделать несколько вариантов текстуры с различными степенями дырявости и между ними переключаться при достижении некоторого порога урона?
В разработке данного ремейка у меня есть принцип - как минимум повторить логику из оригинальной игры. А в оригинальной игре, парус рвется именно там, куда по нему попали.
Правда там еще есть маска с участками которые нельзя порвать, чтобы парус не висел в воздухе аномально. Но это уже мелочи.
Чел, если ты таки сделаешь игру, то я буду первым покупателем.
До сих пор жду игру по пиратам на мотив Корсаров.
Вода просто ахуй
Продолжай в том же духе и не сдавайся , ты красавчик , спасибо за надежду свежего глотка воздуха в этот пиратский шедевр