This tutorial takes you through the process of creating a basic functioning four-wheeled car with the PhysX Wheel colliderA 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.
The steps include:
To follow these instructions, you need:
To create a ground surface:
Ground
. This plane is the ground that the car drives on.First, place the Car model in the SceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary:
Assets
folder (Project tab) More infoCar
asset.Assets
folder (the default location).Take a look at the Car GameObject’s hierarchy in the Hierarchy window. There is a root GameObject called Car
, and child GameObjects for the car body model and each wheel model.
Configure the car body for collisionA collision occurs when the physics engine detects that the colliders of two GameObjects make contact or overlap, when at least one has a Rigidbody component and is in motion. More info
See in Glossary:
Car
root GameObject, add a RigidbodyA component that allows a GameObject to be affected by simulated gravity and other forces. More infoCar Body
GameObject, add a Mesh colliderA free-form collider component which accepts a mesh reference to define its collision surface shape. More infoTo add Wheel colliders to the wheel models, you need to create four new separate GameObjects at the same position as the wheel models (but not as child GameObjects of the wheels).
A fast way to set this up at approximately the same position is to duplicate the wheel GameObjects and then configure the new GameObject:
Wheel Back Left (1)
. For clarity, add the word “Collider” to the GameObject name instead; for example, Wheel Back Left collider
.The Car GameObject hierarchy should now look like this:
Next, you need to adjust the Wheel colliders’ position and size to match the wheel models.
When you select a Wheel collider, the Scene viewAn interactive view into the world you are creating. You use the Scene View to select and position scenery, characters, cameras, lights, and all other types of Game Object. More info
See in Glossary displays a gizmoA graphic overlay associated with a GameObject in a Scene, and displayed in the Scene View. Built-in scene tools such as the move tool are Gizmos, and you can create custom Gizmos using textures or scripting. Some Gizmos are only drawn when the GameObject is selected, while other Gizmos are drawn by the Editor regardless of which GameObjects are selected. More info
See in Glossary which provides a visualization of the Wheel collider settings (see Wheel collider visualization). You can use the gizmo to check the position and size of the Wheel collider against the position and size of the wheel model.
To see the wheel orientation and the gizmo more clearly, set the Scene’s Draw mode to Wireframe and the Scene orientation to Isometric.
When you first add the Wheel colliders with the workflow described in Add Wheel colliders, they are too low (in the Scene view, the Wheel collider circle appears below the wheel model mesh). This is because the Suspension Distance starts from these GameObjects’ positions, and extends downwards by the distance specified in the Suspension Distance setting. The Scene view visualization displays the Suspension Distance as an orange line down the Y axis of the Wheel collider’s gizmo.
The green circle outline displays the wheel at the halfway point of the suspension distance extents, and should be considered the wheel’s normal position, when the car is not squashed down or raised up on its suspension. Therefore the green outline of each Wheel collider needs to be centered over its corresponding wheel mesh.
To correct this, you need to move the WheelCollider GameObjects up (on the Y axis) by half the value of the Wheel collider’s Suspension Distance. In this example project, the Suspension Distance is 0.3 (the default value), so you need to move the Wheel collider GameObjects up by 0.15 units.
Unity allows you to enter simple mathematical calculations into numeric fields. You can use this to add to the Y axis value.
+0.15
to the end of the value (for example, if the value is 0.5, the value should now read 0.5+0.15
).Unity applies +0.15 to the previous value, which moves the Wheel collider GameObjects up the Y axis by 0.15 units.
The Wheel collider gizmo should now be perfectly centered on the wheel meshes:
When you first add the Wheel colliders with the workflow described in Add Wheel colliders, they are too big (in the Scene view, the Wheel collider gizmo is larger than the wheel model mesh).
To correct this accurately, you need to know the exact radius of the wheel model. This information should be available from your 3D modeling software, or from the technical artist who authored the model.
In this example project, the radius of the wheel model is 0.44.
0.44
.If the exact radius of a wheel model is unknown or unavailable, you can use the Wheel collider gizmo to approximately match its radius to the model. Alternatively, you can use a Sphere colliderA sphere-shaped collider component that handles collisions for GameObjects like balls or other things that can be roughly approximated as a sphere for the purposes of physics. More info
See in Glossary to get the radius, because the Sphere collider automatically resizes to encompass the mesh of its associated model.
To get the radius with a Sphere collider:
The Wheel colliders should now exactly match the position and size of the wheel models.
To control the car, you need to add scriptsA piece of code that allows you to create your own Components, trigger game events, modify Component properties over time and respond to user input in any way you like. More info
See in Glossary to the project that do the following:
In this example, we use two scripts to do this: CarControl.cs
and WheelControl.cs
.
Create a C# file named CarControl.cs
, and paste in the code below:
using UnityEngine;
public class CarControl : MonoBehaviour
{
public float motorTorque = 2000;
public float brakeTorque = 2000;
public float maxSpeed = 20;
public float steeringRange = 30;
public float steeringRangeAtMaxSpeed = 10;
public float centreOfGravityOffset = -1f;
WheelControl[] wheels;
Rigidbody rigidBody;
// Start is called before the first frame update
void Start()
{
rigidBody = GetComponent<Rigidbody>();
// Adjust center of mass vertically, to help prevent the car from rolling
rigidBody.centerOfMass += Vector3.up * centreOfGravityOffset;
// Find all child GameObjects that have the WheelControl script attached
wheels = GetComponentsInChildren<WheelControl>();
}
// Update is called once per frame
void Update()
{
float vInput = Input.GetAxis("Vertical");
float hInput = Input.GetAxis("Horizontal");
// Calculate current speed in relation to the forward direction of the car
// (this returns a negative number when traveling backwards)
float forwardSpeed = Vector3.Dot(transform.forward, rigidBody.velocity);
// Calculate how close the car is to top speed
// as a number from zero to one
float speedFactor = Mathf.InverseLerp(0, maxSpeed, forwardSpeed);
// Use that to calculate how much torque is available
// (zero torque at top speed)
float currentMotorTorque = Mathf.Lerp(motorTorque, 0, speedFactor);
// …and to calculate how much to steer
// (the car steers more gently at top speed)
float currentSteerRange = Mathf.Lerp(steeringRange, steeringRangeAtMaxSpeed, speedFactor);
// Check whether the user input is in the same direction
// as the car's velocity
bool isAccelerating = Mathf.Sign(vInput) == Mathf.Sign(forwardSpeed);
foreach (var wheel in wheels)
{
// Apply steering to Wheel colliders that have "Steerable" enabled
if (wheel.steerable)
{
wheel.WheelCollider.steerAngle = hInput * currentSteerRange;
}
if (isAccelerating)
{
// Apply torque to Wheel colliders that have "Motorized" enabled
if (wheel.motorized)
{
wheel.WheelCollider.motorTorque = vInput * currentMotorTorque;
}
wheel.WheelCollider.brakeTorque = 0;
}
else
{
// If the user is trying to go in the opposite direction
// apply brakes to all wheels
wheel.WheelCollider.brakeTorque = Mathf.Abs(vInput) * brakeTorque;
wheel.WheelCollider.motorTorque = 0;
}
}
}
}
Add this CarControl.cs
script to the Car
root GameObject.
The CarControl.cs
script handles car behavior such as acceleration, torque, and braking, based on user input. See the code comments for details.
Some elements of the CarControl.cs
script refer to the WheelControl.cs
script created in the next section.
Create a C# file named WheelControl.cs
, and paste in the code below:
using UnityEngine;
public class WheelControl : MonoBehaviour
{
public Transform wheelModel;
[HideInInspector] public WheelCollider WheelCollider;
// Create properties for the CarControl script
// (You should enable/disable these via the
// Editor Inspector window)
public bool steerable;
public bool motorized;
Vector3 position;
Quaternion rotation;
// Start is called before the first frame update
private void Start()
{
WheelCollider = GetComponent<WheelCollider>();
}
// Update is called once per frame
void Update()
{
// Get the Wheel collider's world pose values and
// use them to set the wheel model's position and rotation
WheelCollider.GetWorldPose(out position, out rotation);
wheelModel.transform.position = position;
wheelModel.transform.rotation = rotation;
}
}
Add this script to each Wheel collider GameObject.
The WheelControl.cs
script uses WheelCollider.GetWorldPose
to get the Wheel collider’s position in the scene. The script then assigns that position information to a specified wheel model GameObject. See the code comments for details.
Each instance of the WheelControl.cs
script must have a reference to its corresponding wheel model GameObject.
To assign the correct wheel model GameObject to each Wheel collider:
You also need to select which wheels receive motor input and steering input from the CarControl script. To simulate a four-wheel drive car via the Wheel Control properties:
To test the car, enter Play mode and use the arrow or WASD keys to move and steer. Note that input controls only work when the Game view has focus.
To get a better view of the car moving around the Scene:
Car
root GameObject in the Scene view, then press Shift + F.Now that you have a basic setup, you can try changing different settings to observe how they affect the movement of the car. You can also follow these instructions with different car models and observe the similarities and differences in their setup.