Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Box2D and JavaScript: Part 3

5.00/5 (1 vote)
21 Apr 2013CPOL3 min read 11.8K  
Integration of Box2D-web with KineticJS library.

Introduction

In Part 2, I covered a basic setup for box2d based simulations and in this long promised final installment of the tutorial series, I will cover the integration with KineticJS library. The most important aspect of this part is how to use a framework like KineticJS and use its features for image rendering and manipulation in physics based simulations without having to write your own physics engine for it.

Before I break up the code and explain the details, you can see here what it is and how it works. And may be download the source code from Git.

First, I define the two functions `loadImages` & `init` to initialize the image sources and load them before we start manipulating them. To read more about loadingImages, check this post.

Next, let's initialize KineticJS related variables - stage and layer as below. Parameter passed as "container" is the name of the div that will be used to create the canvas object by KineticJS.

C#
stage = new Kinetic.Stage(
{container:"canvas", width:screenW, height:screenH});
gameLayer = new Kinetic.Layer();

Then we'll define a KineticJS Image type object to create a background image using one of the images we earlier loaded. Then we add this object to our gameLayer and finally add the gameLayer to our stage.

C#
var gameBg = new Kinetic.Image(

{
 image:images.gameBg,
 x:0, y:0,
 width:screenW, height:screenH
});
gameLayer.add(gameBg); 
//
 Add the gameBg object to our gameLayer
stage.add(gameLayer); 
//
 And add our gameLayer to our stage

After this, we'll do our initialization for Box2D world and ground just like the previous post. However, the objects inside this world will be initialized differently. The code below, adds 5 wall objects to our game canvas as well as box2d world.

C#
for(var i = 0; i < 5; ++i) 
{
 
// lets create a new Image of a wall
var w = new Kinetic.Image(
{
  image: images.w,
  x:Math.random() * screenW,
  y:Math.random() * screenH/4,
  width: images.w.width/4,
  height: images.w.height/4
 });
 gameLayer.add(w);

 
// by default images are positioned from top-left, and box2d objects from center, 
// so let us offset our images to be addressed from center rather than top-left

 w.setOffset(w.getWidth()/2, w.getHeight()/2);

 
// now let us create the corresponding box2d object.
 
// Read my previous post for box2d object details: 
// http://aniruddhaloya.blogspot.com/2012/11/box2d-javascript-part-2.html
 fixDef.shape = new b2PolygonShape;

 var off = w.getOffset();
 fixDef.shape.SetAsBox(off.x/scale, off.y/scale); 

// Remember that we need to scale the canvas to box2d coordinates

 var pos = w.getAbsolutePosition();

 bodyDef.position.Set((pos.x+off.x)/scale, (pos.y+off.y)/scale); 

// Remember that we need to scale the canvas to box2d coordinates

 var body = world.CreateBody(bodyDef);
 body.CreateFixture(fixDef);

// let us push the corresponding objects in their respective containers.
 walls.push(body);
 tiles.push(w);
}

Let's analyze what we are doing in the above piece of code. We first create KineticJS image objects and place it randomly in the screen and add it to the gameLayer. Next, we use setOffest() function of KineticJS to move our image anchor position to its center rather than the default top-left. This is required for proper rotation and correspondance with the corresponding objects in box2d world which we create after that. The creation of corresponding box2d world objects is similar to that in the previous tutorial, except that one needs to take care of the unit system (i.e. scaling factor) between the two environments. Finally, we add the two objects in corresponding containers for ease of access and mapping during the update step (below).

C#
// Traverse through all the box2d objects and update the 
// positions and rotations of corresponding KineticJS objects
for(var i = 0; i < walls.length; i++)
{
 var body = walls[i];
 var wall = tiles[i];
 var p = body.GetPosition();
 wall.setRotation(body.GetAngle());
 wall.setPosition(p.x*scale, p.y*scale);
}

Finally, we need to map and update both the objects. Here, box2d takes care of all the interactions which we simply map to the corresponding KineticJS image objects. Note carefully the use of "scale" parameter which unlike previous code snippet is now multiplied rather than divided.

And like the last time, press 'd' to see the simulation in debug-Draw mode offered by box2d and be assured that the images are actually moving like the physics body they are attached to.

Wow... I finally manage to take time and complete this series. I hope my fellow game developers who are starting/ planning to develop the next Angry Birds find it useful. I'll love to hear your suggestions!

Last but not the least, the entire source code for this tutorial can be downloaded from Git.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)