top of page

Mario Kart game demo using Unity

Updated: Mar 9, 2022

Game Preview





Source code download at:


The code is very easy to understand and self explanatory.


The kart object


The reflection probe is to give the car a nice metallic feel.

Particle systems: Boosting fires, drifting sparks on the tiers, etc.

The animator component is on StandartKart gameobject

Tires


The model’s pivot is not in the center of the model, so we added the model to the parent gameobject called FrontLeft, FrontLeft gameobject is at the center of the model. We will rotate the FrontLeft gameobject when the car is running.


Movement (Back and forth)

PlayerScripts.cs is the most important script in this project.

If you want to know what each function does, just comment out other functions first. Like the first function move();

FixedUpdate() {

move();

//tireSteer();

//steer();

//groundNormalRotation();

//drift();

//boosts();

}

In move function:

if (Input.GetKey(KeyCode.Space)) {

CurrentSpeed = Mathf.Lerp(CurrentSpeed, MaxSpeed, Time.deltaTime * 0.5f);

} else if (Input.GetKey(KeyCode.S)) {

CurrentSpeed = Mathf.Lerp(CurrentSpeed, -MaxSpeed / 1.75f, 1f * Time.deltaTime);

} else {

CurrentSpeed = Mathf.Lerp(CurrentSpeed, 0, Time.deltaTime * 1.5f);

}

Vector3 vel = transform.forward * CurrentSpeed;

vel.y = rb.velocity.y; //gravity

rb.velocity = vel;

CurrentSpeed = Mathf.Lerp(CurrentSpeed, MaxSpeed, Time.deltaTime * 0.5f);

In this line of code, 0.5f means that the kart will reach max speed in 1/0.5=2 seconds.

Don't forget to add vel.y=rb.velocity.y

Obviously we don’t want the gravity effect to get erased.

Car Body Steering

Rotate around the y axis.

In steer() function:

since handling is supposed to be stronger when car is moving slower, we adjust steerAmount depending on the real speed of the kart, and then rotate the kart on its y axis with steerAmount

steerAmount = RealSpeed > 30 ? RealSpeed / 4 * steerDirection : steerAmount = RealSpeed / 1.5f * steerDirection;


Tire steer and rotation


Note that only front tires can rotate left and right. Back tires won’t.

if (Input.GetKey(KeyCode.LeftArrow))

{

frontLeftTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 155, 0), 5 * Time.deltaTime);

frontRightTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 155, 0), 5 * Time.deltaTime);

}

else if (Input.GetKey(KeyCode.RightArrow))

{

frontLeftTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 205, 0), 5 * Time.deltaTime);

frontRightTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 205, 0), 5 * Time.deltaTime);

}

else

{

frontLeftTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 180, 0), 5 * Time.deltaTime); // when moving straight forward

frontRightTire.localEulerAngles = Vector3.Lerp(frontLeftTire.localEulerAngles, new Vector3(0, 180, 0), 5 * Time.deltaTime);

}

The default rotation of the Y axis is 180, when the car is moving straight forward.

Ground Normal Rotation



There is a little bug here we need to fix:

As you can see in the picture above, when on the slope, the body is not parallel to the ground. We need to rotate the car body to achieve the effect of the vehicle climbing a hill.

Just rotate the car to the rotation of the raycast’s hit point’s normal direction.

private void groundNormalRotation()

{

RaycastHit hit;

if (Physics.Raycast(transform.position, -transform.up, out hit, 0.75f))

{

transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.FromToRotation(transform.up * 2, hit.normal) * transform.rotation, 7.5f * Time.deltaTime);

touchingGround = true;

} else {

touchingGround = false;

}

}

Drifting

We need two flags: driftRight and driftLeft

if(steerDirection > 0)

{

driftRight = true;

driftLeft = false;

}

else if(steerDirection < 0)

{

driftRight = false;

driftLeft = true;

}

steerDirection is controlled by Horizontal input axis

steerDirection = Input.GetAxisRaw("Horizontal");

Accumulating drift time:

if (Input.GetKey(KeyCode.V) && touchingGround && CurrentSpeed > 40 && Input.GetAxis("Horizontal") != 0)

