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
.
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.
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.
for(var i = 0; i < 5; ++i)
{
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);
w.setOffset(w.getWidth()/2, w.getHeight()/2);
fixDef.shape = new b2PolygonShape;
var off = w.getOffset();
fixDef.shape.SetAsBox(off.x/scale, off.y/scale);
var pos = w.getAbsolutePosition();
bodyDef.position.Set((pos.x+off.x)/scale, (pos.y+off.y)/scale);
var body = world.CreateBody(bodyDef);
body.CreateFixture(fixDef);
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).
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.