Thursday, July 19, 2012

Box2D - Creation of b2Body Objects

I am writing a pingpong game. I realized I was writing lots of repetitive code for creation of the Box2D body. I have tried to simplify it and  created a skeletal method called  createRigidBody(propList) that can be used to create Dynamic/Static, Box/Circle b2Body Objects. I am planning to add Polygons to it soon. The final idea is to make a RigidBody Class that will take care of all the permutations and combinations of creating a RigidBody in Box2D.

function createRigidBody(propList){
var fixDef = new b2FixtureDef;
fixDef.density = propList.density;
        fixDef.friction = propList.friction;
        fixDef.restitution = propList.restitution;
        var bodyDef = new b2BodyDef;
if(propList.type == "StaticBody"){
    bodyDef.type = b2Body.b2_staticBody;
}
if(propList.type == "DynamicBody"){
bodyDef.type = b2Body.b2_dynamicBody;
}
if(propList.shape == "Box"){
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(propList.width, propList.height);
}
if(propList.shape == "Sphere"){
fixDef.shape = new b2CircleShape(propList.width)
}
bodyDef.position.x = propList.x;
bodyDef.position.y = propList.y;
rbData = new Object();
rbData.name = propList.name;
rbData.width = propList.width;
rbData.height = propList.height;
rbData.skin = propList.skin;
bodyDef.userData = rbData;
world.CreateBody(bodyDef).CreateFixture(fixDef);
}


There are three parts to a b2Body
1. Fixture Definition - It defines the attributes of the object, such as density, friction, and restitution (bounciness).
2. Body Definition - It defines where in the world the object is, and if it is dynamic (reacts to things) or static.
3. Shape - it defines the actual 2D geometrical object, such as a circle/box or polygon. Right now this code handles only box/circle

Rendering the Box2D object on the Canvas


The Box2D object can be drawn on the canvas using the Debug2draw method like in the previous example, but that is only for debugging purpose. For gaming we need to render images on the canvas.
When creating the b2Body, i have attached the skin(image to be rendered) information to it for housekeeping purpose.
rbData.skin = propList.skin;   
..
bodyDef.userData = rbData;  

I am using the updateskin(b) method to redraw the canvas for each step in the game world. When Dynamic physics bodies move in the world the canvas has to be updated to make sure that the image is in the exact same position and of same size as the b2Body.


function updateSkin(b)
{
var pos = b.GetPosition();
context.save();
console.log(b.GetWorldCenter().x * SCALE, b.GetWorldCenter().y *SCALE);
context.translate(b.GetWorldCenter().x * SCALE,b.GetWorldCenter().y * SCALE);
context.rotate(b.GetAngle());
width = b.GetUserData().width * SCALE;
height = b.GetUserData().height * SCALE;
context.drawImage(b.GetUserData().skin, -width, -height, (width)*2, (height)*2);
        context.restore();
}
The updateSkin(b) can be a little tricky since the Canvas and the Box2D world have different co-ordinate systems. Also Box2D uses MKS (meters, kilograms, and seconds) units and radians for angles so you have to come up with a conversion factor for mapping from Box2D to Canvas.




Putting it to Together


Now using the above methods, you can create an Box2D object and render it on screen as follows,

function initGround() {
propertyList = new Object();
propertyList.density = 1.0;
propertyList.friction = 0.5;
propertyList.restitution = 0.2;
propertyList.x = 200;
propertyList.y = 390;
propertyList.width = 350;
propertyList.height = 10;
propertyList.type = "StaticBody";
propertyList.shape = "Box"
var image = new Image();
image.src = "image/brick.png";
propertyList.skin = image;
propertyList.name = "Ground";
createRigidBody(propertyList);
}

function gameLoop() {
    world.Step(1 / 60, 8, 3);
    world.ClearForces();
    context.clearRect(0, 0, canvas.width, canvas.height);
    for (b = world.GetBodyList() ; b; b = b.GetNext()) {
// draw the static world objects
 if (b.GetType() == b2Body.b2_staticBody && b.GetUserData() != null){
updateSkin(b);
}
if (b.GetType() == b2Body.b2_dynamicBody && b.GetUserData() != null) {
updateSkin(b);
}
    }
}


1 comment:

  1. Hi,
    I following your blog, reading all articles.
    I have a doubt. Can I get a specific element using GetBodyList? Or an element in the list?

    ReplyDelete