Saturday, 26 September 2015

Unity Car Tutorial Part 1: Making a Simple Car



Part 1: Making a Simple Car

 Disclaimer: part one was taken from and modified from the base unity 5 tutorials; I felt it was needed as a base to build off of for the rest of the tutorials.


So the first thing we need to do is build a basic car. For this tutorial I will be only using primitives.

1. Create a 3d Plane (GameObject – 3D Object – Plane)
-Set Position to (0, 0, 0)
-Set Scale to (100, 1, 100)

2. Create Empty Game Object (GameObject – Create Empty)
-Set Position to (0, 0, 0)
                -Rename to Car
                -Add Component Rigidbody
                                -Set Mass to 500 (If to little it will fly away)

3. Now Create a Cube (GameObject – 3D Object – Cube)
-Set Position to (0, 0, 0)
-Set Scale to (1, 1, 3) [Forward and backwards will be in the Z axis]
-Rename to CarMesh
-Make the Make “CarMesh” a child to the Car

4. Create Empty Game Object (GameObject – Create Empty)(Not Child)
                -Rename to Wheels
                - Make it a child of Car

5. Duplicate Wheels
                -Rename to frontRightWheel
                -Add component Wheel Collider
                -Make it a child of Wheels
                -Set Position to (1, 0, 1)

6. Duplicate frontRightWheel
                -Rename to frontLeftWheel
                -Set Position to (-1, 0, 1)

7. Duplicate both frontRightWheel and frontLeftWheel
                -Rename one to rearRightWheel
                                -Set Position to (1, 0, -1)
                -Rename one to rearLeftWheel
                                -Set Position to (-1, 0, -1)

It should now look like this (My Plane is disabled for this image)
 

8. Move Car above the plane and have Car selected and press play.
                -See the wheel springs bounce? Now we make the wheels move.

9. Create a new C# script (Right Click – Create – C# Script)
                -Name it SimpleCarController

10. Add to SimpleCarController

    //The maximum amount of power put out by each wheel.
    public float maxTorque = 500f;

    //The max distance a wheel can turn.
    public float maxSteerAngle = 45f;

    //The physics of the wheels, max 20 axels.
    //WheelCollider[4] 4 is how many wheels we have.
    public WheelCollider[] wheelCollider = new WheelCollider[4];

    // Update every fixed framerate frame, use this when dealing with Rigidbody
    public void FixedUpdate()
    {
        //Turn the wheels to a set max, with an input.
        float steer = Input.GetAxis("Horizontal") * maxSteerAngle;
        //Move forward or backwards based on the maxTorque, with an input.
        float torque = Input.GetAxis("Vertical") * maxTorque;

        //Sets which wheels turn, this is the two front wheels.
        wheelCollider[0].steerAngle = steer;
        wheelCollider[1].steerAngle = steer;

        //Sets which wheels move forward or backwards.
        for (int i = 0; i < 4; i++)
        {
            wheelCollider[i].motorTorque = torque;
        }
    }

Back to Unity

11. Place SimpleCarController on to Car
                 













12. Open up Wheel Collider and place the Wheels in this order (The order will matter later)
                                frontRightWheel
                                frontLeftWheel
                                rearRightWheel
                                rearLeftWheel

13. Make the Main Camera a child of Car, place it where you can see the whole car.
                -Press play, you should now be able to drive around.
Your car may vibrate after you turn or reach a certain speed. That is because we do not have real wheels, just the physics of a wheel; so we need colliders for wheel objects.

14. Create an Empty GameObject (GameObject – Create Empty)
                -Name it frontRightWheelObject
                -Make it a child of frontRightWheel
                -Set Position to (0, 0, 0)

15. Create a Cylinder
                -Set Scale to (1, 0.1, 1)
                -Set Rotation to (0, 0, 90)
                -Rename to frontRightWheelMesh
                -Make it a child of frontRightWheelObject
                -Set Position to (0, 0, 0)

It should now look like this

16. Do the same for the other 3 wheels following the same naming convention.
                -They may be slightly above the Wheel Collider, just ignore it for now we will fix it in    code.

