[TUTORIAL] Box2Djs, a JavaScript Physics Engine Using HTML5


box2djs

Implementing physical phenomena in applications can make them highly interactive and create a very realistic experiences for any user, making their interaction more pleasant and intuitive. With the rise of HTML5 and its many possibilities, developing rich interactive and fancy features has become even easier with the many tools available such as the canvas element and the Box2D library. Box2Djs is a JavaScript port of the AS3 version of the famous 2D physics engine library : Box2D. This tool, originally developed for C/C++ applications, allows you to create a virtual two-dimensional world in which the laws of physics apply, especially the most famous – gravity. You can add bodies with specific shapes and make them bounce against each other. You can also set their physical proprieties, like their mass, their velocity, their density. This library provides a large amount of easy to useĀ  functions and objects and you can make excellent features by employing just a few of them.

The idea is to create the bodies contained in the virtual 2D world, set their properties and just let the callback function do the magic: the forces, the new positions, the bounces will be computed automatically. Here is a short tutorial showing how to create a minimal application:

The script will be divided into three main functions:
1/ Initialization: Here we will create the “world” that will contain the bodies we want.
2/ Update: Just by a simple function call, we will be able to compute all the forces to be applied in our world and get the bodies new positions for the next step. Then, by using the HTML5 canvas element we will display the 2D world and its bodies.
3/ Input handling: In this part, we will get all the user input like mouse clicks and/or keyboard events.

Click on the canvas below to see a demo:

You need to download Box2Djs here and include the files in your page as follows:

<script src="js/prototype-1.6.0.2.js"></script>
<script src='js/box2d/common/b2Settings.js'></script>
<script src='js/box2d/common/math/b2Vec2.js'></script>
<script src='js/box2d/common/math/b2Mat22.js'></script>
<script src='js/box2d/common/math/b2Math.js'></script>
<script src='js/box2d/collision/b2AABB.js'></script>
<script src='js/box2d/collision/b2Bound.js'></script>
<script src='js/box2d/collision/b2BoundValues.js'></script>
<script src='js/box2d/collision/b2Pair.js'></script>
<script src='js/box2d/collision/b2PairCallback.js'></script>
<script src='js/box2d/collision/b2BufferedPair.js'></script>
<script src='js/box2d/collision/b2PairManager.js'></script>
<script src='js/box2d/collision/b2BroadPhase.js'></script>
<script src='js/box2d/collision/b2Collision.js'></script>
<script src='js/box2d/collision/Features.js'></script>
<script src='js/box2d/collision/b2ContactID.js'></script>
<script src='js/box2d/collision/b2ContactPoint.js'></script>
<script src='js/box2d/collision/b2Distance.js'></script>
<script src='js/box2d/collision/b2Manifold.js'></script>
<script src='js/box2d/collision/b2OBB.js'></script>
<script src='js/box2d/collision/b2Proxy.js'></script>
<script src='js/box2d/collision/ClipVertex.js'></script>
<script src='js/box2d/collision/shapes/b2Shape.js'></script>
<script src='js/box2d/collision/shapes/b2ShapeDef.js'></script>
<script src='js/box2d/collision/shapes/b2BoxDef.js'></script>
<script src='js/box2d/collision/shapes/b2CircleDef.js'></script>
<script src='js/box2d/collision/shapes/b2CircleShape.js'></script>
<script src='js/box2d/collision/shapes/b2MassData.js'></script>
<script src='js/box2d/collision/shapes/b2PolyDef.js'></script>
<script src='js/box2d/collision/shapes/b2PolyShape.js'></script>
<script src='js/box2d/dynamics/b2Body.js'></script>
<script src='js/box2d/dynamics/b2BodyDef.js'></script>
<script src='js/box2d/dynamics/b2CollisionFilter.js'></script>
<script src='js/box2d/dynamics/b2Island.js'></script>
<script src='js/box2d/dynamics/b2TimeStep.js'></script>
<script src='js/box2d/dynamics/contacts/b2ContactNode.js'></script>
<script src='js/box2d/dynamics/contacts/b2Contact.js'></script>
<script src='js/box2d/dynamics/contacts/b2ContactConstraint.js'></script>
<script src='js/box2d/dynamics/contacts/b2ContactConstraintPoint.js'></script>
<script src='js/box2d/dynamics/contacts/b2ContactRegister.js'></script>
<script src='js/box2d/dynamics/contacts/b2ContactSolver.js'></script>
<script src='js/box2d/dynamics/contacts/b2CircleContact.js'></script>
<script src='js/box2d/dynamics/contacts/b2Conservative.js'></script>
<script src='js/box2d/dynamics/contacts/b2NullContact.js'></script>
<script src='js/box2d/dynamics/contacts/b2PolyAndCircleContact.js'></script>
<script src='js/box2d/dynamics/contacts/b2PolyContact.js'></script>
<script src='js/box2d/dynamics/b2ContactManager.js'></script>
<script src='js/box2d/dynamics/b2World.js'></script>
<script src='js/box2d/dynamics/b2WorldListener.js'></script>
<script src='js/box2d/dynamics/joints/b2JointNode.js'></script>
<script src='js/box2d/dynamics/joints/b2Joint.js'></script>
<script src='js/box2d/dynamics/joints/b2JointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2DistanceJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2DistanceJointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2Jacobian.js'></script>
<script src='js/box2d/dynamics/joints/b2GearJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2GearJointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2MouseJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2MouseJointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2PrismaticJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2PrismaticJointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2PulleyJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2PulleyJointDef.js'></script>
<script src='js/box2d/dynamics/joints/b2RevoluteJoint.js'></script>
<script src='js/box2d/dynamics/joints/b2RevoluteJointDef.js'></script>

