In Unity, there are multiple approaches to creating vehicle movements. While one simple method involves moving a vehicle object in 3D space and adding wheel rotation animations, this approach lacks realism as it ignores physics.

To accurately simulate vehicle movement, Unity provides a specialized component called WheelCollider. This collider is designed to mimic the behaviour of grounded vehicle wheels. The attached vehicle can be realistically moved by applying forces to the wheel colliders, similar to real-world vehicles.

The WheelCollider component offers various properties that can be adjusted, such as mass, radius, suspension settings, and friction settings, allowing users to fine-tune the physical properties and achieve the desired effect.

ℹ️
Find more details about the wheel collider on the official Unity documentation.

1. Getting Started

We will import a vehicle object (3D model of a vehicle) to make it more realistic and attractive from the Unity asset store. Don't worry; many free assets are available in the Unity asset store. This one is very small in size and free too.

However, if you prefer, you can also use your own 3D model of a vehicle or follow along using the basic primitive 3D objects provided by Unity (such as cubes and cylinders).

2. Starting the Project

  • Open the Unity Hub and click on the New Project button to create a new project.
  • Select 3D core from the list of available templates, give the project a proper name and location.
  • You will have a sample scene created and opened for you with a Main Cameraand Directional Light in the scene. In your project view, you can find the scene inside Assets > Scenes > SampleScene. You can rename the scene if you want.

3. Importing the Assets

  • Click on the Add to My Assets button on the Unity Assets store. You may need to sign in with your Unity account if you have not signed in already.
  • Accept the ToS and EULA if prompted. This will add the asset to your account.
  • Then click on Open in Unity and open the link. It will open the Package Manager with the option to download the asset into your project. Make sure the car asset is selected, and click on the Download button.
  • Once the download completes, it will show a button to import the asset into the project. Click on the Import button on the Package Manager. You should see a new folder inside your Assets folder containing the imported assets.
New folder containing the imported assets
Assets folder with the imported assets
  • If you want to use a 3D model that you already have on your device, you can simply drag and drop it into your Project Window.

4. Setting Up the Scene

  • Add a plane to the scene from the + button in the Hierarchy window and give it a scale of 100 along the x-axis and z-axis, so that we have enough area to drive the car around.
Adding a plane from the + button in the hierarchy window
Hierarchy window
Selecting 100 in X-axis and Z-axis in the plane option
Plane options in the Hierarchy window
  • Find the vehicle2-blue object inside Assets > LowPolyVehicle2 > Models. Drag and drop it into the hierarchy. You should see the car model in the Scene View too.
finding vehicle2-blue object inside the models window in lowpolyvehicles option
Models window
  • Did you notice how the vehicle2-blue object is blue while the others are not? It is because it is set as a prefab object. We will make changes within this object, so let's unpack it completely.
  • Right-click the object and select Prefab > Unpack Completely.
  • Let's rename the object to 'Car'.
unpacking the object completely and renaming it Car
Unpacking the object

5. Setting Up the Vehicle Physics

We need to add the Colliders and Rigidbody components to our vehicle to use it as a physical object with physical properties. For that, follow the listed steps.

  • Select the Car object and click the Add Component button on the inspector.
    Click on the Search box and type Rigidbody. You will see two matching components, Rigidbody and Rigidbody 2D. Rigidbody is used for 3D objects, while Rigidbody 2D is used for 2D objects.
  • Click on Rigidbody to add rigidbody components to the object, Car.
  • Within the Rigidbody component properties, update the mass of the car from 1 to 1500 (kg) and drag to 0.01 (optional).
  • Click on Add Component and type Box Collider.
  • Select Box Collider from the filtered list to add a box collider component to the object, Car.
  • Within the Box Collider component, adjust the Size and Center of the collider to match the base of the car.
✍️
Note: You can use Mesh Collider or combine multiple colliders to match the shape of the vehicle. I will be using a single Box Collider for demo purposes.
Setting up the vehicle physics for the object car
Vehicle Physics Setup

6. Setting Up Vehicle Components

Let us take a look at the Car object. If we expand it, we can see the body, doors, windows, wheels, etc., as the Child Objects of the main Car object.
Let's group the wheels together.

  • Right-click the Car object and click on Create Empty. It will add an empty object inside the Car object. (Make sure its Transform Values are set to Default, i.e., 0's for position and rotation and 1's for scale).
  • Rename the newly created object as Wheels.
  • Select all four wheel object WheelBL, WheelBR, WheelFL, WheelFR within the Car object and drag them into Wheels. This will make them child-objects of Wheels.
