|
|
In this section, I will explain how I coded mechanics within the game, why they are designed like this, and how they act within the game.
|
|
|
|
|
|
# Car Driving #
|
|
|
|
|
|
For creating the driving of the car, I tried different ways of coding a drivable car.
|
|
|
|
|
|
The models used were made by Kenney. More information can be found within [Assets](Assets).
|
|
|
|
|
|
To make the car work, I used the FixedUpdate() loop within the code for altering physics. This is better for altering physics within code as it is called before each physics update within engine, rather than Update() which is called before each frame. Due to framerate being potentially inconsistent, this would mean that the physics would not be calculated correctly.
|
|
|
|
|
|
## Initial Design ##
|
|
|
|
|
|
I initially tried to make the car drivable and be able to interact with the environment by adding wheel colliders to the car model wheels. I used a guide from Unity called [Create a car with Wheel Colliders](https://docs.unity3d.com/Manual/WheelColliderTutorial.html) to assist me.
|
|
|
|
|
|
To make this car I first had to put a box collider around the actual car. Then I had to place wheel colliders within the wheels of the car. These wheel colliders were placed in the centre of the wheel, making sure that they were of the correct radius to encompass the whole wheel.
|
|
|
|
|
|
Wheel colliders come with preset options that can be used to help determine the behaviour of the car you desire.
|
|
|
|
|
|
I would create SerializedFields for all the WheelColliders on the car, and bring them into the script. Then I would apply forces to each WheelCollider. These forces would be calculated from the Input of W and S, which are under the Vertical Axis. This gives a number between 1 and -1 which acts as a constant in telling what direction the acceleration should apply to; 1 to accelerate, -1 to reverse. I would then multiply this value by an acceleration constant to get the current acceleration that would be applied to the frontLeft and frontRight wheels motorTorque. MotorTorque essentially adds a force to the car for WheelColliders.
|
|
|
|
|
|
Braking would also be applied depending on whether the LeftControl button was held down. If it was, a braking constant would be applied to all 4 wheel colliders' brakeTorque. BrakeTorque will slow down the car.
|
|
|
|
|
|
I would also then update the actual wheels on the model to match the position of the WheelColliders.
|
|
|
|
|
|
### Problems ###
|
|
|
|
|
|
While this created a working car, it also came with many problems. The car itself would initially fall over if turned too much, meaning I had to recenter the centre of mass on the car Rigidbody. This stopped this from happening.
|
|
|
|
|
|
The major problem with this iteration came from the WheelColliders being difficult to find the correct values for what I wanted. I was aiming to have a somewhat arcade-like car feel, with realism not being too much of a factor. Unfortunately, the WheelColliders tended to be more focused on providing realistic car movement which was not what I wanted. There are of course settings on each WheelCollider which you can change for different behaviour. Unfortunately, I was unable to get these settings to have the behaviour I wanted. This is likely due to my limited knowledge of car physics, as well as the large amount of tinkering necessary for WheelColliders to get the required behaviour.
|
|
|
|
|
|
Due to these problems, I decided to scrap this iteration, and restart from scratch to create a more arcade-like feeling car.
|
|
|
|
|
|
## Final Design ##
|
|
|
|
|
|
This design is based on a YouTube video called [Arcade Car Driving in Unity](https://youtu.be/cqATTzJmFDY?si=T7pNfVaMv7I8jmgh) by the YouTube channel [gamesplusjames](https://www.youtube.com/@gamesplusjames). My code is heavily modified from his, but I did take inspiration and some code from his video to build this design.
|
|
|
|
|
|
The design itself uses a Sphere to simulate all movement instead of actual wheels, thus making it feel more arcade-like and saving myself from tinkering with variables on the WheelColliders to try and get the same feel.
|
|
|
|
|
|
The Sphere starts off as a child to the Car when editing. As soon as the game is played, the Sphere is changed to have no parent. This is done because the Car model has to follow the location of the Sphere as that will be what all the movement forces will apply to. If the Sphere was still the child it would result in the Car moving to where the Sphere would be, but because the Sphere was still the child the Sphere would move with it, resulting in the car constantly moving to where the Sphere would be and the Sphere moving with it.
|
|
|
|
|
|
### Acceleration and Reversing ###
|
|
|
|
|
|
Within the Update() loop, the code determines whether the Game is in play. If it is then PlayerInput() can be run. The PlayerInput() function simply calculates values based on the players inputs and assigns them to the scripts global variables for use within the FixedUpdate() loop, as well as updating the position of the model.
|
|
|
|
|
|
Acceleration is calculated by first getting the Input from the Vertical Axis (i.e. W and S or Up and Down), and then using that to determine whether the acceleration to be applied should be forward or reverse. If the input is greater than 0 then it will be multiplied by the constant forwardAcceleration and 1000 (or 500 depending on if drifting is active) to get the force to be applied to the Sphere. Else, if the input is less than 0 the same calculation will be done but with the backwardAcceleration constant in place of the forwardAcceleration. This calculation is then stored in the speed variable.
|
|
|
|
|
|
This speed variable is then used within the FixedUpdate() loop. First, the loop initialises 4 variables to false; onGround, onWater, onRoad, and inAir. These are all used to determine what the car is currently doing within the game, whether that be driving on a specific layer, or in the air. A Raycast is then used to determine what layer is hit on the ground. A rayPoint variable is used within the scene to determine where the Raycast will come out from. It was placed directly under the car. -transform.up is then used to emit the Raycast downwards towards the ground. A RaycastHit is used to get information back on the object it hits, and is matched against a LayerMask called whatIs____ to decide whether it hit an obstacle of that layer. The rayLength has a size of 0.5f.
|
|
|
|
|
|
Depending on what the Raycast hits, different effects apply. If it hits anything, it will always change the rotation of the car model to be aligned to the normals of the object that has been hit. So if a car was going up a slope, it would rotate to be level with the face of the slope. It will also change the variable of whichever on___ to true. If the layer the ray hit was a Ground layer, onGround would be changed to true.
|
|
|
|
|
|
These on____ booleans are then used to determine what forces to apply to the sphere. If onRoad or onGround is true, then it will use the CreateForce function and pass in the specific drag that should apply to the Sphere depending on the layer. Drag is how much resistance there is to the acceleration of the sphere. It is applied directly to the Sphere Rigidbody and will slow down the car quicker the higher the value is. The onRoad drag is equal to 3, while the onGround drag is equal to 7. This makes the car be quicker on the road than it is on the ground, penalising players for going on to the ground (i.e. the grass).
|
|
|
|
|
|
If onWater is true then the EndGame state will be called within the GameController and the player will lose. If none of these are true, then the car must be in the air. This will set inAir to true, and change the Sphere's drag to 0.1f and apply gravity to the Sphere to push it back down to the ground.
|
|
|
|
|
|
The CreateForce function is used which if the Absolute value of the speed variable is greater than 0, then it will apply the AddForce function to the Sphere, which multiplies transform.forward and the speed variable to create the force.
|
|
|
|
|
|
### Turning ###
|
|
|
|
|
|
Turning is done within the PlayerInput(). It gets the Input from the Horizontal Axis, i.e. a number between -1 and 1 depending on which key is pressed (A and D or Left and Right). This is stored in the turn variable. An if statement is then used to determine that if the car is on the ground or on the road and the cars speed is greater than the speed that the car is no longer allowed to turn after, then the car can be turned. The reason for the check for the turnAfterSpeed is that if a car is stationary it shouldn't be able to turn, so this prevents that. The car is checked to be on the ground or on the road so that it can't turn while in the air.
|
|
|
|
|
|
The transform.rotation is turned using a Quaternion that rotates the car on the Y axis using the turn variable, as well as the turn strength variable and Time.deltaTime.
|
|
|
|
|
|
### Drifting ###
|
|
|
|
|
|
If the player presses either LeftShift or Space then drifting will become active. This mechanic allows the player to turn quicker at the expense of speed. This helps players get round tight turns and corners without crashing.
|
|
|
|
|
|
Drifting simply changes the value used within the code to multiply the speed, as well as changing the turnStrength to a new variable called driftStrength. These allow the car to turn quicker, but be slower.
|
|
|
|
|
|
Drifting also activates a trail renderer, which emits a trail to simulate the wheels marking the road because they are no longer spinning. This is a visual indicator that the car is drifting so the player can tell. It is only emitted when on the ground and drifting.
|
|
|
|
|
|
### Car Feel ###
|
|
|
|
|
|
I believe that this iteration of the car fits the design I was intending much better. It controls much more arcade-like, with much less friction being applied on the car. This means that it is able to be less realistic.
|
|
|
|
|
|
Acceleration is quick which I think helps players and allows them to recover from crashes, making mistakes not necessarily be fatal.
|
|
|
|
|
|
Drifting is an important part of the game, particularly in the later rounds. It allows a player to avoid crashing when turning, which means if a player is able to master the drifting then it will be much easier for them to navigate the track.
|
|
|
|
|
|
|
|
|
|
|
|
|