You don’t need to include all of the box2Djs files, just the features you want to use.

1/ Initialization

function init(){
    // Get the canvas data
    canvas = document.getElementById("mainCanvas");
    width = canvas.width;
    height = canvas.height;
    ctx = canvas.getContext("2d");
 
    // This variable will contain all the bodies in our world
    bodies = new Array();						
 
    // Sets the the world
    worldAABB = new b2AABB();
    // Sets the boundaries
    worldAABB.minVertex.Set(-1000, -1000);
    worldAABB.maxVertex.Set(1000, 1000);
 
    // Sets the gravity vector
    gravity = new b2Vec2(0, 300);
    doSleep = true;
 
    // Creates the world
    world = new b2World(worldAABB, gravity, doSleep);		
 
    // Creates a static ground box in our world
    createGround();
}

2/ Update

function step(cnt){
    // Most important function, computes all the forces to be applied and a get new position for each body
    world.Step(1.0/60, 1);
    // Rendering function, draws and display all the elements on the canvas with their new positions
    drawWorld();
    // Set a timer to call the same function
    setTimeout('step(' + (cnt || 0) + ')', 10);
}
function drawWorld(){
    // Clear the canvas
    ctx.clearRect(0, 0, width, height);
    // Draw the ground box
    drawGround();
    // Runs through the bodies array
    for(var i=0; i<bodies.size(); i++){
        // Draw each one of them
        drawCircle(bodies[i]);
    }
}

3/ Input handling

window.onmousedown = function(e){
    if (e == null) e = window.event;
    // for IE, left click == 1
    // for Firefox, left click == 0
    if (e.button == 1 && window.event != null || e.button == 0){
        // Once a click is detected
        // Create a new circle where we clicked
        var circle = createNewCircle(e.clientX, e.clientY);
        // Add it to the bodies list
        bodies.push(circle);
        // Draw the world
        drawWorld();
    }
}

Once you understand how the engine works, it is quite easy to create fancy features with very nice effects. You can for example use the collision listeners provided by the library to add visual or sound effects when two bodies collide. You can also implement some drag and drop functions to launch bodies by applying a force on them – there are many possibilities.

The full code of this demo is available here.
You can check out the API documentation here.

Technology Tutorials:

Leave a comment