Как сделать машину в юнити 3д
Перейти к содержимому

Как сделать машину в юнити 3д

  • автор:

 

Create a vehicle with Wheel Colliders

The Wheel Collider An invisible shape that is used to handle physical collisions for an object. A collider doesn’t need to be exactly the same shape as the object’s mesh — a rough approximation is often more efficient and indistinguishable in gameplay. More info
See in Glossary component is powered by the PhysX 3 Vehicles SDK.

This tutorial takes you through the process of creating a basic functioning car.

To start, select GameObject The fundamental object in Unity scenes, which can represent characters, props, scenery, cameras, waypoints, and more. A GameObject’s functionality is defined by the Components attached to it. More info
See in Glossary > 3D Object A 3D GameObject such as a cube, terrain or ragdoll. More info
See in Glossary > Plane. This is the ground the car is going to drive on. To keep it simple, make sure the ground has a Transform of 0 (on the Transform component in the Inspector Window, click the Settings cog and click Reset). Increase the Transform’s Scale fields to 100 to make the Plane bigger.

Create a basic car skeleton

  1. First, add a GameObject to act as the car root GameObject. To do this, go to GameObject > Create Empty. Change the GameObject’s name to car_root .
  2. Add a Physics 3D Rigidbody A component that allows a GameObject to be affected by simulated gravity and other forces. More info
    See in Glossary component to car_root . The default mass of 1kg is too light for the default suspension settings; change it to 1500kg to make it much heavier.
  3. Next, create the car body Collider. Go to GameObject > 3D Object > Cube. Make this cube a child GameObject under car_root . Reset the Transform to 0 to make it perfectly aligned in local space. The car is oriented along the Z axis, so set the Transform’s ZScale to 3.
  4. Add the wheels root. Select car_root and GameObject > Create Empty Child. Change the name to wheels . Reset the Transform on it. This GameObject is not mandatory, but it is useful for tuning and debugging later.
  5. To create the first wheel, select the wheels GameObject, go to GameObject > Create Empty Child, and name it frontLeft . Reset the Transform, then set the Transform PositionX to –1, Y to 0, and Z to 1. To add a Collider to the wheel, go to Add component > Physics > Wheel Collider A special collider for grounded vehicles. It has built-in collision detection, wheel physics, and a slip-based tire friction model. It can be used for objects other than wheels, but it is specifically designed for vehicles with wheels. More info
    See in Glossary .
  6. Duplicate the frontLeft GameObject. Change the Transform’s X position to 1. Change the name to frontRight .
  7. Select both the frontLeft and frontRight GameObjects. Duplicate them. Change the Transform’s Z position of both GameObjects to –1. Change the names to rearLeft and rearRight respectively.
  8. Finally, select the car_root GameObject and use the Move Tool to raise it slightly above the ground.

Now you should be able to see something like this:

To make this car actually drivable, you need to write a controller for it. The following code sample works as a controller:

Create a new C# script (Add Component > New Script), on the car_root GameObject, copy this sample into the script file and save it. You can tune the script parameters as shown below; experiment with the settings and enter Play Mode to test the results.

The following settings are very effective as a car controller:

Hint: Make sure to increase the size of AxleInfo .

You can have up to 20 wheels on a single vehicle instance, with each of them applying steering, motor or braking torque.

Next, move on to visual wheels. As you can see, a Wheel Collider doesn’t apply the simulated wheel position and rotation back to the Wheel Collider’s Transform, so adding visual wheel requires some tricks.

You need some wheel geometry here. You can make a simple wheel shape out of a cylinder. There could be several approaches to adding visual wheels: making it so that you have to assign visual wheels manually in script properties, or writing some logic to find the corresponding visual wheel automatically. This tutorial follows the second approach. Attach the visual wheels to the Wheel Collider GameObjects.

Next, change the controller script:

One important parameter of the Wheel Collider component is Force App Point Distance. This is the distance from the base of the resting wheel to the point where the wheel forces are applied. The default value is 0, which means to apply the forces at the base of the resting wheel, but actually, it is wise to have this point located somewhere slightly below the car’s centre of mass.

Руководство к Car Tutorial (Unity3d) часть 1 из 3

Это переведенное руководство для проекта ссылка или альтернативная ссылка на проект с исправленными ошибками под Unity3d 4.6.

P.S Оригинал руководства, находится в самом проекте ввиде 3ех PDF файлов, в папке Assets.

Данный архив был заменен на UnityPacked. В этом проекте уже залит архив со скриптами переписанными на C# находящийся в папке Assets\Scripts\CSharpScripts. Порядок установки:

1) Запускаем Unity3d и создает пустой проект.
2) Импортируем наш проект > (Assets/Import Package/Custom Package).
3) Дожидаемся импорта всех ресурсов и вуаля наш проект импортирован.
4) ВНИМАНИЕ. если хотите использовать все C# скрипты, надо удалить предварительно JS скрипты из проекта и из

Prefabs, а затем распаковать архив C# скриптов и использовать эти скрипты.

Отдельное спасибо команде Zionn Game Room за перевод официальных и не официальных видеоуроков по Unity3d на русский язык. И так, приступим к изучению нашего руководства.

Введение

Цель этого руководства является показать вам, как создать гоночную игру в Unity3d. Мы создадим автомобиль из 3D-моделей, скриптов и компонентов. Мы предоставляем вам полноценный проект гоночного симулятора, где вы можете играть и изучать готовые сцены. Мы также предоставим вам сцену которая полностью готова для игры, кроме автомобиля над которым вы можете потренироваться с помощью этого руководства.

