Lesson 6.2 - Research and Troubleshooting

Tutorial

·

Beginner

·

+10XP

·

30 mins

·

(1551)

Unity Technologies

Lesson 6.2 - Research and Troubleshooting

Overview:

In this lesson, you will attempt to add a speedometer and RPM display for your vehicle in Prototype 1. In doing so, you will learn the process of doing online research when trying to implement new features and troubleshoot bugs in your projects. As you will find out, adding a new feature is very rarely as simple as it initially seems - you inevitably run into unexpected complications and errors that usually require a little online research. In this lesson, you will learn how to do that so that you can do it with your own projects.

Project Outcome:

By the end of this lesson, the vehicle will behave with more realistic physics, and there will be a speedometer and Revolution per Minute (RPM) display.,

1. Make the vehicle use forces

If we’re going to implement a speedometer, the first thing we have to do is make the vehicle accelerate and decelerate more like a real car, which uses forces - as opposed to the Translate method.

  1. Open your Prototype 1 project and make a backup
  2. Replace the Translate call with an AddForce call on the vehicle’s Rigidbody, renaming the “speed” variable to “horsePower
  3. Increase the horsePower to be able to actually move the vehicle
  4. To make the vehicle move in the appropriate direction, change AddForce to AddRelativeForce

Reminder: The Global/Local dropdown menu in the Scene view can be a helpful tool to orient an object the way you want it in space.

Global perspective is the view of the scene from the perspective of the world, where the position, rotation, and scale of objects are relative to the world itself. This is the default perspective when you open a scene in the Scene view.

Local perspective is the view of the scene from the perspective of a particular object, where the position, rotation, and scale of objects are relative to that object. This can be useful for editing objects in a more precise way.

2. Prevent car from flipping over

Now that we’ve implemented real physics on the vehicles, it is very easy to overturn. We need to figure out a way to make our vehicle safer to drive.

  1. Add wheel colliders to the wheels of your vehicle and edit their radius and center position, then disable any other colliders on the wheels
  2. Create a new GameObject centerOfMass variable, then in Start(), assign the playerRb variable to the centerOfMass position
  3. Create a new Empty Child object for the vehicle called “Center Of Mass”, reposition it, and assign it to the Center Of Mass variable in the inspector
  4. Test different center of mass positions, speed, and turn speed values to get the car to steer as you like

3. Add a speedometer display

Now that we have our vehicle in a semi-drivable state, let’s display the speed on the User Interface.

  1. Add a new TextMeshPro - Text object for your “Speedometer Text”
  2. Import the TMPro library, then create and assign new create a new TextMeshProUGUI variable for your speedometerText
  3. Create a new float variables for your speed
  4. In Update(), calculate the speed in mph or kph then display those values on the UI

4. Add an RPM display

One other cool feature that a lot of car simulators have is a display of the RPM (Revolutions per Minute) - the tricky part is figuring out how to calculate it.

  1. Create a new “RPM Text” object, then create and assign a new rpmText variable for it
  2. In Update(), calculate the the RPMs using the Modulus/Remainder operator (%), then display that value on the UI

5. Prevent driving in mid-air

Now that we have a mostly functional vehicle, there’s one other big bug we should try to fix: the car can still accelerate/decelerate, turn, and increase in speed/rpm in mid-air!

  1. Declare a new List of WheelColliders named allWheels (or frontWheels/backWheels), then assign each of your wheels to that list in the inspector
  2. Declare a new int wheelsOnGround
  3. Write a bool IsOnGround() method that returns true if all wheels are on the ground and false if not
  4. Wrap the acceleration, turning, and speed/rpm functionality in if-statements that check if the car is on the ground

PlayerController

using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using UnityEngine;
using TMPro;

public class PlayerController : MonoBehaviour
{

    [SerializeField] float speed;
    [SerializeField] float rpm;
    [SerializeField] private float horsePower = 0;
    [SerializeField] float turnSpeed = 30.0f;
    private float horizontalInput;
    private float forwardInput;
    private Rigidbody playerRb;

    [SerializeField] GameObject centerOfMass;
    [SerializeField] TextMeshProUGUI speedometerText;
    [SerializeField] TextMeshProUGUI rpmText;

    [SerializeField] List<WheelCollider> allWheels;
    [SerializeField] int wheelsOnGround;

    private void Start()
    {
        playerRb = GetComponent<Rigidbody>();
        playerRb.centerOfMass = centerOfMass.transform.position;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        //Get Input from player
        horizontalInput = Input.GetAxis("Horizontal");
        forwardInput = Input.GetAxis("Vertical");

        if (IsOnGround())
        {

            //Move the vehicle forward
            //transform.Translate(Vector3.forward * Time.deltaTime * speed * forwardInput);
            playerRb.AddRelativeForce(Vector3.forward * forwardInput * horsePower);
            //Turning the vehicle
            transform.Rotate(Vector3.up * Time.deltaTime * turnSpeed * horizontalInput);

            //print speed
            speed = Mathf.RoundToInt(playerRb.velocity.magnitude * 2.237f);
            speedometerText.SetText("Speed: " + speed + " mph");

            //print RPM
            rpm = Mathf.Round((speed % 30) * 40);
            rpmText.SetText("RPM: " + rpm);
        }
    }

    bool IsOnGround()
    {
        wheelsOnGround = 0;
        foreach (WheelCollider wheel in allWheels)
        {
            if (wheel.isGrounded)
            {
                wheelsOnGround++;
            }
        }
        if (wheelsOnGround == 4)
        {
            return true;
        } else
        {
            return false;
        }
    }
}

6. Lesson Recap

New Concepts and Skills

  • Searching on Unity Answers, Forum, Scripting API
  • Troubleshooting to resolve bugs
  • AddRelativeForce, Center of Mass, RoundToInt
  • Modulus/Remainder (%) operator
  • Looping through lists
  • Custom methods with bool return

Complete this tutorial