PsRealVehicle, или Open Source-плагин физики танков в Armored Warfare: Assault

tpk-ppd8uortedgcqdi0rzcqs-a.jpeg

Пару лет назад нашей команде выпала честь заняться созданием мобильной «Арматы». Придерживаясь правила «делаем игру, а не технологию», прототип мы создавали на том, что уже есть в движке. Это был UE 4.9, в основе физической модели — PhysX Vehicles, и много боли (как по поводу, так и без).

В дальнейшем наша команда создала open source-плагин PsRealVehicle, доступный по MIT лицензии. Этот плагин заточен под физику танков и колесных машинок для высоконагруженных сетевых шутеров, и его работу вы в любой момент можете наблюдать в нашем проекте Armored Warfare: Assault.

Четко. Ясно. И только по делу.

jury-bxmblc8rywoe28q2istiry.png

Репозиторий плагина

Документация по основным конфигам

Используется в проекте: Armored Warfare: Assault


Немного истории, или Назад к истокам

Работу над проектом мы начали на Unreal Engine 4.9. В то время «из коробки» физика машин поддерживала только четырехколесные машинки, а для шестиколесных «лавок» (LAV-400, наша первая «боевая» машина-прототип) пришлось сразу же использовать кастомную сборку движка. Со встроенной физикой танков было ещё хуже: данные о том, как всё работает и настраивается, приходилось по крупицам выуживать из кода.

Следуя правилу «прототипируй», мы сформировали для себя следующие требования:


  • Физика должна симулировать движение танка (программа-минимум) и колесных машин (весьма желательно — это фишка серии игр AW).
  • Выделенный сервер должен выдерживать до 20 машинок на онлайн-сессию, а клиент должен их обрабатывать.
  • Все колеса и гусеницы должны следовать неровностям поверхности, подвеска должна работать, танк — качаться.
  • Настройка физики должна определяться реальными величинами (масса машинки, мощность двигателя) и вести к реалистичному поведению (возможность преодолевать те или иные виды ландшафта).
  • Чем меньше мы пишем технического кода, тем лучше: движок должны делать Epic Games, а не мы.

tugqm20mytmfcwjgeh-rwe6vukg.png

Итак, требования приблизительно понятны, приступили к делу. Достаточно быстро мы собрали первый прототип, танчики ездили, машинки колесили, но было у нас две беды:


  1. Всё это весьма бодро жрало процессор.
  2. Создаваемая картина мира никак не хотела укладываться в рамки реалистичного поведения тяжелой техники. Тридцатитонный танк ни при каких настройках не мог взять 15-градусный подъем (а это один из самых легких вариантов). Мы потратили немало времени, возясь с настройками симуляции и трения ландшафта, но это приводило либо к задиранию мощности до космических значений (в 20+ раз больше реальных величин, и в результате машины вели себя нестабильно и непрогнозируемо), либо к игрушечным массам техники (PhysX отлично работает при массе ТС в районе полутора тонн).

lp5u_gfun8xtmhelxt5wvvwlsjg.png