Что мы изучим?

Начнем с того о чем это руководство. Оно разделено на три части, которые независимы друг от друга:

1. Сборка автомобиля
Как собрать автомобильный префаб (Car Prefab) из 3D-модели, скриптов и компонентов. Это текущий раздел.

2. Тонкая настройка автомобиля
Как правильно настроить автомобиль.

3. Под капотом
Более глубокий взгляд на исходный код, который приводит в движение автомобиль.

Необходимые условия

Руководство не предназначено для начинающих в качестве обучения Unity3d . Вы должны иметь базовые понимания как Unity3d организован, вы должны знать, что такое Игровой объект (GameObject), Компоненты (Components), Скрипты (Scripts) и т.д. Мы вместе разберем много материала, некоторые вещи разберем базово, некоторые углублено.

Мы не будем изучать:

• Остальные скрипты.
• Основы Unity3d. Мы не будем вдаваться в подробности с объяснением основ работы скриптов и компонентов Unity3d. Для этого есть много других ресурсов по адресам:
ссылка №1
ссылка №2

Руководство пользователя и скриптов Unity3d ценные спутники при изучении этого руководства. Мы предлагаем вам посетить эти ресурсы, когда вы сталкиваетесь со встроенными компонентами или функциями, о которых вы хотели бы узнать больше.

Подход к изучению является аналогом «Обезъяна видит, обезьяна повторяет»: вы следуете инструкциям, которые мы даем о создании автомобиля и изменении его переменных.

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

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

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

Мы уверены, что вы узнаете многое, после того как ознакомитесь со всеми руководствами.

Часть 1: Сборка автомобиля

Скачайте архив с папкой проекта или альтернативная ссылка на проект с исправленными ошибками под Unity3d 4.6. Начните с открытия сцены с именем ‘CompleteScene‘. Эта сцена имеет настроенный автомобиль, вы можете попробовать поиграть нажав кнопку воспроизведения (Play). Это продемонстрирует вам конечный результат того, что мы собираемся сделать.

image

Когда вы закончите играть, откройте сцену под названием ‘TheTrack’. Эта сцена содержит все что нужно для гоночного симулятора, за исключением наиболее важной части — автомобиля.

Теперь перетащите модель автомобиля в сцену. В окне проекта (Project view) вы находим его в Models/Car/catamount,

В зависимости от того, куда вы перетащили автомобиль, вы вероятно захотите изменить его позицию на более подходящую.
Я полагаю, что вы измените позицию автомобиля в инспекторе (inspector) на (860, 102.3, 878) и установите его Y-вращение (Rotate) 130.

image

Это просто 3D модель автомобиля. Если вы посмотрите в инспектор, вы увидите, что она содержит множество дочерних объектов, такие как «тело» автомобиля, окна автомобиля и колеса. Она также содержит две простые сетки, которые мы будем использовать для коллайдеров (colliders) автомобиля. Не волнуйтесь, они сейчас не видны, мы изменим это. Потратьте некоторое время на изучение того как устроен автомобиль и как они связаны друг с другом в иерархии (hierarchy).

По ряду причин мы для автомобиля создали свой слой. С игровым объектом ‘Car’ разобрались, перейдите в инспектор и выберите «Car» в слоях выпадающего меню. В контекстном меню нажмите «Да, изменить дочерний объект (Yes, change children)», чтобы применить, изменения применяются ко всем объектам в иерархии автомобиля.

У игрового объекта «Car» есть компонент анимации, который устанавливается по умолчанию. Поскольку это не то, что мы собираемся использовать, пойдем дальше и немного подчистим, нажав на маленькое колесо справа компонента анимации (Animation Component) и выберите «Remove Component (Удалить компонент)».

Добавление столкновений (Collision)

image

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

