Разработка ремейка методами чайника 8. Система построения маршрута и ИИ

Приветствую, дамы и господа! В новой, несколько затянувшейся, главе саги о создании своих Корсаров мечты, я расскажу о нюансах построения маршрута и перемещению кораблей по нему. Затем проведу вас по глубокой, темной реализации ИИ перемещения и сражения с враждебными судами. А так-же, поведаю о моей реакции на ремейк от Мариусов(если это мнение вообще кого-то интересует).

Маршрут перестроен

Возможность указывать кораблю-компаньону куда плыть, за кем следовать, кого брать на абордаж - очень важна. Но для этих функций ему необходимо знать по какому маршруту достигать цели. Можно направлять корабль напрямик и предохранять его от столкновения с помощью проверки препятствий на пути. Но тогда ИИ может заблудиться в трех бухтах и переломать себе все мачты, как это было в оригинальной игре. Таким образом, наиболее логичным было бы построить для него маршрут с учетом препятствий.

В UE есть много готовых решений, которые разумеется с кораблями из коробки не работают. Например для того чтобы построить маршрут сухопутной крысе, достаточно всего лишь разметить игровую область как проходимую, вызвать ноду Move To, и человечек бодренько автоматически отправиться в указанную область. Но человечку хорошо, он может двигаться в любом направлении под любым углом из любой позиции, а как быть кораблю…? Мало того, что корабль не способен правильно перемещаться с помощью Move To, так еще и не понятно как для него разметить зоны проходимости, ведь вода не может быть размечена соответствующим инструментом.

Понасиловав свой мозг и не найдя ответа, я смог откопать чуть ли не единственный гайд на эту тему. Первое что необходимо сделать - создать навигационную сетку под водой, а затем спроецировать на ней положение корабля. Делается это простым Line Trace-ом и выглядит следующим образом:

Теперь, когда у нас есть точки на навигационной сетке, мы можем построить на ней маршрут через ноду Find Path To Location Synchronously:

Точки кривой - это результат вышеописанной ноды.
Точки кривой - это результат вышеописанной ноды.

Круто, у нас теперь есть маршрут! Может по этому гайду еще получится научить корабль по нему плыть? Вообще да, но нет. В примере не учитывается допустимая маневренность и ускорение, а куда нормальный ИИ без этого…? Если немного подумать, то эта проблема распространяется не только на корабли, почему бы не взглянуть как с этим справляются разработчики автосимов.

К счастью, в отличии от кораблей, для машин есть много гайдов, в том числе и с использованием нейронок. Но нейронки слишком непредсказуемые, поэтому остановимся на чем нибудь попроще. Например на вот этом гайде, описывающем способ перемещения автомобиля с помощью функций пользовательского импута, а не прямого изменения значений координат положения и вращения.

Решение хорошее, но например у меня возникли проблемы с непоследовательным выбором точек назначения. Вариант из этого <a href="https://www.youtube.com/watch?v=ICXrV9IXDVg&amp;list=PLSc29g4OjKUNImPwDA4S2B8lr-xX3zpax&amp;index=1" rel="nofollow noreferrer noopener" target="_blank">видео </a>отработал в этом плане надежнее.
Решение хорошее, но например у меня возникли проблемы с непоследовательным выбором точек назначения. Вариант из этого видео отработал в этом плане надежнее.

К сожалению, во всех примерах что мне встречались, транспорт передвигался с фиксированной, заведомо “идеальной” скоростью для вписывания в повороты. Но не буду же я корабли на боевом парусе вечно держать? В идеале, мне нужно смотреть на градус следующей точки, и в зависимости от этого заблаговременно сбрасывать скорость. Но мне лень (¬ ¬ ). Так что я просто завязался на показатель требуемого поворота руля чтобы вписаться в кривую, и в зависимости от величины этого показателя - переключаю паруса. Разумеется таким образом, корабль имеет все шансы столкнуться со стеной, так что я также добавил систему проверки препятствий прямо по курсу, чтобы паруса как минимум спускались в таком случае. А еще проблему усугубляет то, что система построения маршрута UE ставит точки прямо возле стен, из-за чего корабль так и норовит выйти за пределы навигационной сетки, и начинает теряться до тех пор, пока в неё не вернется. В общем проблем хватает, и на текущий момент оно работает вот так:

Криво-косо, зато работает ╮( ̄ω ̄;)╭ Ах да, скорость x3, поэтому шум моря в черти что превратился, берегите уши.