Press play now, it will no longer vibrate, but the wheels will not be rotating when you go forward or turn. We must set that up in code.

 17. Go to the script SimpleCarController and add

    //Each wheel needs its own mesh
    public Transform[] wheelMesh = new Transform[4];

    public void Update()
    {
        //Sets the wheel meshs to match the rotation of the physics WheelCollider.
        UpdateMeshPosition();
    }

    //Sets each wheel to move with the physics WheelColliders.
    public void UpdateMeshPosition()
    {
        for (int i = 0; i < 4; i++)
        {
            Quaternion quat;
            Vector3 pos;

            //Gets the current position of the physics WheelColliders.
            wheelCollider[i].GetWorldPose(out pos, out quat);

            ///Sets the mesh to match the position and rotation of the physics WheelColliders.
            wheelMesh[i].position = pos;
            wheelMesh[i].rotation = quat;
        }
    }

Back to Unity

18. Go to the Car and add the (______WheelObject)’s to the new Table in the code (Wheel Mesh)
-Note they must be in the same order as the Wheel Collider Table.
                -If you want you can try adding the WheelMesh’s to the table.

19. Press Play and Test,
                -You cannot move
                -Access all the WheelMesh’s and change the Capsule Collider Radius to 0.4
You could not move because the Capsule Collider was not allowing the Wheel Collider to touch the ground.

20. Add some ramps and small bumps and watch what happens.
                -You may notice your car will flip and over all act unrealistically.
                -This is because your center of mass is averaged by the ridged body between ALL colliders.

21. Create Empty Game Object (GameObject – Create Empty)
                -Name it CenterOfMass
                -Make it a Child of Car
                -Set its position to (0, -0.5, 0)

22. Open the Code SimpleCarController and add:

    //If you do not use center of mass the wheels base it off of the colliders
    //By using center of mass you can control where it is.
    public Transform t_CenterOfMass;
    //Ridged body accessor.
    private Rigidbody r_Ridgedbody;

    public void Start()
    {
        // This sets where the center of mass is, if you look r_Ridgedbody."centerOfMass" is a function of ridged body.
        r_Ridgedbody = GetComponent<Rigidbody>();
        r_Ridgedbody.centerOfMass = t_CenterOfMass.localPosition;
    }

Back to Unity

23. On the Car place the CenterOfMass Object in the new slot in the code.

Your car should now no longer flip as much and over all be more stable.


Key for code

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

public class SimpleCarController : MonoBehaviour
{
    //If you do not use center of mass the wheels base it off of the colliders
    //By using center of mass you can control where it is.
    public Transform t_CenterOfMass;

    //The maximum amount of power put out by each wheel.
    public float maxTorque = 500f;

    //The max distance a wheel can turn.
    public float maxSteerAngle = 45f;

    //Each wheel needs its own mesh
    public Transform[] wheelMesh = new Transform[4];

    //The physics of the wheels, max 20 axels.
    //WheelCollider[4] 4 is how many wheels we have.
    public WheelCollider[] wheelCollider = new WheelCollider[4];

    //Ridged body accessor.
    private Rigidbody r_Ridgedbody;

    public void Start()
    {
        // This sets where the center of mass is, if you look r_Ridgedbody."centerOfMass" is a function of ridged body.
        r_Ridgedbody = GetComponent<Rigidbody>();
        r_Ridgedbody.centerOfMass = t_CenterOfMass.localPosition;
    }

    public void Update()
    {
        //Sets the wheel meshs to match the rotation of the physics WheelCollider.
        UpdateMeshPosition();
    }

    public void FixedUpdate()
    {
        //Turn the wheels to a set max, with an input.
        float steer = Input.GetAxis("Horizontal") * maxSteerAngle;
        //Move forward or backwards based on the maxTorque, with an input.
        float torque = Input.GetAxis("Vertical") * maxTorque;

        //Sets which wheels turn, this is the two front wheels.
        wheelCollider[0].steerAngle = steer;
        wheelCollider[1].steerAngle = steer;

        //Sets which wheels move forward or backwards.
        for (int i = 0; i < 4; i++)
        {
            wheelCollider[i].motorTorque = torque;
        }
    }

    //Sets each wheel to move with the physics WheelColliders.
    public void UpdateMeshPosition()
    {
        for (int i = 0; i < 4; i++)
        {
            Quaternion quat;
            Vector3 pos;

            //Gets the current position of the physics WheelColliders.
            wheelCollider[i].GetWorldPose(out pos, out quat);

            ///Sets the mesh to match the position and rotation of the physics WheelColliders.
            wheelMesh[i].position = pos;
            wheelMesh[i].rotation = quat;
        }
    }
}