Advertisement
  1. Game Development
  2. 3D
Gamedevelopment

Creating a Simple 3D Physics Game Using Three.js and Physijs

by
Difficulty:IntermediateLength:MediumLanguages:
Final product image
What You'll Be Creating

In this tutorial, you'll learn how to use Physi.js to add game physics to a 3D scene created using Three.js. We'll create a simple game in which we drive a cart around collecting items, using basic physics shapes and physics constraints.

This tutorial will be building on top of the concepts shared in my previous Three.js tutorial. I would request you to read it if you are new to Three.js and to its 3D scene creation. 

Due to a technical limitation in hosting web worker based solutions on JSFiddle, we are unable to embed the interactive game in this tutorial page. Please use the provided source code to check out the working example on any cloud-based IDEs or by self-hosting.

1. 3D Physics on the Web

There are multiple frameworks and engines currently available which can be used to create 3D content for the web with physics. Some of those worth mentioning are Turbulenz, BabylonJS, PlayCanvas, and the obvious Unity WebGL build. But when it comes to popularity and ease of use, most people like to use Three.js for their experiments. As Three.js is a rendering engine and does not have integrated physics, we need to explore additional frameworks to add the physics capability.

A very popular JavaScript physics solution is Ammo.js, which is a direct port of Bullet physics. While directly using Ammo.js is possible, it is not very beginner friendly and has a lot of boilerplate code for each aspect. Also, as it is not manually written but ported using Emscripten, the code is not easy to understand. 

An alternative solution is to use Cannon.js or Physijs. The interesting thing with Physijs is that the focus is always on making things easier, which makes it the ideal choice for beginners. It is built based on Ammo.js and even has a Cannon.js branch. This tutorial uses Physijs and Three.js to build a working game prototype with physics capabilities. 

Yet another option, although oversimplified, would be to use the Whitestorm framework, which is a component-based framework based on Three.js and Physijs. 

2. Setting Up Physijs

We need to have the ammo.js, physi.js, physijs_worker.js and three.js files within our folder structure or coding environment to use Physijs. Physijs uses a web worker to use different threads for physics calculations. So the first step in the integration process is to set up the web worker as below.

At this point, the setup is complete, and we can start using the physics framework. Physijs has made sure that it followed the coding style of Three.js, and most of the concepts are simple replacements of the corresponding Three.js concept.

Basic Steps

Instead of THREE.Scene, we need to use Physijs.Scene.

There are multiple meshes available in Physijs which need to be used in place of THREE.Mesh. The available options are PlaneMesh, BoxMesh, SphereMesh, CylinderMesh, ConeMesh, CapsuleMesh, ConvexMesh, ConcaveMesh, and HeighfieldMesh.

We need to call the scene.simulate method to do the physics calculations either in the render method or within frequent intervals. Let me remind you that the physics calculations happen in a different thread and will not be in sync or as fast as the scene render loop. 

Even the next call to scene.simulate may happen while the previous calculations are still running. In order to make it properly in sync with the physics calculations, we could use the Physijs scene's update event.

In order to register a collision on a Physijs mesh object named arbitrarily as cube, we can listen to the collision event.

Within the above method, this will refer to cube, while objCollidedWith is the object cube has collided with.

3. Example Game Prototype

For this tutorial, we will be creating a very simple physics-based game where we will use physics constraints to create a vehicle. The player can use arrow keys to drive the vehicle and collect a bouncing ball which randomly appears in the play area. 

Interestingly, Physijs already has a special vehicle feature which can be directly used for creating vehicles, but we won't be using it.

The Game World

Our game world is a vast ground with walls on its four sides as below.

ground with walls

We use Physijs.BoxMesh for the ground and the four walls as shown in the code below.

Notice the usage of Physijs.createMaterial to create the necessary physics materials by passing a friction value and a restitution value. The friction value determines the grip on the ground, and the restitution value determines the bounciness. One important thing to note is that when we provide a mass value of 0, we create a stationary mesh object.

The Vehicle

We are going to create a special vehicle which has two connected parts. The front part, which has three wheels, acts as the engine, and the rear part, having two wheels, will act as a carriage. The carriage part is connected to the engine part using a hinge joint implemented using a Physijs.HingeContraint

The wheels use Physijs.DOFConstraint, which is a degree of freedom constraint to be attached to the vehicle's body while retaining the ability to rotate independently. I would invite you to read the official documentation on the various constraints available in Physijs.

The engine body and carriage body are simple BoxMesh objects like the ground shown above, but with a definite mass value. They are connected to each other using a hinge joint, as shown in the following code. A hinge joint restricts the motion of the connected object like that of a normal door.

The second part of the code applies limits to the rotation of the hinge, which in this case is between -Math.PI/3 and Math.PI/3

The wheels use a degree of freedom constraint which can be used to set limits on both linear motion and angular motion in all three axes. A method addWheel is created for adding wheels, which takes in multiple parameters. 

The parameters are the position of the wheel, the weight of the wheel, whether the wheel is big or small, and the wheel reference object. The method returns a newly created DOFConstraint, which is used for driving the vehicle.

The big wheels need to be attached to the carriage, and the small wheels are attached to the engine. The wheels are given a damping value so that their angular velocity gets reduced when no external force is being applied. This makes sure that the vehicle slows down when we release the accelerator. 

We will explore the driving logic in a later section. Each wheel mesh along with the car meshes are assigned the name of cart for identification purposes during the collision call back. Each wheel constraint has different angular limits, which are set independently once they are created. For example, here is the code for the front middle wheel of the engine, car.wheel_fm, and the corresponding constraint, car.wheel_fm_constraint.

The Ball

The ball is a Physijs.SphereMesh object with a lower mass value of 20. We use the releaseBall method to position the ball randomly within our game area whenever it gets collected. 

One thing worth noticing is the fact that we need to override the position values set by the physics simulation in order to reposition our ball. For this, we use the __dirtyPosition flag, which makes sure that the new position is used for further physics simulation.

The ball gets collected when it collides with any part of the vehicle which happens in the onCollision listener method.

Driving the Vehicle

We add event listeners for the onkeydown and onkeyup events of the document, where we determine the keyCode to set the values of the corresponding wheel constraints. The theory is that the single front wheel of the engine controls the turning of our vehicle, and the two wheels on the rear of the engine control the acceleration and deceleration. The wheels on the carriage do not play any part in the driving.

The DOFConstraint uses the enableAngularMotor method to apply angular velocity on the wheel which turns the wheel based on the axis value provided as a parameter. Basically, we only turn the wheels, and the motion of the vehicle happens due to the frictional response of the ground, as in the real world.

the completed game

We are unable to embed the working game in this page as mentioned at the start of the tutorial. Please go through the complete source to understand how everything is wired together.

Conclusion

This is a very simple introduction to implementing physics in your Three.js 3D world. The Physijs documentation is sorely lacking, but there are many examples already available which are worth looking into. Physijs is a very beginner-friendly framework, like Three.js, when you consider the complexity that is present under the hood. 

JavaScript is clearly popular for game development as well as web development. It’s not without its learning curves, and there are plenty of frameworks and libraries to keep you busy, as well. If you’re looking for additional resources to study or to use in your work, check out what we have available in the Envato marketplace.

Hope this tutorial helps you get started in exploring the interesting world of 3D web game physics.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.