-
Notifications
You must be signed in to change notification settings - Fork 710
Hello Cannon.js!
cannon.js/README.markdown contains a Hello World project. The script creates a static ground plane and a dynamic sphere. This code does not contain any graphics. All you will see is text output in the console of the box's position over time. This is a good example of how to get up and running with Cannon.js.
Every Cannon.js app begins with the creation of a CANNON.World object. CANNON.World is the physics hub that manages objects and simulation. It is easy to create a Cannon.js world. First, we create the CANNON.World object. Then we set the gravity to be 9.82 m/s² in the negative z direction:
var world = new CANNON.World();
world.gravity.set(0,0,-9.82);
We must then provide a Broadphase algorithm to the world so it can find colliding bodies. We use the default NaiveBroadphase:
world.broadphase = new CANNON.NaiveBroadphase();
So now we have our physics world, let's start adding some stuff to it.
Bodies are built using the following steps:
- Define a shape
- Define a rigid body using the shape and other physical properties needed
- Add the body to the world.
var mass = 5, radius = 1;
var sphereShape = new CANNON.Sphere(radius); // Step 1
var sphereBody = new CANNON.Body({mass: mass, shape: sphereShape}); // Step 2
sphereBody.position.set(0,0,0);
world.add(sphereBody); // Step 3
In step 1 we create a spherical shape with radius 1. This is just the mathematical description of a sphere, it must be put into a RigidBody before it can move and collide. In step 2 we create this RigidBody. Bodies become static if the mass is set to zero, but in this case we set mass to 5 kg, which makes the sphere dynamic. Static bodies don't collide with other static bodies, dynamic ones collide with all other bodies. For step 3 we add the body to the world. By adding it to the world it will move according to forces it is subject to, and collide with other objects.
First step is to create the plane shape, and then the body. We give the body zero mass, this will assure the ground body to become static. The orientation of the plane is by default in the z direction. In other words; its normal is (0,0,1). If we want to make it face in some other direction we have to change the orientation of the Body (see Body.quaternion). Last, we add the ground body to the scene.
var groundShape = new CANNON.Plane();
var groundBody = new CANNON.Body({ mass: 0, shape: groundShape });
world.add(groundBody);
That's it for initialization. We are now ready to begin simulating.
So we have initialized the static ground plane and a dynamic sphere. We just have a couple more issues to consider. Cannon.js uses a computational algorithm called an integrator. Integrators simulate the physics equations at discrete points of time. This goes along with the traditional game loop where we essentially have a flip book of movement on the screen. So we need to pick a time step for Cannon.js. Generally physics engines for games like a time step at least as fast as 60Hz or 1/60 seconds. You can get away with larger time steps, but you will have to be more careful about setting up the definitions for your world.
var timeStep = 1.0 / 60.0; // seconds
In addition to the integrator, Cannon.js also uses a constraint solver. The constraint solver solves all the constraints in the simulation. A single constraint can be solved perfectly. However, when we solve one constraint, we slightly disrupt other constraints. To get a good solution, we need to iterate over all constraints a number of times. In this phase the solver computes the impulses necessary for the bodies to move correctly. The suggested iteration count for Cannon.js is around 5. You can tune this number to your liking, just keep in mind that this has a trade-off between speed and accuracy. Using fewer iterations increases performance but accuracy suffers. Likewise, using more iterations decreases performance but improves the quality of your simulation. For this simple example, we don't need much iteration. Here are our chosen iteration counts. world.solver.iterations = 2; Note that the time step and the iteration count are completely unrelated. An iteration is not a sub-step. One solver iteration is a single pass over all the constraints within a time step. You can have multiple passes over the constraints within a single time step.
We are now ready to begin the simulation loop. In your game the simulation loop can be merged with your game loop. In each pass through your game loop you call world.step(timeStep)
. Just one call is usually enough, depending on your frame rate and your physics time step.
The Hello World program was designed to be simple, so it has no graphical output. The code prints out the position of the dynamic body.
Here is the simulation loop that simulates 60 time steps for a total of 1 second of simulated time.
for (var i = 0; i < 60; ++i){
world.step(timeStep);
console.log(sphereBody.position.x, sphereBody.position.y, sphereBody.position.z);
}
The output shows the box falling and landing on the ground box. Your output should look like this:
0 0 4
0 0 3.99
0 0 3.98
...
0 0 1.25
0 0 1.13
0 0 1.01
Once you have conquered the HelloWorld example, you should start looking at Cannon.js' demo framework. CANNON.Demo is a demo environment. Here are some of the features:
- Camera with pan and zoom
- Extensible number of scenes
- GUI for selecting scenes [number keys], parameter tuning, and debug drawing options
- Pause [p] and single step simulation [s]
The demo framework has many examples of Cannon.js usage and the framework itself. I encourage you to explore CANNON.Demo as you learn Cannon.js. Note: the testbed is written using Three.js. CANNON.Demo is not part of the Cannon.js library (build/cannon.js). The Cannon.js library is agnostic about rendering. As shown by the Hello world example, you don't need a renderer to use Cannon.js.