Thursday, July 19, 2012

Box2D collision

This is a continuation from my previous post, I am still on my quest to create a Pingpong game, I will assume that we have all the Images with the physics object rendered in the world, now in order to make it into a game, there are two things,
1. Event Handlers
2. Collision Detection

Event Handlers
I have added my EventListener to the document Class. Every time an event occurs I record it in the global variables moveLeft, moveRight, this is done in keyset(). I use these variable states in the GameLoop to update the Box2D objects.
Alternatively you can use the js-hotkeys jQuery plugin for hooking the keyboard events.


var moveLeft, moveRight;
document.addEventListener("mousedown", handleMouseClick, true);
document.body.addEventListener("keydown", keyset, false);
function handleMouseClick(evt) {
}
function keyset(evt){
        //37: "left", 39: "right"
if(evt.keyCode == 37){
moveLeft = 1;
moveRight = 0;
}
if(evt.keyCode == 39){
moveLeft = 0;
moveRight = 1;
}  
}

Collision Detection
I am doing Collision Detection in the gameLoop, There are alternative ways of doing this, 2weeks into Box2D, this seems the easiest way to do it right now, will post alternatives soon.

The code detects collision between "Ball" and "Bat" and apply's a negative Y force on the ball to make it bounce off the bat in the opposite direction.
In Box2D it's common to think of bodies colliding with each other, but in reality its the fixtures which are used to detect when a collision occurs. Information about a collision is contained in the b2Contact object.

You can look at all the contacts in the world anytime by checking the world's contact list and this is the method that i have used in the following code.

...
//detect collision
 for (var c = world.GetContactList() ; c ; c = c.GetNext()){
var body1 = c.GetFixtureA().GetBody();
               var body2 = c.GetFixtureB().GetBody();
if(body1.GetUserData().name == "Bat" && body2.GetUserData().name == "Ball"){
var force = new b2Vec2(200,-(Math.random())*200000);
var point = new b2Vec2(body2.GetWorldCenter().x * SCALE,body2.GetWorldCenter().y * SCALE);
body2.ApplyForce(force, point);
}
if(body1.GetUserData().name == "Ball" && body2.GetUserData().name == "Bat"){
var force = new b2Vec2(200,-(Math.random())*200000);
var point = new b2Vec2(body1.GetWorldCenter().x * SCALE,body1.GetWorldCenter().y * SCALE);
body1.ApplyForce(force, point);
}
}
....

Alternatively you can look at the contacts for a single body as follows
for (var edge = b.GetContactList() ; edge  ; edge  = edge .GetNext()){

...
}
The other method for collision detection is using the Contact Listeners(will go into this in another blog)

Putting the GameLoop Together
In the game loop Iam taking care of
1. Redrawing the canvas
2. Event Handling, if moveLeft is set, then apply force on the "Bat" object to move it along the x-axis to the left, similarly in the opposite direction if the moveRight is set.
3. Collision Detection to make the ball bounce of the bat when it hits it. 


function gameLoop() {
        world.Step(1 / 60, 8, 3);
        world.ClearForces();
        context.clearRect(0, 0, canvas.width, canvas.height);
world.DrawDebugData();
//detect collision
 for (var c = world.GetContactList() ; c ; c = c.GetNext()){
var body1 = c.GetFixtureA().GetBody();
              var body2 = c.GetFixtureB().GetBody();
if(body1.GetUserData().name == "Bat" && body2.GetUserData().name == "Ball"){
var force = new b2Vec2(200,-(Math.random())*200000);
var point = new b2Vec2(body2.GetWorldCenter().x * SCALE,body2.GetWorldCenter().y * SCALE);
body2.ApplyForce(force, point);
}
if(body1.GetUserData().name == "Ball" && body2.GetUserData().name == "Bat"){
var force = new b2Vec2(200,-(Math.random())*200000);
var point = new b2Vec2(body1.GetWorldCenter().x * SCALE,body1.GetWorldCenter().y * SCALE);
body1.ApplyForce(force, point);
}
}
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) {
if(b.GetUserData().name == "Bat"){
if(moveLeft){
moveLeft = 0;
var force = new b2Vec2(-200000,0);
var point = new b2Vec2(b.GetWorldCenter().x * SCALE,b.GetWorldCenter().y * SCALE);
b.ApplyForce(force, point);
}
if(moveRight){
moveRight = 0;
var force = new b2Vec2(200000,0);
var point = new b2Vec2(b.GetWorldCenter().x * SCALE,b.GetWorldCenter().y * SCALE);
b.ApplyForce(force, point);
}
}
updateSkin(b);
}
}
}

I realize I have too many things happening in my game loop and the same logic might not work in a game with too many objects. right now "Trial and Error" baby :)

No comments:

Post a Comment