Arcade Style Bouncy Vehicle Physics Tutorial

What is this tutorial?
In this tutorial we will look at how to set up arcade style vehicle physics on a 3D model. As with my previous tutorial, in an attempt to keep it as clear and concise as possible I will keep the game design quite simple, therefore this should be seen as a basis from which to build a game, rather than a tutorial for a complete and finished game.

Who is this tutorial aimed at?
This is aimed at people with a reasonable knowledge of C# and Unity as I won’t be explaining in depth basic C# programming concepts or basic Unity concepts, unless it is appropriate to do so within the scope of the tutorial.

Part 1 – The vehicle game object

 As this is a tutorial on coding rather than building game objects in the editor, I’m not going to give step by step instructions on how to put together the car and terrain, instead I’ll just give a brief description of the important bits and how they relate to the code, and I’ll provide all assets in a download link at the end of the tutorial.

First of all I should point out that the method we will be using isn’t a realistic physics simulation, instead it uses forces to ‘fake’ the physics, but the outcome is reasonable and gives a nice Mario Kart style feel to the vehicle handling.

The way we’ll achieve this is by firing a raycast down from each corner of  the vehicle a certain distance (hoverheight), and if it detects a hit, it adds an upward force. We also adjust the strength of the upward force depending on the distance from the vehicle that the raycast detects the hit. So effectively the closer the vehicle gets to the ground the stronger it is pushed back away from it, and vice versa.

The length of the ray we fire can be adjusted, and the longer it is the further the vehicle will float above the ground, we will be using a fairly short ray, because we want this to appear as if it is actually on the ground. However by increasing the hoverheight and hoverforce you can simulate a nice hover car type behaviour instead.

This is a very basic example of how we would set up the vehicle game object with the hover points. The red circles indicate where the hover points are positioned. Notice that they are placed vertically above the centre of the vehicle, this is because of the way we simulate gravity in our code, as I’ll explain a bit further on.

HoverCarBasic

We’ll also attach a rigidbody component, and for this example we’ll give it a mass of 70, drag 3 and angular drag 4. These figures work quite well as they are, but you can achieve different handling effects by tweaking them also.
Lastly we give it a box collider to detect collisions with other scene objects and also to prevent the vehicle from falling through the terrain when the downward velocity is very high and we’ll put it on its own layer (vehicle), so we can ignore it in the raycasts.
We’ll also untick Use Gravity, as we will be handling gravity ourselves.

So that’s pretty much all that’s needed for a basic vehicle setup (in the finished project I have added a buggy model which looks a bit nicer than a plain cube).

Part 2 – The code

So now let’s take a look at the code that will turn this into something a bit more interesting. First off we’ll add the various properties that we’ll use to control the behaviour of the buggy as so.


Most of this should be pretty self explanatory, but I’ll explain what some of them do.

The deadZone value is just a way to make the controller not so sensitive to small movements. Basically any input below the deadZone threshold is ignored.

The groundedDrag value is used to change the buggy RigidBody drag factor depending on whether the buggy is grounded or in the air.

The dustTrails array will hold references to the particle systems that play when the wheels are grounded.

The layerMask property is used to prevent the hover point raycasts from registering hits on the buggy.

Next we have the Start function, which stores a reference to the buggy Rigidbody and stores a reference to the inverse of its LayerMask, for use in the Raycast later.
It also sets the Rigidbody.centerOfMass to be one unit below the buggy, this helps to keep it a bit more stable when it’s in the air.

In the Update function we read the current input and assign a value to the acceleration and rotation from it.

Most of the work is done in FixedUpdate, so let’s take a look at this one bit at a time:-

This block of code above handles the hover/bounce behaviour.
To start with it clears the grounded flag.
Then, for each of the hover points, it fires a raycast of hoverHeight length downwards, and if it detects a hit it applies a force in the opposite direction and scales it depending on the distance the hover point is away from the hit point. So the closer the hover point is to the point which the ray cast hits, the greater the force that is applied to push it back. Kind of like what happens when you compress a spring.
Grounded is also set to true if any of the raycasts detect a hit.

If, however the hover point raycast doesn’t detect a hit, then that means this wheel/corner of the vehicle is off the ground, so we need to handle this differently as follows.

It compares the y position of each hover point with the y position of the vehicle, and pushes it up if it’s below it, or down if it’s above it. This serves two purposes, firstly it makes the vehicle automatically level out when it’s in the air, and secondly it applies a fake gravity effect. This is why the hover points need to be positioned above the centre of the vehicle transform, so that when the vehicle is in the air it will be pushed back down by the gravityForce amount. If we positioned the hover points below the y position of the vehicle transform, once it left the ground it would fly up into the air and never come down.

The next section of code handles other behaviour differences between when the vehicle is grounded and when it is airborne.

