Drift Game Tutorial
Всем привет! Скоро стартуют занятия в первой группе курса »Unreal Engine Game Developer. Basic». В преддверии старта курса прошел открытый урок по созданию Дрифт-симулятора на UE5. Вебинар провёл Дмитрий Исмаилов, Technical Lead в FairGames Studio. Он также написал подробную статью, которую мы и предлагаем вашему вниманию.
Давно хотел начать делать пет-проект про машинки, потому что я люблю машинки. А времени на то, чтобы заниматься автоспортом в реальности, у меня всё нет и нет.
Но ощущение, что можно сделать что-то более интересное в виртуальном дрифте, есть. А тут еще и потребность в таком проекте появилась.
Тема отлично подходила для открытого урока, потому что изначальная задумка была в достаточно простых механиках. Поэтому статья будет интересна как тем, кто впервые открывает для себя Unreal Engine, так и тем, кто знаком с движком, но не углублялся в cоздание автомобилей в нём.
Код весь на Блюпринтах, поэтому вам может показаться, что программирование здесь отсутствует.
Для тех, кто впервые слышит про Blueprints:
Это «визуально скриптовый язык программирования», написанный на С++. То есть это блоки С++ кода, которые мы соединяем наподобие блок-схем. Тем не менее, это вполне себе язык программирования, хорошо подходящий как для прототипирования, так и для написания сложной логики. Разве что для работы с большим количеством данных он подойдет плохо.
Осторожно, в статье много скриншотов и гифок!
Я преследовал цель сделать механику управления, с которой будет приятно играть не только с руля или геймпада, но и с клавиатуры, без возможности дозировать нажатие кнопки газа и плавно поворачивать руль. А ощущения должны быть похожи на зимние покатушки по заснеженной площадке. Скользкое покрытие прощает многие ошибки и позволяет просто наслаждаться процессом, не борясь с машиной. Только фан, но при этом с ощущением, что ты управляешь настоящей машиной, а не игрушкой на радио управлении.
И вот что получилось.
Я уже наметил себе дальнейший план развития этого пет-проекта. Добавить все-таки коробку передач, улучшить отклик машины на газ. Но лично мне уже нравится играть в текущий вариант.
Шаблон проекта и дефолтный автомобиль
Начал я с шаблона проекта Vehicle.Тут в нашем распоряжении готовый трек, готовая машина.
Можно сказать, дело сделано! Сейчас машинке скажем, что она мощ-щ-щная, заднеприводная и ка-а-ак повалим боком!
А она не хочет. Едет быстро, а вот в заносе не держится. И какую мощность я бы не ставил двигателю, держаться в заносе она не начинает, еще и разворачивается постоянно. При этом скорость поворота колес зависит от скорости движения. В общем, машинка делает очень многое за нас. Но всё не то и всё не так.
Да, возможно, её можно настроить правильно, а я просто не разобрался в чужом коде и решил изобрести велосипед. Но, думаю, в этот раз это того стоило. И вот почему:
Пара строк философии
На мой взгляд, цель разработчика геймплея такая же, как у фокусника — простейшими действиями заставить поверить всех, что законы мироздания можно обмануть.И когда наша цель — передать ощущения того, как ты зимой на парковке жмешь на газ, рулем крутишь, а машина едет боком так, будто твоя фамилия Чивчян или Цареградцев, нам не нужна реалистичная физика. Нам нужно то, что дает этот кайф.
Переведя на занудный: нужно придумать упрощенную физическую модель, учитывающую и передающую главные аспекты увлекательности процесса дрифта.
Изобретаем подвеску
Поскольку реалистичная машина EpicGames нам не подошла, начинаем изобретать свою с нуля. Точнее, с подвески.
Итак, подвеска нужна, чтобы поведение машины выглядело похожим на настоящее. По сути, это всё. Можно было бы использовать просто анимации кренов. Сделать четыре положения наклона автомобиля (вперед, назад, вправо, влево) и смешивать их в зависимости от ускорения. Но я решил внести долю реалистичности процесса. Почему? Потому что проще сделать физику пружин и сообщать этой физической модели примененную силу, чем самому рассчитывать кучу сил и углов.
Главное упрощение состоит в том, что подвеска — это сила, удерживающая кузов машины от того, чтобы стать стенс-проектом: просто красиво лежать и никуда не ехать.
Машина опирается на четыре точки, поэтому сила приложена к кузову там, где находятся колёса, и направлена вверх (точнее перпендикулярно поверхности), так же, как та самая сила «Реакции опоры» из школьной физики, которую еще называли N.
Но в нашем случае, это сила, с которой пружины подвески отталкивают наш кузов от земли. Для расчета этой силы нам нужна формула. Сначала я вспомнил школьную физику, потом полистал статейки о моделировании подвески и наткнулся на видео (на ютубе, конечно же). Ну и, смешав всё это, получилось следующее:
Мы пускаем LineTrace — луч, идущий из ступицы колеса вниз, место, где луч упрется в какую-нибудь другую коллизию и будет считаться точкой, на котором сейчас стоит колесо. Определяем, на какой высоте от земли находится центр колеса и на сколько выше или ниже он должен находится в состоянии покоя (наш желаемый клиренс).
После всех расчетов применяем эту силу к кузову в месте крепления колеса:
Стадия прогресса: левитирующий кирпич в виде машины.
Добавим щепотку трения
Теперь нужно добавить трение, которое и позволит настроить машину от аркадной, едущей «как по рельсам», до веселого дрифт корча.
Для начала, делаем нормальную машину. Как мы помним, машина опирается на четыре точки. Во всех этих четырех точках есть две силы трения: сила качения вдоль направления вращения колеса и сила трения поперек вращения колеса. Сила качения нас совершенно не интересует. Сила трения же начинает действовать, если колесо пытается двигаться поперек оси вращения. Значит, как только у колеса появляется скорость поперек оси вращения, нужно толкать колесо в обратную сторону.
А чтобы машинка начала скользить, нужно лишь ограничить максимальную силу, с которой мы будем толкать колесо, чтобы она с большой центробежной силой скользила вбок.
Теперь скольжение нужно сделать управляемым. Для начала сделаем разный коэффициент трения для передних и задних колес: чем больше разница в «держаке», тем лучше машина будет слушаться передних колес и скользить задними.
И последние штрихи — изменение трения c началом скольжения. Это что-то среднее между правильным применением трения покоя и трением скольжения, плюс симуляция срыва колеса при применении избыточной мощности. Ускорение машины тоже ограничиваем через коэффициент трения и, если колеса задней оси начали куда-либо скользить, уменьшаем коэффициент трения для этой оси.
Что-то не то… Итоговый вариант, который я показывал в начале, игрался явно лучше. Секрет кроется в добавлении помощи рулежки. Потому что на клавиатуре невозможно самостоятельно контролировать поворот колес на небольшой угол и плавно менять его.
Дрифт-помощник
Раз моя цель — сделать приятную игру для клавиатуры, то без ИИ, который будет выступать в роли помощника руления, тут не обойтись. При этом единственную роль которую возьмет на себя Искусственный Интеллект — это рулить в сторону заноса. Точнее держать передние колеса авто в сторону движения. А нажатия кнопок поворота вправо и влево будет корректировать угол поворота колес.
Визуал и обманы зрения
А теперь поговорим о, возможно, самой главной части проекта, дающей ощущение собственно дрифта — о визуале. Я специально отключил анимации колес, но не стал отключать частички дыма и следов шин, потому что без частичек остается непонятное движение машины в пространстве.
Таким образом, лишь отсутствием/добавлением визуальных частичек очень сильно меняется восприятие виртуального инерции движения автомобиля.
Также на восприятие поведения авто влияет визуал кренов. Давайте сравним.
Это машина с «жесткой подвеской».
А это с «мягкой подвеской»
Из-за того, что мягкая подвеска более «валкая», создается ощущение, что и рулится она похуже, будто на дороге стоит не так уверенно. Однако в текущей реализации нашему трению абсолютно без разницы на крены, и все колеса, касающиеся земли, одинаково «трутся» о поверхность. Так что это очередной «фокус» с восприятием игрока.
Частички
Вернемся к частичкам. Система частиц достаточно проста. Она генерирует спрайты дыма, которые по конусу разлетаются от места спавна (Add Velocity in Cone), заполняя пространство вокруг, также спрайт чуть вращается (Sprite Rotation Rate) для создания ощущения клуба дыма и со временем пропадает по альфе (Scale Color). И спрайты следов шин, которые располагаются «лицом» вверх и повернуты так, как повернута система частиц (Sprite Facing and Alignment).
Хочу заострить внимание на двух аспектах:
Для спавна спрайтов частиц я использую спавн частичек в зависимости от сдвига эмиттера (Spawn Per Unit). Изначально я пытался спавнить декали следов шин в тике, но при большой скорости появлялись разрывы в следах. Так что я отказался от декалей. Тем более, мой способ проще и дешевле, чем спамить декалями каждый кадр или следить за тем, насколько сдвинулось колесо, это автоматически делает система частиц. И, по сути, это достаточно реалистично — в жизни у нас тоже след от шины появляется от трения по асфальту, от этого же трения растет температура покрышки, она начинает плавиться и появляется дым.
Текстура для следа шины с использованием круговой маски прозрачности. Удивительно, но когда я начал изучать, как это делают на ютубе и во множестве плагинов, их подход совершенно не подходил для дрифта, потому что они использовали квадратный рисунок следа от шины, из-за чего машина при движении боком оставляла следы лесенкой (если только не ляпать частичку каждый сантиметр). Но это звучит слишком жирно. А вот использование круговой маски прозрачности для текстуры дало достаточно приятный результат.
Анимация колёс
Ну и последний штрих визуальной части — это анимация колёс.
По сути, анимация колес заключается в вращении их костей через AnimationBlueprint, потому что модель машины рассчитана на использование с дефолтными классами UE для машин. А эти классы требуют, чтобы колеса были отдельными костями в скелетном меше. Но можно было использовать и просто статик меши для кузова и колес и вращать колеса, как отдельные объекты.
Поворот руля я применяю, как есть (да, одинаковый для обоих колес, на угол аккермана можно забить). А градус вращения же считаю по формуле перевода из линейной скорости в угловую. При этом я беру не весь вектор скорости, а только его проекцию на ось, перпендикулярную оси вращению колеса.
Положение же колеса беру из расчета высоты подвески и здесь же располагаю системы частиц каждого колеса в паре сантиметров над точкой опоры колеса.
На этом, в общем-то, всё.
Заключение
Надеюсь, вам понравилась подобная идея прототипа, и вы будете ждать от меня новых новостей про развитие этого проекта, или же у вас уже зачесались руки сделать ещё лучше самому. Думаю, вы уже поняли, что Unreal Engine дает возможность достаточно просто делать интересные и классные вещи.
Если захочется поиграться моим кодом, прошу на гитхаб https://github.com/Rasta42/DriftLesson
В заключение скажу, что скоро состоится второй открытый урок «ИИ в Unreal Engine 5. Создаем патрулирующего бота».На этом уроке спикер расскажет, какие ИИ бывают в современных играх и как их можно разделить на группы с точки зрения разработки. Рассмотрим основные составляющие ИИ в Unreal Engine 5 и как разрабатывается логика для поведения бота. Разберем, как создать простого бота, который патрулирует определенную зону. Записаться можно здесь.