Еще в этот блок должны были попасть мои мучения с попыткой научить корабли не ходить против ветра с помощью NavModifier, но нормально это запустить у меня не получилось. Да и в целом выглядит логичнее как-то покрутить построенную кривую, чем перестраивать навигационную сетку под каждый корабль в мире. Но я решил что это то, чем можно пренебречь в супер альфа-демо-тестовой версии. Тем более что абордажа пока что нет, а значит и сближаться с противником с учетом ветра - нет необходимости. Разве что строить маршрут для побега…

Искусственный идиот

Ооох, вот это конечно та еще головоломка. Чтобы вы понимали всю величину проблемы, стоит рассмотреть 3 одновременные задачи, которые завязаны на направленность корабля. Нам нужно:

  • поддерживать расстояние между ИИ и игроком с учетом дальности заряженного снаряда(BTT_ShipMove)
  • вращать корабль, чтобы отстреляться бортами по игроку(BTT_ShipRotateAttack)
  • следить за препятствиями, чтобы ИИ не влетел в скалу и вовремя менять парус вращая корабль(BTS_ShipObstacleSavier)
Первая версия дерева поведения корабля. Если у вас конечно хорошее зрение…
Первая версия дерева поведения корабля. Если у вас конечно хорошее зрение…

Я не буду углубляться в реализацию конкретных задач и сервисов, просто потому что это не несет особого научного интереса. Но я расскажу об архитектуре поведения в целом.

Начнем с корневых сервисов:

  • Все начинается с проверки на хп у подопечного корабля с помощью декоратора - BTD_IsWeAlive
  • Затем BTS_CalcShipTask каждую секунду проверяет окружение на наличие врагов, и при их наличии - переключает текущую задачу на атаку противника. В будущем у этого сервиса будет больше обязанностей, например учет возможности побега, избегания встречи с вражескими кораблями, абордаж и т.п.
  • BTS_ModifyShipSailLevel - решает конфликты между разными задачами и сервисами при работе с парусами. Например задача Move построила маршрут и выставила скорость паруса в 1, а сервис BTS_ShipObstacleSavier не увидел перед собой никаких препятствий и выставил парус в 2. Ситуация может быть и обратной, но прав скорее всего тот, у кого меньше.
  • BTS_ShipObstacleSavier - проверка препятствий перед кораблем, и попытки их избежать.
  • BTS_ShipAutoFire - стреляет во все, что находится в зоне досягаемости текущим снарядом.

Далее идет логика задач:

  • Move - с помощью сервиса BTS_BuildPath строим маршрут до цели и передаем его в BTT_ShipMove, который регулирует скорость и повороты. По достижению цели - ИИ забывает эту задачу.
  • Follow - логика идентична Move, но задача установлена перманентно.
  • Attack - причина моей головной боли и кошмаров по ночам:
    BTD_IsTargetAlive - проверяем жизнеспособность противника. Если мертв - просто забываем.
    BTS_ShipChangeCannonBallDistance - каждую секунду проверяем каким снарядом нам лучше стрелять с текущего расстояния и состояния противника, затем меняем снаряд при необходимости. Необходимость достигается - либо только что сделанным выстрелом, либо…
    BTD_IsTargetInFireDistance - проверяем, достреливаем ли текущим снарядом по противнику. Если нет - проверяем можем ли мы дострелить хоть каким-то снарядом. В положительном случае даем разрешение на смену снаряда через
    BTT_SetShipAllowChangeCannonBall. Если же противник слишком далеко - строим до него маршрут, и направляем к нему нашего ИИ.
    BTT_ShipRotateAttack - особая уличная магия, подбор борта из которого стоит стрелять, и вращение корабля на соответствующий борт. Работает только x секунд, потому что…
    BTT_CalcTargetLocationOnShipDistance - устанавливает точку с идеальным расстоянием до противника, в которую двигается ИИ в течении x секунд, чтобы потом снова передать эстафету BTT_ShipRotateAttack

Скоооолько болтовни… может лучше покажешь на деле?!

Собственно, если бы мне нечего было показать, я бы и не писал эту статью. Поэтому встречайте - небольшой альфа-недо-геймплей морской боевки! Я ради этого дела, даже немного эффектов завез и немного улучшил управление. Правда пока что без нормальных эффектов воды и попаданий по корпусу.

Звук моря в начале потерялся, забыл его на всю карту растянуть, после первой минуты будет норм.

Так я не понял, а где дырки в парусах?! Почему книпелей нет?! Ты что за мусор мне за Корсаров втираешь?!

Каюсь. Я все сломал. Не знаю что, но почему то на тестовом проекте это работает нормально, а на основном - не выдает корректных координат. Но чести ради, я в этом еще не разбирался, просто паруса меня уже за*****! Но к релизу демки это точно будет исправлено!

Шо там у Мауриус?

Честно говоря, я решил разрабатывать своих корсаров, потому что казалось что после определенных событий, разработка украинцев точно отложена до лучших времен. Тем более что они уже длительное время не выкладывали никаких дневников разработки. До меня доходили только слухи, что мол разработка идет, но это могло быть только для того, чтобы игроки не теряли надежду. Но тут оказалось, что ребята живее всех живых, и на днях даже выпустили демо версию. Конечно демка оставляет желать лучшего, но все же на текущий момент они впереди меня на несколько шагов. Да и каким образом, одна жалкая веб-макака в принципе может их не то что обогнать, а хотя бы приблизиться к команде полноценных игровых разработчиков, пусть и мобильных…

Таким образом, я поставил себе текущей целью сделать демоверсию своей игры, а дальнейшее развитие проекта будет зависеть от реакции сообщества. Наземную боевку я точно завезти не успею, но просто перемещение персонажа по городу, пример диалоговой системы, принятие и выполнение квестов - может и получится. Также, хотелось бы показать свое видение почти бесшовного перехода между глобальной картой и боевой. Ну и ИИ кораблей еще нужно подтянуть, разделить их на группы патрулей и торговцев с разными приоритетами, и возвращению к исходной задаче после побега или победы над противником. А еще падение мачты, новые корабли, фиксы оптимизации… ох, сколько всего (⊙_⊙).

Ну а на сегодня это все! Если вам понравилась статья, то буду благодарен за ваши комментарии, вопросы или советы! Если вам не понравилась статья, то можете поставить дизы подо всеми моими статьями, как это сделал Михаил.

7.1K7.1K показов
809809 открытий
21 комментарий

Спустить паруса! Поднять паруса! Спустить паруса! Поднять паруса!

Кросивое. Будим слидить.

Ответить

Если есть слово Корсары - лайк не глядя!

Ответить

Как человек посвятившей свое время этой же задачке по поиску пути некоторое время могу сказать что использовать навигационный меш и поиск пути для кораблей по нему это путь почти в никуда, т.к. даже построив этот путь надо понимать что это путь примерный для будущего корабля будет, и написать такое движение где будет в каждой корневой точке написано какая скорость (обычная и угловая) у корабля должна быть , ну очень сложно, и при этом даже написав это вы получите что у вас корабль будет двигаться нифига не реалистично, то есть далеко не, так как бы двигался игрок. А вот что бы он двигался реалистично нужно написать будет еще понимание того где нужно брать ранний апекс, а где поздний, а где средний. И это для полностью рандомный карты, за адекватное время (я про процессорное) на мой взгляд довольно сложная задача. Тут нужны либо предпросчеты прохождения каждого элемента карты, либо хз).
Я лично попробовав это написать забил болт и написал localAvoidence и он норм работает, но нужно понимать что в моих картах не было лабиринтов).

Ответить

Да у меня в общем-то тоже лабиринтов не планируется, но тема с localAvoidence была реализована в оригинальной игре, и если цель стояла за каким то островом, то ии мог просто начать крутиться на одном месте ломая себе паруса от сушу. Текущее решение разумеется такое себе, но зато корабль гарантированно(ну ладно, почти) доберется до игрока.

Ответить

"Но тут оказалось, что ребята живее всех"
Я бы лучше видел объединение разрабов одной тематики, чем 2 недоделанные демки. У каждого свои идеи и нововведение, вот и сделайте Корсары: "HD Революция" ;)

Ответить

Начнем с того, что они делают на юнити, а я на UE. Не думаю что кто либо из нас, согласиться менять движок) Во всяком случае, я бы не согласился.
А так, утопичное у тебя конечно желание...
Так-то всегда были есть и будут разные команды, которые не хотят лишаться свободы творчества, а в больших командах иначе быть не может, иначе цельного проекта не получится просто.

Ответить

Смотрит видео: занос, заход в простой стоячий поворот со второй попытки

Ну и дерьмо. *Аутентично.*
- мимо 1000 часов в КГПК и ККС

З.Ы. Ты классный, продолжай!

Ответить