Setting up the wheel components for the object 'car'
Setting up wheels components
ℹ️
Note: Grouping the objects is optional.
  • Similarly, create another empty object inside car and rename it as WheelColliders. Again, create an empty object inside WheelColliders and rename it as WCFL.
Creating wheel colliders
Creating Wheel Colliders
  • Select the WCFL object and click on Add Component button in the Inspector view. Type WheelCollider in the search box and select the WheelCollider option from the filtered list. This action adds a wheel collider component.
  • You may need to select the Car object to see the WheelCollider component on the scene view. Move the WCFL object to align its Center with one of the car wheels. Then adjust its radius in the Inspector view to match the size of the car wheel.
adding and optimizing wheelcollider component values
Adding WheelCollider components
  • We need to move WCFL to WheelFL position. Copy the transform values of WheelFL onto WCFL and adjust the Y-position value manually.
moving the values of WCFL to WheelFL
Moving WCFL values to WheelFL
  • Duplicate WCFL three times and rename them as WCFR, WCBL and WCBR respectively. Copy the positions of WheelFR, WheelBL and WheelBR onto WCFR, WCBL and WCBR respectively.
duplicating WCFL three times and renaming them WCFR, WCBL and WCBR respectively
Duplicating WCFL
Setting the values of WCFR, WCBL and WCBR
Setting the component values of WCFR, WCBL and WCBR
  • Create an empty object within Car and rename it to CenterOfMass. Then position it somewhere Center at the base of the car body. This will be used to set the center of mass of the car. It is recommended to place it a little forward from the center (closer to the engine) because that is the center of mass in real cars.

7. Setting Up Input

Our vehicle is now set up and ready to move. We need to read the input from the user, which controls the vehicle movements.

  • Create a C# script named InputController.cs.
  • Add the following properties in the script to read input values from the user:
using UnityEngine;
public class InputController : MonoBehaviour
{
    public float Horizontal { get; private set; }
    public float Vertical { get; private set; }
    public float Brake { get; private set; }
}
Declare properties for input values

Here, each property uses a public get and a private set. This allows the values to be accessed from outside this script but modified/controlled within this script only.

  • Now, let us read the input values and assign them to the properties declared above from the Update method.
using UnityEngine;
public class InputController : MonoBehaviour
{
    public float Horizontal { get; private set; }
    public float Vertical { get; private set; }
    public float Brake { get; private set; }

    void Update()
    {
        Horizontal = Input.GetAxis("Horizontal");
        Vertical = Input.GetAxis("Vertical");
        Brake = Input.GetAxis("Jump");
    }
}
Read input into properties

Our script is ready to read input from the user. Now we need to attach it to a GameObject.

  • Create an empty GameObject in the hierarchy and rename it as InputController. Then attach the script we just wrote to the GameObject.
Creating InputController GameObject

8. Controlling the Vehicle with Input

Now, we will use the input values to control the vehicle movements.

  • Create a C# script named VehicleController.cs.
  • Declare some variables that are used to control the vehicle movements:
    - Force will be used to drive the vehicles using WheelColliders.
    - Positive value and negative value of force will move the vehicle forward and in reverse, respectively.
    - Angle will be used to steer the vehicle left or right.
    - BrakeForce will be used to apply brakes.
using UnityEngine;
public class VehicleController : MonoBehaviour
{
    public InputController InputCtrl;
    [Tooltip("Set ref in order of FL, FR, RL, RR")]
    public WheelCollider[] WheelColliders;

    [Tooltip("Set ref of wheel meshes in order of  FL, FR, RL, RR")]
    public Transform[] Wheels;

    public Transform CenterOfMass;

    public int Force;
    public int Angle;
    public int BrakeForce;
}

Creating VehicleController.cs

Let's create methods to use these values in action.

Here, we assume the vehicle is a front-wheel drive, and we use indices 0 and 1 to reference front WheelColliders. We use motorTorque to apply rotating force on the front WheelColliders , which results in the vehicle's movement. Similarly, steerAngle and brakeTorque are used to apply steering and braking force, respectively.

using UnityEngine;
public class VehicleController : MonoBehaviour
{
    ...
    public int BrakeForce;
    
    private void Drive()
    {
        WheelColliders[0].motorTorque = WheelColliders[1].motorTorque = InputCtrl.Vertical * Force;
    }