So basically, if the vehicle is on the ground, we set the Rigidbody.drag value to the amount we set in the inspector, and we give the dust trail particles a suitable emission rate.
But if the vehicle is in the air we set the Rigidbody.drag to a very low value, and we also drastically reduce the thrust and turn values, as we don’t want to have full control whilst we aren’t on the ground.
Lastly for this section, we iterate through the dustTrails array and set the particle emissionRate to the appropriate value (10 if grounded, zero if in the air).

Last of all we apply the thrust and turn forces to the vehicle and then limit it’s velocity to the maxVelocity value we set in the inspector.

So that’s the entire vehicle controller script, it produces quite a nice arcade style drive and with a bit more work could form the basis of a fun driving game, you can test out the complete project which can be downloaded from here. Once you have loaded it into Unity you will need to open Assets\Scene 1.

The behaviour of the vehicle can be modified to make it feel like it’s driving on different surfaces by changing the various properties exposed in the inspector, for example to make it feel like it’s on ice change the following properties:-

  • Grounded Drag = 0.5
  • Max Velocity = 30
  • Forward Acceleration = 1500
  • Reverse Acceleration = 750
  • Turn Strength = 500

It uses the standard WASD and Arrow keys to control acceleration, braking and turning.

Thanks to Carbon Concept for the free buggy model

I hope you enjoyed this tutorial, and please feel free to post any comments or suggestions.

Download project files

Progress update

Currently working on a new one part tutorial, Bouncy Arcade Style Vehicle Physics. It will demonstrate a basic method to create a Mario Kart style of vehicle.

Hoping to have it published by the weekend.

In the meantime here’s a video I made which shows what the end result of the tutorial will be.

Picture Slider – released on Play Store

We released our latest game yesterday.

Picture Slider – tile sliding puzzle game

Unity Web player version available here

How quickly can you unscramble the pictures by sliding horizontal and vertical rows of tiles?

★ 60+ Pictures to choose from – unlock pictures as you play
★ 5 Levels of difficulty
4 Tiles – Very Easy
9 Tiles – Easy
16 Tiles – Challenging
25 Tiles – Extremely Challenging
36 Tiles – For experts only
★ Records progress for each picture on each difficulty
★ Simple swipe to move controls

On 16 tile puzzles and above this is a very difficult puzzle to solve, and will definitely suit those puzzlers that seek a challenge. Can you solve a 36 tile puzzle?

All pictures Designed by Freepik.com

Upcoming features:-
More pictures
Friends leaderboard

Gameplay video on YouTube

Unity 5 Network Tutorial Part 7 – Improved respawning and health pickups

Welcome to part 7 of my Unity 5 basic network game tutorial, in this, the final part, we will improve the respawn process and implement health pickups.

Part 7a – Improved respawn

In the last part of the tutorial, we implemented respawn behaviour when a player’s health reaches zero, however as it stands there is no delay between the player dying and being respawned, which dosn’t feel quite right. Also there is a subtle bug, whereby if the player dies close to his respawn point, you will see him ‘lerp’ to the respawn point on remote clients.
So we’ll go ahead and fix both of those issues now.

First of all, open the NetworkPlayer script in your editor and make the playerCam variable public.

public Camera playerCam

