This tutorial takes you through the process of creating a basic functioning four-wheeled car with the PhysX Wheel collider.
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 Scene:
Car
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 collision:
Car
root GameObject, add a Rigidbody component.Car Body
GameObject, add a Mesh collider component.To 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 view displays a gizmo 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 collider 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 scripts 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.