    private void Steer()
    {
        WheelColliders[0].steerAngle = WheelColliders[1].steerAngle = InputCtrl.Horizontal * Angle;
    }

    private void Brake()
    {
        WheelColliders[0].brakeTorque = WheelColliders[1].brakeTorque = InputCtrl.Brake * BrakeForce;
    }
}

Creating methods for VehicleController.cs
  • The above code updates the WheelColliders and results into vehicle movements, but the wheels (tyres) of the vehicles are not updated. Note that the WheelColliders are not visible in the gameplay.
  • Moving a vehicle without moving the visible wheels would be unrealistic. So, the next step is to move the wheels to match the vehicle's movement. To achieve this, we will copy the WheelCollider movements (positions, rotations) onto the wheel-transforms.
using UnityEngine;
public class VehicleController : MonoBehaviour
{    
    ...
    private void Brake()
    {
        ...
    }
  
    private void UpdateWheelMovements()
    {
        for (var i = 0; i < Wheels.Length; i++)
        {
            Vector3 pos;
            Quaternion rot;
            WheelColliders[i].GetWorldPose(out pos, out rot);
            Wheels[i].transform.position = pos;
            Wheels[i].transform.rotation = rot;
        }
    }
}

We have the methods to move the vehicle. Let's call them inside FixedUpdate function.

using UnityEngine;
public class VehicleController : MonoBehaviour
{
    ...
    private void UpdateWheelMovements()
    {
       ...
    }
    private void FixedUpdate()
    {
        Steer();
        Drive();
        Brake();
        UpdateWheelMovements();
    }
}

  • This should be enough to make the vehicle move, turn, etc. Let's make it more stable so it won't trip over while steering. We will use centerOfMass position for this purpose. The lower the center of mass, the more stable the vehicle. Rigidbody of the vehicle is used to set the centerOfMass position. We will set that in the Start method. We can access the Rigidbody component using GetComponent<Rigidbody>().
using UnityEngine;
public class VehicleController : MonoBehaviour
{
    ...
    private void FixedUpdate()
    {
        ...
    }
    private void Start()
    {
        GetComponent<Rigidbody>().centerOfMass = CenterOfMass.localPosition;
    }
}

That's it. Our VehicleController script is ready. Let's move some methods up/down and see the final script.

using UnityEngine;
public class VehicleController : MonoBehaviour
{
    public InputController InputCtrl;
    [Tooltip("Set ref in order of FL, FR, RL, RR")]
    public WheelCollider[] WheelColliders;

    [Tooltip("Set ref of wheel meshes in order of  FL, FR, RL, RR")]
    public Transform[] Wheels;

    public Transform CenterOfMass;

    public int Force;
    public int Angle;
    public int BrakeForce;

    private void Start()
    {
        GetComponent<Rigidbody>().centerOfMass = CenterOfMass.localPosition;
    }

    private void FixedUpdate()
    {
        Steer();
        Drive();
        Brake();
        UpdateWheelMovements();
    }
	
	//Drive forward/backward
    private void Drive()
    {
        WheelColliders[0].motorTorque = WheelColliders[1].motorTorque = InputCtrl.Vertical * Force;
    }
    
	//Steer left/right
    private void Steer()
    {
        WheelColliders[0].steerAngle = WheelColliders[1].steerAngle = InputCtrl.Horizontal * Angle;
    }

	//Apply brakes
    private void Brake()
    {
        WheelColliders[0].brakeTorque = WheelColliders[1].brakeTorque = InputCtrl.Brake * BrakeForce;
    }

	//imitate the wheelcollider movements onto the wheel-meshes
    private void UpdateWheelMovements()
    {
        for (var i = 0; i < Wheels.Length; i++)
        {
            Vector3 pos;
            Quaternion rot;
            WheelColliders[i].GetWorldPose(out pos, out rot);
            Wheels[i].transform.position = pos;
            Wheels[i].transform.rotation = rot;
        }
    }
}
  • It is time to attach this script to a GameObject and provide the necessary references.
  • Let's create an empty GameObject inside the vehicle to mark the CenterOfMass position.
Marking the CenterOfMass
  • Attach VehicleController.cs script onto the Car object and provide references.
Providing references to the Car object

Now, your vehicle is ready to be controlled using arrows or WSAD keys and Spacebar. You can experiment by tweaking the values until you find the movements of your liking. Congratulations on making your first vehicle simulation using wheel colliders in Unity.

Thank you for reading. I hope it was helpful and easy to follow. More on vehicle controller coming soon.