The reason for making the playerCam variable public is because we want to temporarily detach the camera from a player object when he dies. This enables us to reposition the player without the camera immediately following him. (This is a bit of a workaround to avoid the lerping issue mentioned earlier.

This is the only change we need to make to the NetworkPlayer script, so go ahead and save it, and then open the HealthAndDamage script in your editor, as we also need to make some changes there.

We’ll handle detaching and re-attaching the camera in the HealthAndDamage script, so we’ll store a reference to it in a variable in the HealthAndDamage script.
Add this line below the respawnPos variable:-

Camera playerCam;

And add this line to the OnStartLocalPlayer() function:-

playerCam = GetComponent<NetworkPlayer>().playerCam;

That’s the reference to the player’s camera sorted, so next we’ll add three new functions that will perform the improved respawn.

Add the following code just below the GetRandomSpawnPoint() function:-

So looking at these new fuctions, we have setVisibleState(bool state), what this does is turn on or off the player object renderer and name label, effectively making it invisible or visible depending on the state argument.

Then we have a coroutine, HandlePlayerDeath() which calls setVisibleState with a value of false, which makes all instances of the player object invisible.
Next, only if it’s running on the local player, it detaches the camera, preserving the camera’s current position, and then it repositions the player in the respawn position. As the camera is now not parented to the player, the game view stays in the position it was when the player died, and then it waits for two seconds. This is good for two reasons, first it gives a nice pause between dying and respawning and secondly it allows the clients to lerp to the new spawn position whilst they are invisible, so you don’t see it happen.
Finally it calls the Respawn() function.

The Respawn() function checks to see if it’s running on the local player, and if it is, it re-parents the camera to the player object and sets it’s local position to the correct value.
Then it tells the server to reset the player’s health to 100. Finally it makes the player visible again on all PCs on the network (which is why the last command needs to be outside of the isLocalPlayer check).

The final change we need to make is to the RpcHandlePlayerDeath() function, to make it call the HandlePlayerDeath() coroutine instead of handling the respawning itself. So replace the existing RpcHandlePlayerDeath() function with this new one:-

So that’s the new and improved respawn procedure finished, this is the new HealthAndDamage script with all the above changes implemented:-

Save this and then build and run the game, you will see that after a player dies he disappears for two seconds before reappearing at one of the spawn points with full health.


Part 7B – Health Pickup

Now let’s add a health pack that you can walk over to replenish your health. We’ll implement these as scene objects, so we can just place them in the editor and not have to worry about runtime instantiation and health spawn points etc. etc.

So the first thing we need to do is create a health pack game object. Open the online scene and add a 3d Cube game object (GameObject->3D Object->Cube) and rename it HealthPack.
Now make the following changes to the HealthPack game object:-

  • Set its transform.position to  -8,0.25,-5
  • Set its scale to 0.5,0.5,0.5.
  • Add a NetworkIdentity component to the HealthPack (with the HealthPack game object selected use the menu option (Component->Network->NetworkIdentity)).
  • Set its Box Collider Is Trigger property to ticked

Next we’ll give it some colour; Open the Assets/Materials folder, create a new material in there and rename it HealthPack, then set the albedo Colour to a nice bright green.
Then drag this new material onto the HealthPack game object in the hierarchy and you should see the cube take on the colour of your new material.

Your scene setup should look like this after you have done all the above.

Now let’s add a script to the HealthPack game object to implement the functionality. Create a new folder in Assets and rename it HealthPack, and in that folder create a new c# script and rename it HealthPack. Then open the Healthpack script in your editor and replace the default code with the following:-

This is a fairly straightforward script with only five functions, also notice that it derives from NetworkBehaviour instead of MonoBehaviour. Now let’s take a look at each part in turn and I’ll explain what each one does.

Firstly we declare a variable, bool visible, and make it a SycVar with a hook function. The hook function OnVisibleChanged just activates or deactivates the attached Renderer and Collider based on the newValue argument. This has the effect of hiding or showing the health pack in the scene. Anytime the value of visible is changed this hook function will run and update the state of the HealthPack in the scene.

Next we have OnStartServer(), this will only ever run on a dedicated server when it starts, or the host when it starts. Therefore we can use this function to set the initial state of the HealthPack, and as we want all health packs to start enabled we set visible to true.

Next comes OnStartClient(), this runs on all clients when they join the game, and at this point all SyncVars are guaranteed to have the correct synchronized value, so we manually call the visible hook function, passing the current value of visible, so we can update the state of the health pack in our scene. This ensures that if a health pack is hidden on the server at the time we join the game, our local copy also gets hidden.

Then we have the HandlePickup() coroutine.

All this does is set visible to false, which makes the hook function run, which hides the health pack.
Then it waits 15 seconds and then sets visible to true, which makes the health pack visible and available for use again.
We can make direct changes to the visible variable as this script is running on the server.

Lastly comes OnTriggerEnter(Collider other)

By default, this function runs on all clients whenever a trigger collision is detected, however we only want to handle collisions with the HealthPack on the server. We could ensure this in a couple of ways, either by checking if isServer is true, or (and this is how we do it) with the use of attribute tags.
The use of the [Server] tag, would mean that the function will only run on the server, however as we can’t control when this function is invoked, we can’t prevent clients from calling this function, and although the function won’t run on the client, we would get a console littered with debug warnings. Therefore instead of using the [Server] attribute, we’ll use the [ServerCallback] attribute, which still makes it only run on the server, but also supresses the warning messages if the function is called from the client.

So having ensured this will only run on server, what does it do. Firstly it starts the HandlePickup coroutine as described above, to hide the health pack.
The ‘other’ argument, will contain a reference to the player game object that collided with the HealthPack, so we use GetComponent to access its HealthAndDamage script and add 10 points to its publicly exposed health variable.
There again we can do this directly as this script is running on the server.
This is where the power of SyncVars shows, because this updated health value is now automatically sent to all clients and because we had previously set up a hook function for the health variable, it in turn updates the health display on the HUD. So just by changing the value of the health variable everything automatically synchronizes and updates, very neat!

Save the HealthPack script and add it to the HealthPack game object by dragging it onto the HealthPack in the hierarchy window.

Then save the Online scene, and the open the Offline scene. You can now build and run the game and test the HealthPack.

So now we have a working health pack, which when a player walks over it will add some health and disappear, before respawning again 15 seconds later. You can duplicate the health pack game object as many times as you like and position them around your game scene.

There are a couple of obvious things about the health pack that could be improved, such as preventing it from increasing health above 100, and also stopping the player from flashing yellow when he picks up a health pack when he is below 100 health. But I’ll leave those as an exercise for you to figure out.

So that’s it for this tutorial series, I hope it’s proved understandable and useful and I’ll do my best to answer any questions that might arise.

You can download the complete Unity project files here:-
Unity Networking Tutorial