{

driftTime += Time.deltaTime;

Conditions of drifting: touching ground, speed>40, hold left or right key, hold V the drift key.


According to the drift time, set a different color for the particle system. The longer the drift, the stronger the color. This way we give users visual feedback.

Before drifting there will be a hop animation:



Boosts

The boost time is determined by the total of drift time

//give a boost

if (driftTime > 1.5 && driftTime < 4) {

BoostTime = 0.75f;

}

if (driftTime >= 4 && driftTime < 7)

{

BoostTime = 1.5f;

}

if (driftTime >= 7)

{

BoostTime = 2.5f;

}

When boosting, maxspeed will be set to boostspeed:

if(BoostTime > 0) {

for(int i = 0; i < boostFire.childCount; i++)

{ // boost fire particles

if (! boostFire.GetChild(i).GetComponent<ParticleSystem>().isPlaying) {

boostFire.GetChild(i).GetComponent<ParticleSystem>().Play();

}

}

MaxSpeed = boostSpeed;

CurrentSpeed = Mathf.Lerp(CurrentSpeed, MaxSpeed, 1 * Time.deltaTime);

} else {

for (int i = 0; i < boostFire.childCount; i++) {

boostFire.GetChild(i).GetComponent<ParticleSystem>().Stop();

}

MaxSpeed = boostSpeed - 20;

}

Camera Follow


The CameraFollow.cs script is attached on PlayerLookat gameobject


The Main Camera gameobject is the child of PlayerLookat object.

Note that the relative position is 0,0.95,-5.5 and the relative rotation on the X axis is 10 to make it look down a bit.

Also, in the game, when we get a boost, the camera moves slightly back. But it's not the actual PlayerLookat object that's moving back, it’s Main Camera gameobject that is moving back. The relevant code below:

In CameraFollow.cs:

if (playerScript.BoostTime > 0) {

transform.GetChild(0).localPosition = Vector3.Lerp(transform.GetChild(0).localPosition, boostCamPos, 3 * Time.deltaTime);

} else {

transform.GetChild(0).localPosition = Vector3.Lerp(transform.GetChild(0).localPosition, origCamPos, 3 * Time.deltaTime);

}

When the kart is turning or drifting,

PlayerLookat gameobject will gradually rotate to the direction the kart is rotating.

Because we want to see the side of the car, so we made the camera’s rotation value slowly interpolate approaching the kart’s steering rotation.


otherwise we can only see the back of the car the whole time like this:


How to achieve this in code:

In CameraFollow.cs

transform.rotation = Quaternion.Slerp(transform.rotation, player.rotation, 3 * Time.deltaTime);

The camera's rotation is approaching player’s rotation slowly.

Gliding

Preview:




How to trigger gliding:


The extra collider is above the panel, this extra collider is set to Trigger.

In PlayerScript.cs:

private void OnTriggerExit(Collider other)

{

if(other.gameObject.tag == "GliderPanel")

{

GLIDER_FLY = true;

gliderAnim.SetBool("GliderOpen", true);

gliderAnim.SetBool("GliderClose", false);

}

}

When exit the trigger, GLIDER_FLY will be true.

private void OnCollisionEnter(Collision collision)

{

if(collision.gameObject.tag == "Ground" || collision.gameObject.tag == "OffRoad")

{

GLIDER_FLY = false;

gliderAnim.SetBool("GliderOpen", false);

gliderAnim.SetBool("GliderClose", true);

}

}

When hit the ground or off road, we will end the gliding by set GLIDER_FLY = false;

We will use the GLIDER_FLY boolean flag to decide the gravity factor and speed:

In PlayerScript.cs move() function:

if (!GLIDER_FLY) {

Vector3 vel = transform.forward * CurrentSpeed;

vel.y = rb.velocity.y; //gravity

rb.velocity = vel;

} else {

Vector3 vel = transform.forward * CurrentSpeed;

vel.y = rb.velocity.y * 0.6f; //gravity with gliding

rb.velocity = vel;

}

Also, when gliding, the kart will rotate around the z axis instead of y axis that the kart rotates around when the kart is on the ground.

//glider movements

if (Input.GetKey(KeyCode.LeftArrow) && GLIDER_FLY) //left

{

transform.rotation = Quaternion.SlerpUnclamped(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, 40), 2 * Time.deltaTime);

} // left

else if (Input.GetKey(KeyCode.RightArrow) && GLIDER_FLY) //right

{

transform.rotation = Quaternion.SlerpUnclamped(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, -40), 2 * Time.deltaTime);

} //right

else //nothing

{

transform.rotation = Quaternion.SlerpUnclamped(transform.rotation, Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, 0), 2 * Time.deltaTime);

} //nothing

Animation of gliding:





TO BE CONTINUED:



74 views0 comments

Comments


bottom of page