Wwwebber's Blog

Box2d 2.1 How to use a b2Controller

Posted in actionscript 3, Box2d by wwwebber on July 9, 2010

Box2d 2.1 brought some awesome improvements
1) improved class structure.
2) buyouncy support
3) a set of Controller Classes that are well described by the docs as ” a convience for encapsulating common per-step functionality.” (read about them here)

These improvements were actually worth the fact that none of your prior Box2d code (and I mean none) would compile with the new class structure.

If you used earlier versions of Bo2D, you already used something like these controllers–the Gravity Vector that you passed to the world object at construction.
This was a b2Vec2 (the gravity) that the world applied to all non-static objects. Ie the walls wouldn’t be affected by the gravity vector but all the moving objects would be affected by a constant force downwards (unless your gravity had an unusual orientation)

There are several types of controllers and they all extends b2Controller . The TestBuoyancy class that comes with the TestBed shows an example of how to use the b2BuoyancyController .

All of the controllers have the following methods

AddBody(body:b2Body):void
RemoveBody(body:b2Body):void

I was interested in using a b2ConstantAccelController. There aren’t really any examples out there for this (at least that I could find) so here’s how easy it is to implement a b2ConstantAccelController–which will just apply an additional vector each time step to any bodies added to that controller.

Now, unlike the GravityVector you can arbitrarily add and remove objects from the controller. How could this be useful? Imagine that you have gusts of wind blowing sideways…you can add your objects to a Contoller and have them pushed sideways…then when the wind passes you could remove them from that controller.

How to create a b2ConstantAccelController :

//construct object and its acceleration vector
var myAccelController:b2ConstantAccelController = new b2ConstantAccelController();
const WIND_VEC :b2Vec2 = new b2Vec2(10,0);
//associate controller with vector
myAccelController.A = WIND_VEC

Henceforth, all b2bodies that are stored in myAccelController will have the WIND_VEC applied to them during the b2World.step() function .. you don’t have to do anything else except add and remove bodies to the controller.

//now let’s add something to the Controller
myAccelController.AddBody(someB2Body);

…when you want to remove the body
myAccelController.RemoveBody(someB2Body);

Advertisements
Tagged with: ,

Box2d 2.1 b2world.QueryPoint() and iterating over a b2fixture list

Posted in actionscript 3, Box2d by wwwebber on May 20, 2010

In version 2.1 (and earlier I believe) of box2d objects are stored in linked lists. A common task will be iterate over one of these linked lists. For instance if you want to iterate over a body’s b2fixture linked list. In my case, I had the following problem: I was making a kids math game on how to combine like terms called Rj The Robot , and I only wanted the robot to jump if it was standing on a ‘floor’ shape. Now all ‘foors’ in the game had a string attached to their b2fixture called ‘is_floor’. Below is some code that demonstrates how floor bodies, shapes and fixtures are creating. Note: if you don’t know what a b2fixture is read this.

//bottom wall
var bottom_wallShape:b2PolygonShape = new b2PolygonShape();
var bottom_wallBd:b2BodyDef = new b2BodyDef();
bottom_wallBd.type = b2Body.b2_staticBody;
var bottom_wallBody:b2Body;
bottom_wallBd.position.Set(halfOfStageWidth /PIXELS_PER_METER , halfOfStage*2/ PIXELS_PER_METER- .5 );
bottom_wallShape.SetAsBox(ground_width, ground_height);
bottom_wallBody = myB2World.CreateBody(bottom_wallBd);


var fd:b2FixtureDef = new b2FixtureDef();
fd.friction = 1 ;
fd.shape = bottom_wallShape;
fd.userData = 'is_floor';
bottom_wallBody.CreateFixture(fd);


Now, I wanted the hero to be able to tell if it was standing on a shape whose b2fixture had the string ‘is_floor’ as its userdata. The solution is to use the b2World.QueryPoint() function . This function takes the form of myb2World.QueryPoint(callbackFunction, someB2Vec) where the someB2Vec is the point to check.  In the picture below I was sending the red dot, called heroFootPoint in my code, to the function. Below is the full code explained in the comments
//get hero's center point
var currentCenter:b2Vec2 = _body.GetWorldCenter();
heroFootPoint.x = currentCenter.x
heroFootPoint.y = currentCenter.y + 1.43    //add 1.43 so point is below Robot  foot;
var bIsOnFloor:Boolean = false;             //assume not standing on floor

function bOnFloorFixture(fixture:b2Fixture):Boolean    //call back function
{                                                                                                               //this call back function
var body:b2Body = b2Fixture(fixture).GetBody();            //get body of current fixture
var bsFixture:b2Fixture = body.GetFixtureList();
while (bsFixture != null )                                                                 //it
{
if (bsFixture.GetUserData() == ‘is_floor’)                  //found a fixture whose userdata is ‘is_floor’…ie are standing on the floor
{
bIsOnFloor = true;
return false;                                                                           //return false so that we don’t continue iterating over the list
}
bsFixture = bsFixture.GetNext();                              //if we got here we didn’t yet find a fixture with ‘is_floor’ userdat..

}                                                                                              //so see if body has another b2fixture attached for checking

return true;                                                                                    //callback returns true means that the queryWorld() function will check next b2Fixture at heroFootPoint
}
myB2World.QueryPoint(bOnFloorFixture, heroFootPoint);               //start queryPoint()…check all fixtures overlapping heroFootPoint

Comments Off on Box2d 2.1 b2world.QueryPoint() and iterating over a b2fixture list