Геймдизайнеры от такого были далеко не в восторге. Программисты плакали, кололись, но продолжали есть кактус (партия требует рабочего решения!). Прототип был одобрен руководством, и отправлен на создание альфа-версии (к слову, видео из прототипа есть на Youtube. Но время шло, а надежды на светлое будущее такой физики становились всё меньше. Настроек было недостаточно, их поведение выглядело чёрной магией. А позиция «игра, а не технологии» по-своему связывала руки. Хотя бы сомнениями в том, а потянем ли.

Тихонько вооружившись Википедией, остаточными школьными знаниями и опытом работы над физикой «на понтонах» а-ля Assassin’s Creed, за пару дней я создал прототип новой физики танка, который и лег в основу плагина PsRealVehicle. В течение недели proof-of-concept был поставлен на ноги, показан CTO команды и защищён нагрузочным тестированием. Цифры говорили: своей физике — быть.


…-…, и в продакшн

Путь от прототипа до прода вышел куда длиннее. Если на концептуальную проверку хватило недели, то на адекватную бета-версию ушло уже месяца полтора. Создание полноценного «продовского» релиза заняло около полугода, постоянная доводка и коррекция — на протяжении всего времени работы над проектом. Во многом такой высокой скоростью разработки и внедрения физики в проект мы обязаны пришедшему как раз в то время в нашу команду техническому геймдизайнеру Игорю, чья дотошность в аспектах работы математической модели и ее субъективного восприятия игроками и привела к текущему результату. Должен признать, в технологическом смысле я — варвар: мое дело сделать топор, чтобы валить лес. После обработки Игорем и доводки модели другими ребятами мы получили production-ready открытое решение, масштабируемое и в высшей мере оптимизированное для нужд мультиплеера. Здесь есть чем гордиться: из множества доступных на рынке плагинов (включая встроенный PhysX Vehicles) наш самый быстрый и прозрачный в настройке.

Кстати, не обошлось и без смешных случаев. Пока мы работали с PhysX Vehicle и наши предельно скользкие многоколесные машинки не могли взобраться на мелкие холмы, я не раз слышал упреки, мол, не может наша команда настроить, чтобы как у людей было. Решение об использовании своего плагина было принято, в том числе, под влиянием этого кадра:

llx5zyvm9un4kqbbptkutjkl-js.png

Новейшая разработка советской армии! Танк-паук, который способен подниматься на 89-градусные стены. Такое крыть было просто нечем : D


Особенности нашего решения

Прежде чем я перейду к описанию настройки танков и машин в PsRealVehicle на примере нашего AW: Assault, хочу сказать еще о паре вещей, которые легли в основу используемой физической модели.

ctjmczrjxmqlvxnq7vitxxo2wvg.gif

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

Первый пункт имеет следствие: некоторые вещи в игре работают весьма фейково. Если что-то выглядит как танк и ведет себя как танк — то это танк, и не важно, что внутри он немного фрегат, или что часть физики настроена условной магией трения. Одним из таких условностей является регулирование поворота машинки путем изменения угловой скорости, а не силами, приложенными к колесам и подвеске. Условно, танк поворачивает на X градусов в секунду, потому что мы так решили исходя из геймплейных соображений, а не потому, что у него гусеницы вращаются с такой-то скоростью.

vt81ycuavkjcezmuos42pkd3j5c.gif

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

k8l4labeq23fkhmcxuyy9obujd8.gif


Иерархия классов

AAwmVehicle — главный C++ класс, отвечающий за машинку в игре, разбитый на множество компонентов (движение — UPsRealVehicleMovementComponent, звуки, VFX, статистика, броня и другие). От него наследуется блюпринт BP_DefaultVehicle, который является дополнительной прослойкой для настроек по-умолчанию для всех машин. Все прочие — частные блюпринты настроек для каждой единицы техники в игре.

Каждая машина представляет из себя набор таких данных:


  • Блюпринт, где прописаны все внешние ассеты, заданы звуки, свойства а-ля «колесная/гусеничная техника», и настроена физика.
  • Скелетал меш и привязанные к нему ассеты:
    — Физический ассет (здесь никакой магии, всё стандартно).
    — Анимационное дерево.
  • Текстуры (diffuse, normal map, RMM).
  • Материал инстансы (корпус, гусеницы + разрушенное состояние).
  • Набор мешей брони для системы пробитий.
  • Камеры, чекеры уровня воды и прочие вспомогательные коллизии.


Анимация танка

Настроить один танк — мелочь, каким бы сложным ни было анимационное дерево. Настроить десятки таких танков и поддерживать их в актуальном состоянии, при изменении костей, меша и так далее — совершенно неадекватный объем для ручной работы. К счастью, в нашем случае речь идёт о достаточно стандартизированном «персонаже»: танк можно препарировать на сущности и называть их шаблонно. Речь, конечно же, об именовании костей.

Такой подход позволил использовать по сути одно и то же анимационное дерево, которое святыми Ctrl+C / Ctrl+V множится на любое число танков и не требует никакой поддержки, кроме изначального QA-check’а.

jkac3e9ehgqjpxomkep5uekdnoq.png

Вся магия происходит внутри кастомных сипипи-нод. Это позволило не только стандартизировать дерево, но и сильно сократить количество вычислений на расчёте анимаций (стандартные ноды очень любят гонять системы координат туда-сюда).


Материалы танка

Для всех частей танка используется один мастер-материал, кастомизируемый парой Switch-нод.

blazc_ihvsibh0upozkwha6c1ks.png

Далее мы получаем такое дерево:

 - M_Vehicles
 - -- MI_Vehicles_Clean_Body
 - -- -- MI_Leopard2
 - -- -- -- MI_Leopard2_LOD
 - -- MI_Vehicles_Clean_Treads (стоит галочка "Treads")
 - -- -- MI_Leopard2_Treads
 - -- -- -- MI_Leopard2_Treads_LOD

Настоящий «вес» здесь имеют только M_Vehicles и MI_Vehicles_Clean_Treads, все остальные инстансы — просто наборы параметров и потребляют минимум памяти и места на диске.

svzdzmbcm6u9zpycumfljxddrpo.png

В целом, набор графических ассетов для танка получается весьма стандартным для любых игр.


Работа брони

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

vl5pljjj372kzdcxamm4tat4n2m.png

На самом деле мы используем обычные анриловские коллизии, но только чтобы «поймать» пулю. После того, как прожектайл воткнулся в танк, обсчёт повреждений происходит пополигонально по всем листам брони, с учётом свойств каждого куска, многослойности, переотражений снаряда, кумулятивной воронки и прочих интересных механик.

Самое удобное для такого случая — читать «голые» данные меша, которые для выделенного сервера мы не strip’аем.


Сеть и экстра-оптимизация

Пара «околотанковых» моментов, которые я также хотел бы кратко упомянуть.


  • Всё движение танков осуществляется только на сервере, клиенты лишь интерполируют полученные значения. Никакой экстраполяции не используется. Частота синхронизации — 10 раз в секунду.


  • В зависимости от ScreenSize танка мы пропускаем то или иное количество тиков скелетал меша, что включает в себя обсчёт всех анимаций и некоторых физических взаимодействий. Если танк не виден на экране — он тупой не анимированный ящик, плавающий в пространстве. Встроенный Update Rate Optimization, несмотря на хорошую идею, обладает весьма грубой реализацией, не дающей ощутимого прироста производительности. Особенно, если речь о мобилках.


  • Для всех танков, кроме собственного, на клиенте отрезаются все компоненты, кроме самых базовых: камер, чекеров и прочего, из чего состоит танк. По сути, они не имеют ничего, кроме внешнего вида.


hs96z4mtindirtkklvghhlznocg.jpeg


  • На выделенном сервере ездит форсированный LOD1 танка. Меньше вершин — меньше потребления процессора. Причём обновление положения кастомных кусков брони происходит только в момент попадания прожектайла: нет смысла обновлять состояние частей каждый тик.

Мы в Pushkin Studio считаем, что обмен опытом разработки очень важен, в том числе и для роста профессионального уровня внутри команды. Open Source-проекты — значимая составляющая такого подхода, и я рад, что могу представить сообществу такую технологию, как PsRealVehicle.

На мой взгляд, очень важно, что мы сами ежедневно используем все публикуемые нами плагины и утилиты. Ведь путь, ярко демонстрируемый самими Epic Games, заключается в том, что успех хорошей технологии — это использование её самими разработчиками в собственных продуктах. Сейчас мы работаем уже на версии UE 4.20, наш плагин прошел с нами весь этот путь, и мы не собираемся останавливаться!

4mlh-kvwjhjyci6vxtcoao45wu8.png

© Habrahabr.ru