• Нажмите на игровой объект Collider_Bottom, который находится как дочерний объект, объекта ‘Car’ (автомобиль).
• Перейдите в меню Component/Physics и нажмите MeshCollider добавив к объекту игры.
• Нажмите Material в выпадающем селекторе на вновь добавленном компоненте MeshCollider и выберите physics material.
• Проверьте что бы стояли галочки на двух квадратах (checkbox) ‘Smooth Sphere Collisions’ и ‘Convex’
• Так как коллайдеры будут невидимыми, удалите MeshRenderer и MeshFilter компоненты из игрового объекта (Нажмите на маленькое зубчатое колесо справа компонентов и выберите пункт «Удалить компонент» (‘Remove Component’).
• Сделайте то же самое что описано выше для игрового объекта Collider_Top.

Настройки тени для конкретной модели автомобиля

Мы собираемся изменить настройки теней для модели автомобиля «Car» по двум причинам. Прежде всего отключение теней в объектах, которые на самом деле не нуждаются в ней очень хорошая практика для повышения производительности. Во-вторых, мы считаем, что автомобиль будет выглядить лучше когда настроим тени. Это может быть более приятным для глаз, когда тени появляются и исчезают на автомобиле, во время его передвижения с большой скоростью по сцене. Если вы хотите более реалистичное поведение теней, это вполне возможно. Просто измените настройки в соответствии с вашими желаниями.

Настройки, которые мы используем для различных частей автомобиля являются следующие:

Термины:

Body: Cast Shadows enabled. Receive Shadows disabled
Body Interior: Cast Shadows enabled. Receive Shadows disabled
Car Windows: Cast and Receive Shadows disabled
DiscBrakes: Cast and Receive Shadows disabled
Wheels: Cast Shadows enabled. Receive shadows disabled.

Добавление компонентов автомобиля

Теперь давайте начнем добавлять компоненты, необходимые для правильной работы автомобиля (игрового объекта ‘Car’)

image

Прежде всего, нам нужен способ контролировать положение автомобиля в мире с помощью физической симуляции, и встроенный в компонент Rigidbody идеально подходит для этого. Выберите игровой объект «Car», перейдите в меню Components и выберите Physics/RigidBody. Подтвердите сообщение Unity3d, которое сообщает вам о потере prefabсоединений и наблюдаем, как игровой объект теперь имеет Rigidbody компонент прикрепленный в качестве одного из его компонентов.

• Автомобиль очевидно весит больше, чем просто один килограмм, так что начнем с изменения массы (Mass) в Rigidbody на что-то более реалистичное, допустим 1500кг.
• Далее мы имеем возможность изменить angularDrag свойство, это силы которые замедляют скорость и вращение Rigidbody. Мы будем контролировать сопротивление автомобиля с помощью скриптов, так что просто установите свойство angularDrag в 0.
• Найдите скрипт Car.js в папке ‘scripts/JavaScripts’ и перетащите его на игровой объект «Car». Этот скрипт является «двигателем» автомобиля, на объяснения скрипта мы сосредоточимся более подробно в конце этого руководства.

Компонент-скрипт «Car.js» имеет много различных переменных, которые будут объясняться, когда мы начнем настройки автомобиля, еще более подробно мы расскажем когда будем изучать код. Сейчас мы просто хотим настроить то что нужно, чтобы иметь возможность управлять автомобилем на трассе.

image

Прежде всего, скрипт «Car» должен знать о колесах, которые имеет автомобиль. В инспекторе вы увидите передние колеса (Front Wheels) и задние колеса (Rear Wheels), обратите внимание, что оба они могут быть расширены путем нажатия на маленькую стрелку слева от имени.

• Установите размер (size) передних (Front) и задних колес (Rear Wheels) на 2, оставляя место для двух передних колес и двух задних колес.
• Теперь раскройте WheelFL, WheelFR, WheelRL и WheelRR в инспекторе. Вы увидите, что каждый из них имеет тормозной диск (DiscBrake) в качестве дочернего объекта, и то что каждый тормозной диск (DiscBrake) имеет колесо в качестве дочернего объекта.
• Перетащите DiscBrakeFL и DiscBrakeFR в два открытых слота под (Front Wheels) передние колеса в скрипте «Car» , а так же DiscBrakeRL и DiscBrakeRR к слотам под (Rear Wheels) задние колеса.
• Вы можете спросить — зачем дисковые тормоза колесам? И объяснение простое: Дисковые тормоза в качестве родительских игровых объектов, поэтому установка дисков как колес будут включать шины.

Добавление blob теней

image

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

Для этого мы будем использовать проектор, который проецирует Blob тень, напоминающую форму автомобиля на дороге непосредственно под машиной. Проектор встроенный в компонент, который работает так же, как настоящий проектор. Вы указываете текстуру, которую хотите передавать, и на основе настроек для проектора и (расстояния до цели), тень будет опираться на те текстуры объектов, которые находятся на пути света проектора.

• В иерархии, создайте пустой игровой объект и перетащите его на автомобиль «Car», чтобы сделать его дочерним объектом, игрового объекта «Car».
• Задайте имя объекту «Blob shadow projector»
• Добавить компонент (Projector) проектора на Blob тень этого проектора (Component->Renderer->Projector)
• Установите на проекторах настройки Near Clip Plane = 0,1, Far Clip Plane = 50, Field of View = 30.
• Назначьте материал Blob_shadow для слота материала.
• В «Ignore Layers» выберите «Everything», а затем снимите флажок со слоя «Road», в результате чего проектор отбросит Blob тень на дорогу.
• Добавьте скрипт BlobShadowController.js (в папке Scripts/CSharpScripts в окне проекта)

Положение и вращение компонента (Projector) проектора обновляется каждый кадр в BlobShadowController.js скрипте который является довольно простым. Короче говоря, он находится в 10 метрах над автомобилем и получает его координаты вращения на основе вращения машины. Вы можете взглянуть на скрипт и попытаться изменить значение, если вы хотите что бы Blob тень автомобиля на дороге выглядела иначе.

Следы от шин

image

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

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

Мы создали prefab, для этого вы можете просто перетащить его на сцену:

• Перетащите Skidmarks prefab из Prefabs->VFX->Skidmarks на сцену.

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

Максимум следов от шин

Переменная Max Marks определяет количество позиций для следов от шин, которые могут существовать на сцене в любое время. Все колеса, используют те же следы от шин, так что это число рассчитывается на все колеса. При достижении следов от шин максимального количества, первая позиция будет перезаписана. Увеличение этого числа также будет увеличивать суммарную длину всех частей следов от шин в сцене.

Ширина следов от шин

Переменная (Mark Width) определяет ширину следов от шин. Она должна быть отрегулирована, чтобы соответствовать колесам созданного транспортного средства. Если это большой грузовик вы попытаетесь сделать очень широкий skidmark, который нам необходим, и если это «сверхзвуковой автомобиль» с ультра-тонкими шинами, изготовленные для установки рекорда скорости, очень тонкий skidmark будет выглядеть реалистичней.

Наземное смещение

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

Чтобы предотвратить это, вводится переменная Ground Offset (Наземное смещение). Сетка будет создана и приподнята на всю длину смещения в направлении нормали к поверхности. Так что, если некоторое мерцание существует или следы от шин пересекаются с поверхностью, попробуйте увеличить смещение. Для дальнейшего обеспечения того, чтобы следы от шин оставались на поверхности земли, используются шейдеры для следов от шин, было создано смещение, и было приписана к другой очереди визуализации (Rendering).

Минимальная дистанция

Когда новая точка добавляется в SkidmarkController она должна быть в (Min Distance) минимальном расстоянии от последней точки skidmark (следов от шин). Это гарантирует вам производительное добавление следов от шин на очень небольшие площади. Не устанавливайте это значение слишком большим, хотя это может сделать следы от шин слишком большими, и кроме того, увеличенное расстояние может показаться, будто они отстают от колес т.е. следы от шин появляются за колесами. Уменьшение значения будет в какой-то степени сглаживать следы от шин, создавая иллюзию будто следы от шин «ближе» к колесам.

Текстуры

Текстуры шин для колес от грузовика весьма разные в сравнении с текстурами шин на колесах из формулы-1 (Formula-1). Текстуры для следов от шин (skidmarks) будут создаваться на поверхности. Если вы создали другой тип автомобиля с очень разными колесами, вам нужно будет изменить эту текстуру, если вы хотите, чтобы следы от шин соответствовали колесам.

Добавление звуков

• Добавьте скрипт SoundController.js в игровой объект автомобиль «Car» (Перетащите его из Scripts/JavaScripts/SoundController.js).

Компонент Звукового контроллера (Sound Controller) имеет несколько слотов для аудиофайлов, в которые мы должны назначить разные аудиофайлы. Аудиофайлы находятся в папке Sound/Car в окне проекта (Project view).

image
Перетащите:

CarEngine_D_upper-register перетащить на слот D. Установите громкость на 0,565.
CarEngine_E_midlow-register перетащить на слот E. Установите громкость на 0.8
CarEngine_F_midhigh-register перетащить на слот F. Установите громкость на 0.78
CarEngine_K_passing-rush перетащить на слот K. Установите громкость на 0.565
CarEngine_L_lower-register перетащить на слот L. Установите громкость на 0.71
Wind-loop_stereo_22khz_16bit перетащить на слот Wind. Установите громкость на 0.8
CarEngine_DEFL_tunnel-add_small перетащить на слот Tunnel Sound. Установите громкость на 0.8
Collision1 перетащить на слот Crash Low Speed Sound. Установите громкость на 0.8
Car_crash1_smaller перетащить на слот Crash High Speed Sound. Установите громкость на 0.5
Car_skid1 перетащить на слот Skid Sound.
CarTutorialSong перетащить на слот Background Music. Установите громкость на 1.

Настройки громкости (volume settings), конечно это только настройки которые мы предлагаем. Вы можете «поиграть» с разными значениями, чтобы получить точный звуковой образ, который вы себе представляете. Или вы могли бы пойти еще дальше и создать своё собственный меню настроек для звука, позволяя настроить громкость музыки и эффектов отдельно в игре.

Завершение и сборка

Наконец перетащите следующие скрипты на игровой объект автомобиль (Car):

LightmapperObjectUV.js из (scripts/JavaScripts)
CrashController.js из (scripts/JavaScripts)
Generate2DReflection.cs из (scripts/CSharpScripts)

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

• Перейдите к Main_Camera (Главная камера) и перетащите ее на игровой объект «Car» (Автомобиль) и направьте камеру так как вам удобно для управления машиной (в рамках компонента скрипта «Car Camera» Автомобильная камера).

How to build a basic vehicle simulation environment in Unity 3D

Unity 3D is an open source Game Engine, which is primarily used to develop video games and simulations for computers, consoles and mobile devices. This article focuses on virtual vehicle simulation, the demand for which has been ever-growing with the recent advancements in the self-driving car industry. Building a simulation environment was a part of my internship at LIST, Luxembourg. Project MADSAV focuses on evaluating driver skills in advance handover situations.

The best part about Unity 3D is its simplistic approach. It has extensive documentation with scripting reference and tutorials with video and article based content.

If you are a beginner to Unity 3D, I really recommend to start learning by modelling roll-a-ball game. This 8-step video tutorials will quickly make you comfortable with the home screen consisting of hierarchy, inspector, scene, environment, camera, transformations, colliders etc. and learn basic scripts in C#.

Part 2 : Adding Assets

Unity has some widely used in-built standard assets consisting of particle systems, effects, materials, 2D objects etc. and the Unity’s asset store is a library containing 15k+ free and paid assets.

Building the Environment : For vehicle simulation, it is easy to develop a map with basic knowledge of terrain, road materials, assets and some C# codes.

Build the terrain and select the base materials. The road materials, buildings, road signs etc can be easily found on the asset store. Once you import them, place them on the 3D terrain.

One alternative way to manually develop road environment is by procedural generation. I used Road Architect which is a free and open-source road construction system efficient in building roads, lanes, extrusions, bridges, traffic lights and a lot more. The best part of using this system is that it can build a road environment in less than 30 minutes. You can find its tutorials here.

Some more road generation systems could be found here and here. Map-ity uses real world data for generating maps.

Creating a Vehicle: You can import a vehicle controller asset from the asset store or develop your own using a 3D modelling software(like Blender, TurboSquid) and a physics engine(like Vehicle Physics, Vamos Open Source etc)

I used RCC Car Controller due to its tweaking capability and it also comes with a pack of cars to choose from. The asset has developed over the years with detailed 3D models and a variety of car physics options to tune.

The physics engine for RCC is built in such a way that the suspension, brakes, steering and engine parameters can be modified with additional options for changes in ABS, traction control and tire friction coefficients to model slippery or other dangerous conditions. This is integrated in the inspector so you won’t need any additional scripts for it.

Как сделать машинку на WheelCollider’ах?

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

 

Множество игр базируются на физике автомобилей, например серия игр GTA или NFS. Так же, во многих играх транспорт является важным добавлением игровой механики – серия игр Battlefield, например. И, естественно, многие разработчики хотят добавить физику автомобилей в свой проект. Как раз для этого созданы WheelCollider’ы. Казалось бы, что может пойти нет так?

С самых первых версий Unity3D разработчики ведут неравный бой с WheelCollider’ами. Изначально проблема состояла из двух факторов:

– С одной стороны, WheelCollider’ы устроены очень примитивно, базовый функционал в Unity3D доступен ограничено.

– С другой стороны, на деле, кроме колеса и подвески нужно еще много чего написать. Объем работ, нередко, невероятно огромен.

Базовые проблемы – машина обладает низкой стабильностью поведения. В первую очередь – постоянно переворачивается. В этой статье я собрал коллекцию базовых техник, необходимых, чтобы решить проблему переворотов.

Эта статья состоит из нескольких частей:

– Перевод оригинальной статьи с сайта Unity3d.com о создании автомобиля на WheelCollider’ах.

– Трабл-шутинг, устраняем проблемы, «чтобы поехало хоть как-то»

– Несколько способов\методов\лучших практик, позволяющих сделать поведение машины на WheelCollider’ах более-менее приемлемым.

– Сборка машинки на основе очень кривой модели.

Перевод: Создание простого скелета

  1. Сначала, добавьте GameObject, который будет служить базой автомобиля. Чтобы сделать это, нажмите GameObject > CreateEmpty. Смените имя GameObject’а на car_root.
  2. Добавьте компонент Rigidbody на car_root. Стандартное значение массы в 1 кг слишком легкое для стандартных настроек подвески; установите массу на 1500 кг.
  3. Далее, создаем Collider автомобиля. GameObject > 3D Object > Cube. Расположите куб под car_root в иерархии. Сбросьте параметры компонента Transform на 0 чтобы идеально выровнять куб в локальном пространстве. Автомобиль сориентирован параллельно оси Z (Z+ это направление вперед), поэтому меняем параметр ZScale на значение 3.
  4. Добавьте колеса к базе автомобиля. Выберите car_root и кликните по нему правой клавишей, далее CreateEmptyChild. Поменяйте название на wheels. Сбросьте параметры Transform на этом объекте. Этот GameObject не обязателен, но позже он поможет для настройки и отладки.
  5. Чтобы создать первое колесо, выберите wheels GameObject, правая клавиша > CreateEmpty, назовите новый объект frontLeft. Сбросьте Transform, а потом установите координаты: X на –1, Y на 0, и Z to Чтобы добавить колайдер, в меню инспектора нажмите Addcomponent > Physics > WheelCollider.
  6. Продублируйте GameObject frontLeft (правая клавиша > Duplicate). Измените координатыX c -1 на 1. Смените имя объекта на frontRight.
  7. Выберите frontLeftand frontRight GameObject’ы. Продублируйте их. Измените координатыZ на обоих GameObject’ах на –1. Измените имена на rearLeft и rearRight.
  8. Наконец, выберите car_root приподнимите его над поверхностью земли.

У вас должно получится что-то типа этого:

Чтобы машиной можно было управлять, вам нужно написать контроллер для неё:

Создайте новый скрипт C# и назовите его SimpleCarController. Скопируйте в новый скрипт текст скрипта выше и сохраните его. Далее добавьте его на базу автомобиля (Add Component > New Script на car_root). Вы можете попробовать разные настройки и протестировать их. Такие настройки SimpleCarController очень эффективны:

У вас может быть до 20 колес на одной машине. Далее, добавим колеса. Как видите, Wheel Collider не добавляет визуальную часть колеса, поэтому нужно еще чуть-чуть кода.

Вам нужна геометрия колеса. Вы можете сделать простое колесо с помощью цилиндров. Есть несколько способов добавить визуальную часть колеса: добавить визуальную часть в параметры скрипта или написать скрипт, который будет автоматически находить и присваивать визуальную часть. Мы воспользуемся вторым вариантом. Добавьте визуальную часть колес под GameObject’ы Wheel Collider’ов.

Далее, изменяем скрипт SimpleCarController:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class AxleInfo <
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor;
public bool steering;
>

public class SimpleCarController : MonoBehaviour <
public List<AxleInfo> axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;

// находит визуальную часть колес
// устанавливает новые координаты
public void ApplyLocalPositionToVisuals(WheelCollider collider)
<
if (collider.transform.childCount == 0) <
return;
>

Transform visualWheel = collider.transform.GetChild(0);

Vector3 position;
Quaternion rotation;
collider.GetWorldPose(out position, out rotation);

visualWheel.transform.position = position;
visualWheel.transform.rotation = rotation;
>

public void FixedUpdate()
<
float motor = maxMotorTorque * Input.GetAxis(“Vertical”);
float steering = maxSteeringAngle * Input.GetAxis(“Horizontal”);

foreach (AxleInfo axleInfo in axleInfos) <
if (axleInfo.steering) <
axleInfo.leftWheel.steerAngle = steering;
axleInfo.rightWheel.steerAngle = steering;
>
if (axleInfo.motor) <
axleInfo.leftWheel.motorTorque = motor;
axleInfo.rightWheel.motorTorque = motor;
>
ApplyLocalPositionToVisuals(axleInfo.leftWheel);
ApplyLocalPositionToVisuals(axleInfo.rightWheel);
>
>
>

  • Нужно проверить настройки инпута. Есть небольшой, но реальный шанс, что инпут обнулился при создании проекта. Edit > Project Settings… > Input. Конкретно нас интересуют оси Horizontal и Vertical, должно быть, как на картинки снизу.

  • Колеса слишком высоко, по итогу колеса не касаются земли > сдвинуть колеса по Y координатам на 0.5 юнита ниже (т.е. Y = -0.5)
  • Не выставлены значения в SimpleCarController > значение maxMotorTorque = 400

Лучшие практики, устранение проблем

1. Колеса смотрят непонятно куда

В двух словах нужно использовать пустой GameObject как базу для колеса, а затем саму модель нужно повернуть на 90 градусов по Z. Не забудьте присвоить базу колеса в SimpleCarController. В реальной ситуации колесо всегда состоит из нескольких моделей, так что изменения иерархии не избежать. Далее эта часть будет усложнятся – будем добавлять тормозные диски и суппорта.

2. Машину трясет при наборе скорости, Машина переворачивается – как увеличить стабильность?

  • Поднять точку приложения силы колеса до середины колеса – в нашем случае ForceAppPointDistance = 0.5 (в настройках WheelCollider’а)
  • Правильное, корректное поведение пружины – под нагрузкой пружина пытается разжаться до длинны в состоянии «без нагрузки». Тем не менее, стандартные настройки почему-то выставлены на середину хода подвески. TargetPosition = 0 . Что-то типа стабилизаторов поперечной устойчивости. Суть стабилизаторов поперечной устойчивости – когда машина кренится, колесо, с противоположной стороны от направления крена, приподнимается выше. Таким образом машина кренится меньше. В нашем случае, мы добавляем стабилизирующие внешние силы. Мощность стабилизаторов следует выставлять в диапазоне от 0 до жесткости пружин (WheelCollider > Suspencion Spring > Spring).
  • Меньше мощность стабилизаторов – больше крен в поворотах. И еще момент: ситуация в которой автомобиль с ходом подвески в полметра и диаметром колес в один метр переворачивается на ровном месте – это нормальное, адекватное поведение автомобиля. Существует т.н. moose test, как раз, чтобы проверить подобное поведение.

Рассчитываем сжатие подвески в процентах слева и справа

-> сравниваем сжатия (левое сжатие минус правое)

-> знак результата сравнения дает направление приложения силы стабилизации (минус или плюс)

-> домнажаем то, что получилось на мощность стабилизатора

-> присваиваем в центр колеса.

Так же, есть смысл корректировать точку присваивания силы в соответствии с ForceAppPointDistance.

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

Аккерман. (на русском нет статьи на вики, тем не менее). Для того, чтобы автомобиль не заносило (а в нашем случае – еще и не переворачивало), нужно, чтобы колеса рулевого управления поворачивали в соответствии с геометрией рулевого управления Аккермана. К сожалению, WheelCollider’ы устроены так, что при определенных углах проскальзывания колеса сила стремится к бесконечности – в этот момент машина пытается перевернутся. Чтобы снизить шанс переворота, нужно написать симуляцию Аккермана. ackermanSteering = 0 означает, что колеса поворачивают параллельно, 1 означает, что Аккерман присваивается в полной мере, в соответствии с положением колес\осей относительно друг друга.

4. Настройка частоты обновления колайдеров колеса

Значения могу быть разными, зависят от конкретной настройки fixedTimeStep. В общем случае уменьшение fixedTimeStep (т.е. увеличение количества раз обработки физики в секунду) улучшает ситуацию, НО, низкие значения fixedTimeStep драматично и жестко грузят процессор. Нужно найти «золотую середину» между адекватным поведением автомобиля и нагрузкой на процессор. В данном случае fixedTimeStep = 0.02. Значения меньше 0.033 считаются очень маленькими.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class AxleInfo
<
public WheelCollider leftWheel;
public GameObject leftWheelVisuals;
private bool leftGrounded = false;
private float travelL = 0f;
private float leftAckermanCorrectionAngle = 0;

public WheelCollider rightWheel;
public GameObject rightWheelVisuals;
private bool rightGrounded = false;
private float travelR = 0f;
private float rightAckermanCorrectionAngle = 0;

public bool motor;
public bool steering;

public float Antiroll = 10000;
private float AntrollForce = 0;

public float ackermanSteering = 1f;

public void ApplyLocalPositionToVisuals()
<
//left wheel
if (leftWheelVisuals == null)
<
return;
>
Vector3 position;
Quaternion rotation;
leftWheel.GetWorldPose(out position, out rotation);

leftWheelVisuals.transform.position = position;
leftWheelVisuals.transform.rotation = rotation;

//right wheel
if (rightWheelVisuals == null)
<
return;
>

rightWheel.GetWorldPose(out position, out rotation);

rightWheelVisuals.transform.position = position;
rightWheelVisuals.transform.rotation = rotation;
>
public void CalculateAndApplyAntiRollForce(Rigidbody theBody)
<
WheelHit hit;

leftGrounded = leftWheel.GetGroundHit(out hit);
if (leftGrounded)
travelL = (-leftWheel.transform.InverseTransformPoint(hit.point).y – leftWheel.radius) / leftWheel.suspensionDistance;
else
travelL = 1f;

rightGrounded = rightWheel.GetGroundHit(out hit);
if (rightGrounded)
travelR = (-rightWheel.transform.InverseTransformPoint(hit.point).y – rightWheel.radius) / rightWheel.suspensionDistance;
else
travelR = 1f;

AntrollForce = (travelL – travelR) * Antiroll;

if (leftGrounded)
theBody.AddForceAtPosition(leftWheel.transform.up * -AntrollForce, leftWheel.transform.position);
if (rightGrounded)
theBody.AddForceAtPosition(rightWheel.transform.up * AntrollForce, rightWheel.transform.position);

>
public void CalculateAndApplySteering (float input, float maxSteerAngle, List<AxleInfo> allAxles)
<
//first find farest axle, we got to apply default values
AxleInfo farestAxle = allAxles[0];
//calculate start point for checking
float farestAxleDistantion = ((allAxles[0].leftWheel.transform.localPosition – allAxles[0].rightWheel.transform.localPosition) / 2f).z;
for (int a = 0; a < allAxles.Count; a++)
<
float theDistance = ((allAxles[a].leftWheel.transform.localPosition – allAxles[a].rightWheel.transform.localPosition)/ 2f).z;
// if we found axle that farer – save it
if (theDistance < farestAxleDistantion)
<
farestAxleDistantion = theDistance;
farestAxle = allAxles[a];
>
>
float wheelBaseWidth = (Mathf.Abs( leftWheel.transform.localPosition.x) + Mathf.Abs( rightWheel.transform.localPosition.x))/2;
float wheelBaseLength = Mathf.Abs( ((farestAxle.leftWheel.transform.localPosition + farestAxle.rightWheel.transform.localPosition)/ 2f).z) +
Mathf.Abs(((leftWheel.transform.localPosition + rightWheel.transform.localPosition) / 2f).z);

float angle = maxSteerAngle * input;
//ackerman implementation
float turnRadius = Mathf.Abs(wheelBaseLength * Mathf.Tan(Mathf.Deg2Rad * (90 – Mathf.Abs(angle))));
//38.363
if (input != 0)
<
//right wheel
if (angle > 0)

rightAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius – wheelBaseWidth / 2f));
rightAckermanCorrectionAngle = (rightAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
rightAckermanCorrectionAngle = Mathf.Sign(angle) * rightAckermanCorrectionAngle;

>
else

rightAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius + wheelBaseWidth / 2f));
rightAckermanCorrectionAngle = (rightAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
rightAckermanCorrectionAngle = Mathf.Sign(angle) * rightAckermanCorrectionAngle;

>

//left wheel
if (angle > 0)
leftAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius + wheelBaseWidth / 2f));
leftAckermanCorrectionAngle = (leftAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
leftAckermanCorrectionAngle = Mathf.Sign(angle) * leftAckermanCorrectionAngle;
>
else
leftAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius – wheelBaseWidth / 2f));
leftAckermanCorrectionAngle = (leftAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
leftAckermanCorrectionAngle = Mathf.Sign(angle) * leftAckermanCorrectionAngle;
>

>
else
<
rightAckermanCorrectionAngle = 0f;
leftAckermanCorrectionAngle = 0f;
>
leftWheel.steerAngle = leftAckermanCorrectionAngle;
rightWheel.steerAngle = rightAckermanCorrectionAngle;

>
>

[RequireComponent(typeof(Rigidbody))]
public class SimpleCarController : MonoBehaviour
<
public List<AxleInfo> axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;

private Rigidbody body;
private void Start()
<
body = GetComponent<Rigidbody>();

for (int a = 0; a < axleInfos.Count;a++)
<
axleInfos[a].leftWheel.ConfigureVehicleSubsteps(5, 12, 15);
axleInfos[a].rightWheel.ConfigureVehicleSubsteps(5, 12, 15);
>
>

public void FixedUpdate()
<
float motor = maxMotorTorque * Input.GetAxis(“Vertical”);

foreach (AxleInfo axleInfo in axleInfos)
<
if (axleInfo.steering)
<
axleInfo.CalculateAndApplySteering(Input.GetAxis(“Horizontal”), maxSteeringAngle, axleInfos);
>
if (axleInfo.motor)
<
axleInfo.leftWheel.motorTorque = motor;
axleInfo.rightWheel.motorTorque = motor;
>
axleInfo.ApplyLocalPositionToVisuals();
axleInfo.CalculateAndApplyAntiRollForce(body);
>
>
>

Как правильно добавить графику и модели

1. Для начала нужна модель автомобиля. В общем случае, есть 3 варианта где её достать: заказать у специалиста по игровым 3D моделям, купить/скачать с Asset store, скачать с стороннего сайта.

Нужно иметь ввиду, что модели, «выдраные» из игр нельзя использовать в комерческих играх. Так же, стоит обратить внимание, что модели для рендеренга видео и модели из google sketchup не подходят принципиально из-за их внутренней структуры. В общем случае, при всех равных условия, подобные модели требуют в 2 раза больше ресурсов компьютера.

Для тестов мы воспользуемся сайтом gamemodels.ru. Это сайт, на котором модеры (люди, занимающиеся модифициями игр) выкладывают модели, «выдраные» из всевозможных игр. Ссылка на используемую модель

2. Создайте папку Models в ассетах игры. Распакуйте архив, и добавьте содержимое в папку Models

3. Зайдите в папку и перетащите файл “r34” на сцену. Должно получится так:

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

4. В иерархии жмем правой клавишей на объект r34 и жмем «Unpack prefab». Это нужно, чтобы можно было корректировать иерархию, названия, добавлять скрипты.

5. Под объектом r34 нужно создать пустой объект, назвать его Wheels, убедится, что этот объект находится на координатах 0.

6. В Scene view кликаем на колеса и диски – перетаскиваем их под объект Wheels

7. Внимание! Кликаем на колесо, смотрим координаты. Колесо, вроде, находится на дальней стороне автомобиля. И, вроде, гизмо контроля положения в его центре. А вот координаты почему-то на нуле. Это нормально – реальный центр колеса находится в центре автомобиля. Чтобы решить эту проблему создаем 3 пустых объекта на каждое колесо – один для WheelCollider’а, второй для визуальной части колеса, третий для калиперов. Далее, чтобы быстрее\проще их разместить можно воспользоватся изометрическим видом. Для этого кликните на одну из осей в правом верхнем углу Scene View. Чтобы вернутся в вид перспективы – кликните на сам центральный белый кубик. Координаты центров колес: FR(0.78, 0.32399, 1.399); FL(-0.78, 0.32399, 1.399); RL(-0.78, 0.32399, -1.26), RR(0.78, 0.32399, -1.26).

8. Переименовываем колеса в соответствии с иерархией, использованной в начале статьи: корневой объект называем в соответствии с положением (например FR_Wheel это front-right wheel, переднее правое колесо). Копируем, добавляем Visual (например, FR_WheelVisual). Добавляем под базовый объект покрышки, диски и тормозные диски. Называем покрышки Tire, тормозные диски называем BrakeDisc. Для тормозных скоб (калиперов) создаем копии базового объекта, называем в соответствии с положение – FR_Caliper и оставляем их на том же уровне иерархии, что базовые объекты колеса, добавляем под них соответствующий калипер. Должно получится вот так:

9. Создаем пустой объект под r34, назваем его Body. Перетаскиваем под него всю крупную геометрию автомобиля, в т.ч. стекла фар. На этом скриншоте я отключил отображение геометрии, которую нужно отправить под объект Body, т.е. видно только то, что трогать не надо.

10. Выделяем все объекты под Body. Добавляем компонент MeshCollider (на панеле инспектора AddComponent -> MeshCollider) и жмем галочку Convex. Должно получится так:

Суть: если нужно, чтобы сталкивались два колайдера произвольной геометрии, то один из них должен быть «Convex». Такие колайдеры генерируются используя точки, максимально удаленные от центра модели.

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

11. На коренной объект (r34) добавляем скрипт, контролирующий автомобиль.

12. На пустые объекты XX_Wheel добавляем WheelCollider’ы

13. Если запустить игру, как только WheelColider’ы касаются земли, машина улетает за горизонт. Причина в том, что WheelColider’ы взаимодействуют с колайдерами кузова автомобиля И в Rigidbody не выставлен параметр массы. Для того, чтобы решить эту проблему, нужно настроить слои объектов и настроить Collision Matrix (матрицу столкновений), чтобы объекты разных слоев не сталкивались. Кликаем по корневому объекту автомобиля (r34). На инспекторе, сверху слева Layer – Add Layer… Называем новый слой Car. Опять выбираем корневой объект автомобиля (r34) и там же выбираем слой Car. В диалоговом окне спросят хотим ли мы присовить все объекты иерархии к этому слою. Выбираем «yes, change children».

Повторяем операцию с объектом Wheels, новый слой будет называться Wheel.

Далее Edit -> Project Settings… -> Physics

В матрице столкновений отключаем взаимодействие слоев Car и Wheel, должно выглядеть так:

И выставляем в Rigidbody Mass = 1500.

14. Выставляем параметры WheelCollider’ов: Radius = 0.315; ForceAppPointDistance = 0.315; TargetPosition = 0;

15. Корректируем управляющий скрипт, для работы с калиперами

16. Колеса ходят «восьмерками»

Причина в том, что изначальная модель вырезана с небольшим отрицательным развалом колес. Поправляем модельки калиперов и самого колеса, на левой стороне ставим RotationZ = 4.5; на правой RotationZ = -4.5;

Восьмерка хоть и пропала, но колесо дергает вверх-вниз. Чтобы как-то сгладить ситуацию нужно подвинуть визуальные части колеса немного ниже, до Y = -0.269.

Так же, хочу обратить ваше внимание, что подобного рода проблемы возникают всегда, вне зависимости от качества базовых моделей\ассетов. Если вы хотите, чтобы Ваша система физики автомобиля была жизнеспособна, нужно учитывать подобного рода проблемы.

17. Настройка посадки

Ставим на всех WheelCollider’ах позицию Y на 0.47, а SuspencionDistance на 0.2.

Да, много работы ��

Но, в общем, если пользоваться «нормальными» моделями автомобилей, процесс гораздо быстрее.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *