Box2D 2.4.1
A 2D physics engine for games
Loading...
Searching...
No Matches
Dynamics Module

The Dynamics module is the most complex part of Box2D and is the part you likely interact with the most. The Dynamics module sits on top of the Common and Collision modules, so you should be somewhat familiar with those by now.

The Dynamics module contains:

  • fixture class
  • rigid body class
  • contact class
  • joint classes
  • world class
  • listener classes

There are many dependencies between these classes so it is difficult to describe one class without referring to another. In the following, you may see some references to classes that have not been described yet. Therefore, you may want to quickly skim this chapter before reading it closely.

The dynamics module is covered in the following chapters.

Bodies

Bodies have position and velocity. You can apply forces, torques, and impulses to bodies. Bodies can be static, kinematic, or dynamic. Here are the body type definitions:

b2_staticBody

A static body does not move under simulation and behaves as if it has infinite mass. Internally, Box2D stores zero for the mass and the inverse mass. Static bodies can be moved manually by the user. A static body has zero velocity. Static bodies do not collide with other static or kinematic bodies.

b2_kinematicBody

A kinematic body moves under simulation according to its velocity. Kinematic bodies do not respond to forces. They can be moved manually by the user, but normally a kinematic body is moved by setting its velocity. A kinematic body behaves as if it has infinite mass, however, Box2D stores zero for the mass and the inverse mass. Kinematic bodies do not collide with other kinematic or static bodies.

b2_dynamicBody

A dynamic body is fully simulated. They can be moved manually by the user, but normally they move according to forces. A dynamic body can collide with all body types. A dynamic body always has finite, non-zero mass. If you try to set the mass of a dynamic body to zero, it will automatically acquire a mass of one kilogram and it won't rotate.

Bodies are the backbone for fixtures (shapes). Bodies carry fixtures and move them around in the world. Bodies are always rigid bodies in Box2D. That means that two fixtures attached to the same rigid body never move relative to each other and fixtures attached to the same body don't collide.

Fixtures have collision geometry and density. Normally, bodies acquire their mass properties from the fixtures. However, you can override the mass properties after a body is constructed.

You usually keep pointers to all the bodies you create. This way you can query the body positions to update the positions of your graphical entities. You should also keep body pointers so you can destroy them when you are done with them.

Body Definition

Before a body is created you must create a body definition (b2BodyDef). The body definition holds the data needed to create and initialize a body.

Box2D copies the data out of the body definition; it does not keep a pointer to the body definition. This means you can recycle a body definition to create multiple bodies.

Let's go over some of the key members of the body definition.

Body Type

As discussed at the beginning of this chapter, there are three different body types: static, kinematic, and dynamic. You should establish the body type at creation because changing the body type later is expensive.

b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
Definition b2_body.h:53
b2BodyType type
Definition b2_body.h:74

Setting the body type is mandatory.

Position and Angle

The body definition gives you the chance to initialize the position of the body on creation. This has far better performance than creating the body at the world origin and then moving the body.

Caution: Do not create a body at the origin and then move it. If you create several bodies at the origin, then performance will suffer.

A body has two main points of interest. The first point is the body's origin. Fixtures and joints are attached relative to the body's origin. The second point of interest is the center of mass. The center of mass is determined from mass distribution of the attached shapes or is explicitly set with b2MassData. Much of Box2D's internal computations use the center of mass position. For example b2Body stores the linear velocity for the center of mass.

When you are building the body definition, you may not know where the center of mass is located. Therefore you specify the position of the body's origin. You may also specify the body's angle in radians, which is not affected by the position of the center of mass. If you later change the mass properties of the body, then the center of mass may move on the body, but the origin position does not change and the attached shapes and joints do not move.

b2BodyDef bodyDef;
bodyDef.position.Set(0.0f, 2.0f); // the body's origin position.
bodyDef.angle = 0.25f * b2_pi; // the body's angle in radians.
b2Vec2 position
Definition b2_body.h:78
float angle
The world angle of the body in radians.
Definition b2_body.h:81
void Set(float x_, float y_)
Set this vector to some specified coordinates.
Definition b2_math.h:53

A rigid body is also a frame of reference. You can define fixtures and joints in that frame. Those fixtures and joint anchors never move in the local frame of the body.

Damping

Damping is used to reduce the world velocity of bodies. Damping is different than friction because friction only occurs with contact. Damping is not a replacement for friction and the two effects should be used together.

Damping parameters should be between 0 and infinity, with 0 meaning no damping, and infinity meaning full damping. Normally you will use a damping value between 0 and 0.1. I generally do not use linear damping because it makes bodies look like they are floating.

b2BodyDef bodyDef;
bodyDef.linearDamping = 0.0f;
bodyDef.angularDamping = 0.01f;
float linearDamping
Definition b2_body.h:93
float angularDamping
Definition b2_body.h:99

Damping is approximated for stability and performance. At small damping values the damping effect is mostly independent of the time step. At larger damping values, the damping effect will vary with the time step. This is not an issue if you use a fixed time step (recommended).

Gravity Scale

You can use the gravity scale to adjust the gravity on a single body. Be careful though, increased gravity can decrease stability.

// Set the gravity scale to zero so this body will float
b2BodyDef bodyDef;
bodyDef.gravityScale = 0.0f;
float gravityScale
Scale the gravity applied to this body.
Definition b2_body.h:124

Sleep Parameters

What does sleep mean? Well it is expensive to simulate bodies, so the less we have to simulate the better. When a body comes to rest we would like to stop simulating it.

When Box2D determines that a body (or group of bodies) has come to rest, the body enters a sleep state which has very little CPU overhead. If a body is awake and collides with a sleeping body, then the sleeping body wakes up. Bodies will also wake up if a joint or contact attached to them is destroyed. You can also wake a body manually.

The body definition lets you specify whether a body can sleep and whether a body is created sleeping.

b2BodyDef bodyDef;
bodyDef.allowSleep = true;
bodyDef.awake = true;
bool allowSleep
Definition b2_body.h:103
bool awake
Is this body initially awake or sleeping?
Definition b2_body.h:106

Fixed Rotation

You may want a rigid body, such as a character, to have a fixed rotation. Such a body should not rotate, even under load. You can use the fixed rotation setting to achieve this:

b2BodyDef bodyDef;
bodyDef.fixedRotation = true;
bool fixedRotation
Should this body be prevented from rotating? Useful for characters.
Definition b2_body.h:109

The fixed rotation flag causes the rotational inertia and its inverse to be set to zero.

Bullets

Game simulation usually generates a sequence of images that are played at some frame rate. This is called discrete simulation. In discrete simulation, rigid bodies can move by a large amount in one time step. If a physics engine doesn't account for the large motion, you may see some objects incorrectly pass through each other. This effect is called tunneling.

By default, Box2D uses continuous collision detection (CCD) to prevent dynamic bodies from tunneling through static bodies. This is done by sweeping shapes from their old position to their new positions. The engine looks for new collisions during the sweep and computes the time of impact (TOI) for these collisions. Bodies are moved to their first TOI and then the solver performs a sub-step to complete the full time step. There may be additional TOI events within a sub-step.

Normally CCD is not used between dynamic bodies. This is done to keep performance reasonable. In some game scenarios you need dynamic bodies to use CCD. For example, you may want to shoot a high speed bullet at a stack of dynamic bricks. Without CCD, the bullet might tunnel through the bricks.

Fast moving objects in Box2D can be labeled as bullets. Bullets will perform CCD with both static and dynamic bodies. You should decide what bodies should be bullets based on your game design. If you decide a body should be treated as a bullet, use the following setting.

b2BodyDef bodyDef;
bodyDef.bullet = true;
bool bullet
Definition b2_body.h:115

The bullet flag only affects dynamic bodies.

Activation

You may wish a body to be created but not participate in collision or dynamics. This state is similar to sleeping except the body will not be woken by other bodies and the body's fixtures will not be placed in the broad-phase. This means the body will not participate in collisions, ray casts, etc.

You can create a body in an inactive state and later re-activate it.

b2BodyDef bodyDef;
bodyDef.active = true;

Joints may be connected to inactive bodies. These joints will not be simulated. You should be careful when you activate a body that its joints are not distorted.

Note that activating a body is almost as expensive as creating the body from scratch. So you should not use activation for streaming worlds. Use creation/destruction for streaming worlds to save memory.

User Data

User data is a void pointer. This gives you a hook to link your application objects to bodies. You should be consistent to use the same object type for all body user data.

b2BodyDef bodyDef;
bodyDef.userData.pointer = reinterpret_cast<uintptr_t>(&myActor);
b2BodyUserData userData
Use this to store application specific body data.
Definition b2_body.h:121
uintptr_t pointer
For legacy compatibility.
Definition b2_settings.h:66

Body Factory

Bodies are created and destroyed using a body factory provided by the world class. This lets the world create the body with an efficient allocator and add the body to the world data structure.

b2World* myWorld;
b2Body* dynamicBody = myWorld->CreateBody(&bodyDef);
// ... do stuff ...
myWorld->DestroyBody(dynamicBody);
dynamicBody = nullptr;
A rigid body. These are created via b2World::CreateBody.
Definition b2_body.h:129
Definition b2_world.h:47
b2Body * CreateBody(const b2BodyDef *def)
void DestroyBody(b2Body *body)

Caution: You should never use new or malloc to create a body. The world won't know about the body and the body won't be properly initialized.

Box2D does not keep a reference to the body definition or any of the data it holds (except user data pointers). So you can create temporary body definitions and reuse the same body definitions.

Box2D allows you to avoid destroying bodies by deleting your b2World object, which does all the cleanup work for you. However, you should be mindful to nullify body pointers that you keep in your game engine.

When you destroy a body, the attached fixtures and joints are automatically destroyed. This has important implications for how you manage shape and joint pointers.

Using a Body

After creating a body, there are many operations you can perform on the body. These include setting mass properties, accessing position and velocity, applying forces, and transforming points and vectors.

Mass Data

A body has mass (scalar), center of mass (2-vector), and rotational inertia (scalar). For static bodies, the mass and rotational inertia are set to zero. When a body has fixed rotation, its rotational inertia is zero.

Normally the mass properties of a body are established automatically when fixtures are added to the body. You can also adjust the mass of a body at run-time. This is usually done when you have special game scenarios that require altering the mass.

void b2Body::SetMassData(const b2MassData* data);
void SetMassData(const b2MassData *data)
This holds the mass data computed for a shape.
Definition b2_shape.h:34

After setting a body's mass directly, you may wish to revert to the natural mass dictated by the fixtures. You can do this with:

void ResetMassData()

The body's mass data is available through the following functions:

float b2Body::GetMass() const;
float b2Body::GetInertia() const;
void b2Body::GetMassData(b2MassData* data) const;
const b2Vec2 & GetLocalCenter() const
Get the local position of the center of mass.
Definition b2_body.h:496
float GetMass() const
Definition b2_body.h:541
b2MassData GetMassData() const
Definition b2_body.h:551
float GetInertia() const
Definition b2_body.h:546
A 2D column vector.
Definition b2_math.h:42

State Information

There are many aspects to the body's state. You can access this state data efficiently through the following functions:

void b2Body::SetType(b2BodyType type);
b2BodyType b2Body::GetType();
void b2Body::SetBullet(bool flag);
bool b2Body::IsBullet() const;
void b2Body::SetAwake(bool flag);
bool b2Body::IsAwake() const;
void b2Body::SetEnabled(bool flag);
bool b2Body::IsEnabled() const;
void b2Body::SetFixedRotation(bool flag);
bool IsEnabled() const
Get the active state of the body.
Definition b2_body.h:665
void SetEnabled(bool flag)
bool IsFixedRotation() const
Does this body have fixed rotation?
Definition b2_body.h:670
void SetSleepingAllowed(bool flag)
Definition b2_body.h:675
void SetBullet(bool flag)
Should this body be treated like a bullet for continuous collision detection?
Definition b2_body.h:620
void SetType(b2BodyType type)
Set the type of this body. This may alter the mass and velocity.
bool IsAwake() const
Definition b2_body.h:660
b2BodyType GetType() const
Get the type of this body.
Definition b2_body.h:471
bool IsSleepingAllowed() const
Is this body allowed to sleep.
Definition b2_body.h:688
void SetAwake(bool flag)
Definition b2_body.h:637
bool IsBullet() const
Is this body treated like a bullet for continuous collision detection?
Definition b2_body.h:632
void SetFixedRotation(bool flag)

Position and Velocity

You can access the position and rotation of a body. This is common when rendering your associated game actor. You can also set the position, although this is less common since you will normally use Box2D to simulate movement.

bool b2Body::SetTransform(const b2Vec2& position, float angle);
const b2Vec2& b2Body::GetPosition() const;
float b2Body::GetAngle() const;
const b2Vec2 & GetPosition() const
Definition b2_body.h:481
float GetAngle() const
Definition b2_body.h:486
void SetTransform(const b2Vec2 &position, float angle)
const b2Transform & GetTransform() const
Definition b2_body.h:476
Definition b2_math.h:339

You can access the center of mass position in local and world coordinates. Much of the internal simulation in Box2D uses the center of mass. However, you should normally not need to access it. Instead you will usually work with the body transform. For example, you may have a body that is square. The body origin might be a corner of the square, while the center of mass is located at the center of the square.

const b2Vec2 & GetWorldCenter() const
Get the world position of the center of mass.
Definition b2_body.h:491

You can access the linear and angular velocity. The linear velocity is for the center of mass. Therefore, the linear velocity may change if the mass properties change.

Forces and Impulses

You can apply forces, torques, and impulses to a body. When you apply a force or an impulse, you provide a world point where the load is applied. This often results in a torque about the center of mass.

void b2Body::ApplyForce(const b2Vec2& force, const b2Vec2& point);
void b2Body::ApplyTorque(float torque);
void b2Body::ApplyLinearImpulse(const b2Vec2& impulse, const b2Vec2& point);
void b2Body::ApplyAngularImpulse(float impulse);
void ApplyAngularImpulse(float impulse, bool wake)
Definition b2_body.h:840
void ApplyLinearImpulse(const b2Vec2 &impulse, const b2Vec2 &point, bool wake)
Definition b2_body.h:801
void ApplyForce(const b2Vec2 &force, const b2Vec2 &point, bool wake)
Definition b2_body.h:743
void ApplyTorque(float torque, bool wake)
Definition b2_body.h:782

Applying a force, torque, or impulse wakes the body. Sometimes this is undesirable. For example, you may be applying a steady force and want to allow the body to sleep to improve performance. In this case you can use the following code.

if (myBody->IsAwake() == true)
{
myBody->ApplyForce(myForce, myPoint);
}

Coordinate Transformations

The body class has some utility functions to help you transform points and vectors between local and world space. If you don't understand these concepts, please read "Essential Mathematics for Games and Interactive Applications" by Jim Van Verth and Lars Bishop. These functions are efficient (when inlined).

b2Vec2 b2Body::GetWorldPoint(const b2Vec2& localPoint);
b2Vec2 b2Body::GetWorldVector(const b2Vec2& localVector);
b2Vec2 b2Body::GetLocalPoint(const b2Vec2& worldPoint);
b2Vec2 b2Body::GetLocalVector(const b2Vec2& worldVector);
b2Vec2 GetLocalPoint(const b2Vec2 &worldPoint) const
Definition b2_body.h:570
b2Vec2 GetWorldPoint(const b2Vec2 &localPoint) const
Definition b2_body.h:560
b2Vec2 GetWorldVector(const b2Vec2 &localVector) const
Definition b2_body.h:565
b2Vec2 GetLocalVector(const b2Vec2 &worldVector) const
Definition b2_body.h:575

Acessing Fixtures, Joints, and Contacts

You can iterate over a body's fixtures. This is mainly useful if you need to access the fixture's user data.

for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
{
MyFixtureData* data = (MyFixtureData*)f->GetUserData();
// do something with data ...
}
Definition b2_fixture.h:117
b2Fixture * GetNext()
Definition b2_fixture.h:299

You can similarly iterate over the body's joint list.

The body also provides a list of associated contacts. You can use this to get information about the current contacts. Be careful, because the contact list may not contain all the contacts that existed during the previous time step.

Fixtures

Recall that shapes don't know about bodies and may be used independently of the physics simulation. Therefore Box2D provides the b2Fixture class to attach shapes to bodies. A body may have zero or more fixtures. A body with multiple fixtures is sometimes called a compound body.

Fixtures hold the following:

  • a single shape
  • broad-phase proxies
  • density, friction, and restitution
  • collision filtering flags
  • back pointer to the parent body
  • user data
  • sensor flag

These are described in the following sections.

Fixture Creation

Fixtures are created by initializing a fixture definition and then passing the definition to the parent body.

b2Body* myBody;
b2FixtureDef fixtureDef;
fixtureDef.shape = &myShape;
fixtureDef.density = 1.0f;
b2Fixture* myFixture = myBody->CreateFixture(&fixtureDef);
b2Fixture * CreateFixture(const b2FixtureDef *def)
Definition b2_fixture.h:62
const b2Shape * shape
Definition b2_fixture.h:76
float density
The density, usually in kg/m^2.
Definition b2_fixture.h:92

This creates the fixture and attaches it to the body. You do not need to store the fixture pointer since the fixture will automatically be destroyed when the parent body is destroyed. You can create multiple fixtures on a single body.

You can destroy a fixture on the parent body. You may do this to model a breakable object. Otherwise you can just leave the fixture alone and let the body destruction take care of destroying the attached fixtures.

myBody->DestroyFixture(myFixture);
void DestroyFixture(b2Fixture *fixture)

Density

The fixture density is used to compute the mass properties of the parent body. The density can be zero or positive. You should generally use similar densities for all your fixtures. This will improve stacking stability.

The mass of a body is not adjusted when you set the density. You must call ResetMassData for this to occur.

b2Fixture* fixture;
fixture->SetDensity(5.0f);
body->ResetMassData();
void SetDensity(float density)
Definition b2_fixture.h:309

Friction

Friction is used to make objects slide along each other realistically. Box2D supports static and dynamic friction, but uses the same parameter for both. Friction is simulated accurately in Box2D and the friction strength is proportional to the normal force (this is called Coulomb friction). The friction parameter is usually set between 0 and 1, but can be any non-negative value. A friction value of 0 turns off friction and a value of 1 makes the friction strong. When the friction force is computed between two shapes, Box2D must combine the friction parameters of the two parent fixtures. This is done with the geometric mean:

b2Fixture* fixtureA;
b2Fixture* fixtureB;
float friction;
friction = sqrtf(fixtureA->friction * fixtureB->friction);

So if one fixture has zero friction then the contact will have zero friction.

You can override the default mixed friction using b2Contact::SetFriction. This is usually done in the b2ContactListener callback.

Restitution

Restitution is used to make objects bounce. The restitution value is usually set to be between 0 and 1. Consider dropping a ball on a table. A value of zero means the ball won't bounce. This is called an inelastic collision. A value of one means the ball's velocity will be exactly reflected. This is called a perfectly elastic collision. Restitution is combined using the following formula.

b2Fixture* fixtureA;
b2Fixture* fixtureB;
float restitution;
restitution = b2Max(fixtureA->restitution, fixtureB->restitution);

Restitution is combined this way so that you can have a bouncy super ball without having a bouncy floor.

You can override the default mixed restitution using b2Contact::SetRestitution. This is usually done in the b2ContactListener callback.

When a shape develops multiple contacts, restitution is simulated approximately. This is because Box2D uses an iterative solver. Box2D also uses inelastic collisions when the collision velocity is small. This is done to prevent jitter. See b2_velocityThreshold.

Filtering

Collision filtering allows you to prevent collision between fixtures. For example, say you make a character that rides a bicycle. You want the bicycle to collide with the terrain and the character to collide with the terrain, but you don't want the character to collide with the bicycle (because they must overlap). Box2D supports such collision filtering using categories and groups.

Box2D supports 16 collision categories. For each fixture you can specify which category it belongs to. You also specify what other categories this fixture can collide with. For example, you could specify in a multiplayer game that all players don't collide with each other and monsters don't collide with each other, but players and monsters should collide. This is done with masking bits. For example:

b2FixtureDef playerFixtureDef, monsterFixtureDef;
playerFixtureDef.filter.categoryBits = 0x0002;
monsterFixtureDef.filter.categoryBits = 0x0004;
playerFixtureDef.filter.maskBits = 0x0004;
monsterFixtureDef.filter.maskBits = 0x0002;
uint16 categoryBits
The collision category bits. Normally you would just set one bit.
Definition b2_fixture.h:47
uint16 maskBits
Definition b2_fixture.h:51
b2Filter filter
Contact filtering data.
Definition b2_fixture.h:99

Here is the rule for a collision to occur:

uint16 catA = fixtureA.filter.categoryBits;
uint16 maskA = fixtureA.filter.maskBits;
uint16 catB = fixtureB.filter.categoryBits;
uint16 maskB = fixtureB.filter.maskBits;
if ((catA & maskB) != 0 && (catB & maskA) != 0)
{
// fixtures can collide
}

Collision groups let you specify an integral group index. You can have all fixtures with the same group index always collide (positive index) or never collide (negative index). Group indices are usually used for things that are somehow related, like the parts of a bicycle. In the following example, fixture1 and fixture2 always collide, but fixture3 and fixture4 never collide.

fixture1Def.filter.groupIndex = 2;
fixture2Def.filter.groupIndex = 2;
fixture3Def.filter.groupIndex = -8;
fixture4Def.filter.groupIndex = -8;

Collisions between fixtures of different group indices are filtered according the category and mask bits. In other words, group filtering has higher precedence than category filtering.

Note that additional collision filtering occurs in Box2D. Here is a list:

  • A fixture on a static body can only collide with a dynamic body.
  • A fixture on a kinematic body can only collide with a dynamic body.
  • Fixtures on the same body never collide with each other.
  • You can optionally enable/disable collision between fixtures on bodies connected by a joint.

Sometimes you might need to change collision filtering after a fixture has already been created. You can get and set the b2Filter structure on an existing fixture using b2Fixture::GetFilterData and b2Fixture::SetFilterData. Note that changing the filter data will not add or remove contacts until the next time step (see the World class).

Sensors

Sometimes game logic needs to know when two fixtures overlap yet there should be no collision response. This is done by using sensors. A sensor is a fixture that detects collision but does not produce a response.

You can flag any fixture as being a sensor. Sensors may be static, kinematic, or dynamic. Remember that you may have multiple fixtures per body and you can have any mix of sensors and solid fixtures. Also, sensors only form contacts when at least one body is dynamic, so you will not get a contact for kinematic versus kinematic, kinematic versus static, or static versus static.

Sensors do not generate contact points. There are two ways to get the state of a sensor:

  1. b2Contact::IsTouching
  2. b2ContactListener::BeginContact and b2ContactListener::EndContact

Joints

Joints are used to constrain bodies to the world or to each other. Typical examples in games include ragdolls, teeters, and pulleys. Joints can be combined in many different ways to create interesting motions.

Some joints provide limits so you can control the range of motion. Some joint provide motors which can be used to drive the joint at a prescribed speed until a prescribed force/torque is exceeded.

Joint motors can be used in many ways. You can use motors to control position by specifying a joint velocity that is proportional to the difference between the actual and desired position. You can also use motors to simulate joint friction: set the joint velocity to zero and provide a small, but significant maximum motor force/torque. Then the motor will attempt to keep the joint from moving until the load becomes too strong.

Joint Definition

Each joint type has a definition that derives from b2JointDef. All joints are connected between two different bodies. One body may be static. Joints between static and/or kinematic bodies are allowed, but have no effect and use some processing time.

You can specify user data for any joint type and you can provide a flag to prevent the attached bodies from colliding with each other. This is actually the default behavior and you must set the collideConnected Boolean to allow collision between to connected bodies.

Many joint definitions require that you provide some geometric data. Often a joint will be defined by anchor points. These are points fixed in the attached bodies. Box2D requires these points to be specified in local coordinates. This way the joint can be specified even when the current body transforms violate the joint constraint --- a common occurrence when a game is saved and reloaded. Additionally, some joint definitions need to know the default relative angle between the bodies. This is necessary to constrain rotation correctly.

Initializing the geometric data can be tedious, so many joints have initialization functions that use the current body transforms to remove much of the work. However, these initialization functions should usually only be used for prototyping. Production code should define the geometry directly. This will make joint behavior more robust.

The rest of the joint definition data depends on the joint type. We cover these now.

Joint Factory

Joints are created and destroyed using the world factory methods. This brings up an old issue:

Caution: Don't try to create a joint on the stack or on the heap using new or malloc. You must create and destroy bodies and joints using the create and destroy methods of the b2World class.

Here's an example of the lifetime of a revolute joint:

b2World* myWorld;
jointDef.bodyA = myBodyA;
jointDef.bodyB = myBodyB;
jointDef.anchorPoint = myBodyA->GetCenterPosition();
b2RevoluteJoint* joint = (b2RevoluteJoint*)myWorld->CreateJoint(&jointDef);
// ... do stuff ...
myWorld->DestroyJoint(joint);
joint = nullptr;
Definition b2_revolute_joint.h:95
b2Joint * CreateJoint(const b2JointDef *def)
void DestroyJoint(b2Joint *joint)
b2Body * bodyA
The first attached body.
Definition b2_joint.h:88
b2Body * bodyB
The second attached body.
Definition b2_joint.h:91
Definition b2_revolute_joint.h:40

It is always good to nullify your pointer after they are destroyed. This will make the program crash in a controlled manner if you try to reuse the pointer.

The lifetime of a joint is not simple. Heed this warning well:

Caution: Joints are destroyed when an attached body is destroyed.

This precaution is not always necessary. You may organize your game engine so that joints are always destroyed before the attached bodies. In this case you don't need to implement the listener class. See the section on Implicit Destruction for details.

Using Joints

Many simulations create the joints and don't access them again until they are destroyed. However, there is a lot of useful data contained in joints that you can use to create a rich simulation.

First of all, you can get the bodies, anchor points, and user data from a joint.

b2Body * GetBodyA()
Get the first body attached to this joint.
Definition b2_joint.h:198
b2Body * GetBodyB()
Get the second body attached to this joint.
Definition b2_joint.h:203
virtual b2Vec2 GetAnchorB() const =0
Get the anchor point on bodyB in world coordinates.
b2JointUserData & GetUserData()
Get the user data pointer.
Definition b2_joint.h:218
virtual b2Vec2 GetAnchorA() const =0
Get the anchor point on bodyA in world coordinates.

All joints have a reaction force and torque. This the reaction force applied to body 2 at the anchor point. You can use reaction forces to break joints or trigger other game events. These functions may do some computations, so don't call them if you don't need the result.

virtual b2Vec2 GetReactionForce(float inv_dt) const =0
Get the reaction force on bodyB at the joint anchor in Newtons.
virtual float GetReactionTorque(float inv_dt) const =0
Get the reaction torque on bodyB in N*m.

Distance Joint

One of the simplest joint is a distance joint which says that the distance between two points on two bodies must be constant. When you specify a distance joint the two bodies should already be in place. Then you specify the two anchor points in world coordinates. The first anchor point is connected to body 1, and the second anchor point is connected to body 2. These points imply the length of the distance constraint.

Distance Joint

Here is an example of a distance joint definition. In this case we decide to allow the bodies to collide.

jointDef.Initialize(myBodyA, myBodyB, worldAnchorOnBodyA,
worldAnchorOnBodyB);
jointDef.collideConnected = true;
Definition b2_distance_joint.h:34
void Initialize(b2Body *bodyA, b2Body *bodyB, const b2Vec2 &anchorA, const b2Vec2 &anchorB)
bool collideConnected
Set this flag to true if the attached bodies should collide.
Definition b2_joint.h:94

The distance joint can also be made soft, like a spring-damper connection. See the Web example in the testbed to see how this behaves.

Softness is achieved by tuning two constants in the definition: stiffness and damping. It can be non-intuitive setting these values directly since they have units in terms on Newtons. Box2D provides and API to compute these values in terms of frequency and damping ratio.

void b2LinearStiffness(float& stiffness, float& damping,
float frequencyHertz, float dampingRatio,
const b2Body* bodyA, const b2Body* bodyB);

Think of the frequency as the frequency of a harmonic oscillator (like a guitar string). The frequency is specified in Hertz. Typically the frequency should be less than a half the frequency of the time step. So if you are using a 60Hz time step, the frequency of the distance joint should be less than 30Hz. The reason is related to the Nyquist frequency.

The damping ratio is non-dimensional and is typically between 0 and 1, but can be larger. At 1, the damping is critical (all oscillations should vanish).

float frequencyHz = 4.0f;
float dampingRatio = 0.5f;
b2LinearStiffness(jointDef.stiffness, jointDef.damping, frequencyHz, dampingRatio, jointDef.bodyA, jointDef.bodyB);
float stiffness
The linear stiffness in N/m.
Definition b2_distance_joint.h:68
float damping
The linear damping in N*s/m.
Definition b2_distance_joint.h:71

It is also possible to define a minimum and maximum length for the distance joint. See b2DistanceJointDef for details.

Revolute Joint

A revolute joint forces two bodies to share a common anchor point, often called a hinge point. The revolute joint has a single degree of freedom: the relative rotation of the two bodies. This is called the joint angle.

Revolute Joint

To specify a revolute you need to provide two bodies and a single anchor point in world space. The initialization function assumes that the bodies are already in the correct position.

In this example, two bodies are connected by a revolute joint at the first body's center of mass.

jointDef.Initialize(myBodyA, myBodyB, myBodyA->GetWorldCenter());
void Initialize(b2Body *bodyA, b2Body *bodyB, const b2Vec2 &anchor)

The revolute joint angle is positive when bodyB rotates CCW about the angle point. Like all angles in Box2D, the revolute angle is measured in radians. By convention the revolute joint angle is zero when the joint is created using Initialize(), regardless of the current rotation of the two bodies.

In some cases you might wish to control the joint angle. For this, the revolute joint can optionally simulate a joint limit and/or a motor.

A joint limit forces the joint angle to remain between a lower and upper bound. The limit will apply as much torque as needed to make this happen. The limit range should include zero, otherwise the joint will lurch when the simulation begins.

A joint motor allows you to specify the joint speed (the time derivative of the angle). The speed can be negative or positive. A motor can have infinite force, but this is usually not desirable. Recall the eternal question:

What happens when an irresistible force meets an immovable object?

I can tell you it's not pretty. So you can provide a maximum torque for the joint motor. The joint motor will maintain the specified speed unless the required torque exceeds the specified maximum. When the maximum torque is exceeded, the joint will slow down and can even reverse.

You can use a joint motor to simulate joint friction. Just set the joint speed to zero, and set the maximum torque to some small, but significant value. The motor will try to prevent the joint from rotating, but will yield to a significant load.

Here's a revision of the revolute joint definition above; this time the joint has a limit and a motor enabled. The motor is setup to simulate joint friction.

jointDef.Initialize(bodyA, bodyB, myBodyA->GetWorldCenter());
jointDef.lowerAngle = -0.5f * b2_pi; // -90 degrees
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f;
jointDef.motorSpeed = 0.0f;
jointDef.enableMotor = true;
float lowerAngle
The lower angle for the joint limit (radians).
Definition b2_revolute_joint.h:72
bool enableLimit
A flag to enable joint limits.
Definition b2_revolute_joint.h:69
float motorSpeed
The desired motor speed. Usually in radians per second.
Definition b2_revolute_joint.h:81
float upperAngle
The upper angle for the joint limit (radians).
Definition b2_revolute_joint.h:75
bool enableMotor
A flag to enable the joint motor.
Definition b2_revolute_joint.h:78
float maxMotorTorque
Definition b2_revolute_joint.h:85

You can access a revolute joint's angle, speed, and motor torque.

float GetJointAngle() const
Get the current joint angle in radians.
float GetMotorTorque(float inv_dt) const
float GetJointSpeed() const
Get the current joint angle speed in radians per second.

You also update the motor parameters each step.

void SetMotorSpeed(float speed)
Set the motor speed in radians per second.
void SetMaxMotorTorque(float torque)
Set the maximum motor torque, usually in N-m.

Joint motors have some interesting abilities. You can update the joint speed every time step so you can make the joint move back-and-forth like a sine-wave or according to whatever function you want.

// ... Game Loop Begin ...
myJoint->SetMotorSpeed(cosf(0.5f * time));
// ... Game Loop End ...

You can also use joint motors to track a desired joint angle. For example:

// ... Game Loop Begin ...
float angleError = myJoint->GetJointAngle() - angleTarget;
float gain = 0.1f;
myJoint->SetMotorSpeed(-gain * angleError);
// ... Game Loop End ...

Generally your gain parameter should not be too large. Otherwise your joint may become unstable.

Prismatic Joint

A prismatic joint allows for relative translation of two bodies along a specified axis. A prismatic joint prevents relative rotation. Therefore, a prismatic joint has a single degree of freedom.

Prismatic Joint

The prismatic joint definition is similar to the revolute joint description; just substitute translation for angle and force for torque. Using this analogy provides an example prismatic joint definition with a joint limit and a friction motor:

b2Vec2 worldAxis(1.0f, 0.0f);
jointDef.Initialize(myBodyA, myBodyB, myBodyA->GetWorldCenter(), worldAxis);
jointDef.lowerTranslation = -5.0f;
jointDef.upperTranslation = 2.5f;
jointDef.enableLimit = true;
jointDef.maxMotorForce = 1.0f;
jointDef.motorSpeed = 0.0f;
jointDef.enableMotor = true;
Definition b2_prismatic_joint.h:36
float lowerTranslation
The lower translation limit, usually in meters.
Definition b2_prismatic_joint.h:72
bool enableMotor
Enable/disable the joint motor.
Definition b2_prismatic_joint.h:78
float motorSpeed
The desired motor speed in radians per second.
Definition b2_prismatic_joint.h:84
float upperTranslation
The upper translation limit, usually in meters.
Definition b2_prismatic_joint.h:75
bool enableLimit
Enable/disable the joint limit.
Definition b2_prismatic_joint.h:69
void Initialize(b2Body *bodyA, b2Body *bodyB, const b2Vec2 &anchor, const b2Vec2 &axis)
float maxMotorForce
The maximum motor torque, usually in N-m.
Definition b2_prismatic_joint.h:81

The revolute joint has an implicit axis coming out of the screen. The prismatic joint needs an explicit axis parallel to the screen. This axis is fixed in the two bodies and follows their motion.

Like the revolute joint, the prismatic joint translation is zero when the joint is created using Initialize(). So be sure zero is between your lower and upper translation limits.

Using a prismatic joint is similar to using a revolute joint. Here are the relevant member functions:

float PrismaticJoint::GetJointTranslation() const;
float PrismaticJoint::GetJointSpeed() const;
float PrismaticJoint::GetMotorForce() const;
void PrismaticJoint::SetMotorSpeed(float speed);
void PrismaticJoint::SetMotorForce(float force);

Pulley Joint

A pulley is used to create an idealized pulley. The pulley connects two bodies to ground and to each other. As one body goes up, the other goes down. The total length of the pulley rope is conserved according to the initial configuration.

length1 + length2 == constant

You can supply a ratio that simulates a block and tackle. This causes one side of the pulley to extend faster than the other. At the same time the constraint force is smaller on one side than the other. You can use this to create mechanical leverage.

length1 + ratio * length2 == constant

For example, if the ratio is 2, then length1 will vary at twice the rate of length2. Also the force in the rope attached to body1 will have half the constraint force as the rope attached to body2.

Pulley Joint

Pulleys can be troublesome when one side is fully extended. The rope on the other side will have zero length. At this point the constraint equations become singular (bad). You should configure collision shapes to prevent this.

Here is an example pulley definition:

b2Vec2 anchor1 = myBody1->GetWorldCenter();
b2Vec2 anchor2 = myBody2->GetWorldCenter();
b2Vec2 groundAnchor1(p1.x, p1.y + 10.0f);
b2Vec2 groundAnchor2(p2.x, p2.y + 12.0f);
float ratio = 1.0f;
jointDef.Initialize(myBody1, myBody2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);
Definition b2_pulley_joint.h:34
void Initialize(b2Body *bodyA, b2Body *bodyB, const b2Vec2 &groundAnchorA, const b2Vec2 &groundAnchorB, const b2Vec2 &anchorA, const b2Vec2 &anchorB, float ratio)
Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.

Pulley joints provide the current lengths.

float PulleyJoint::GetLengthA() const;
float PulleyJoint::GetLengthB() const;

Gear Joint

If you want to create a sophisticated mechanical contraption you might want to use gears. In principle you can create gears in Box2D by using compound shapes to model gear teeth. This is not very efficient and might be tedious to author. You also have to be careful to line up the gears so the teeth mesh smoothly. Box2D has a simpler method of creating gears: the gear joint.

Gear Joint

The gear joint can only connect revolute and/or prismatic joints.

Like the pulley ratio, you can specify a gear ratio. However, in this case the gear ratio can be negative. Also keep in mind that when one joint is a revolute joint (angular) and the other joint is prismatic (translation), and then the gear ratio will have units of length or one over length.

coordinate1 + ratio * coordinate2 == constant

Here is an example gear joint. The bodies myBodyA and myBodyB are any bodies from the two joints, as long as they are not the same bodies.

b2GearJointDef jointDef;
jointDef.bodyA = myBodyA;
jointDef.bodyB = myBodyB;
jointDef.joint1 = myRevoluteJoint;
jointDef.joint2 = myPrismaticJoint;
jointDef.ratio = 2.0f * b2_pi / myLength;
Definition b2_gear_joint.h:32
b2Joint * joint2
The second revolute/prismatic joint attached to the gear joint.
Definition b2_gear_joint.h:45
float ratio
Definition b2_gear_joint.h:49
b2Joint * joint1
The first revolute/prismatic joint attached to the gear joint.
Definition b2_gear_joint.h:42

Note that the gear joint depends on two other joints. This creates a fragile situation. What happens if those joints are deleted?

Caution: Always delete gear joints before the revolute/prismatic joints on the gears. Otherwise your code will crash in a bad way due to the orphaned joint pointers in the gear joint. You should also delete the gear joint before you delete any of the bodies involved.

Mouse Joint

The mouse joint is used in the testbed to manipulate bodies with the mouse. It attempts to drive a point on a body towards the current position of the cursor. There is no restriction on rotation.

The mouse joint definition has a target point, maximum force, frequency, and damping ratio. The target point initially coincides with the body's anchor point. The maximum force is used to prevent violent reactions when multiple dynamic bodies interact. You can make this as large as you like. The frequency and damping ratio are used to create a spring/damper effect similar to the distance joint.

Many users have tried to adapt the mouse joint for game play. Users often want to achieve precise positioning and instantaneous response. The mouse joint doesn't work very well in that context. You may wish to consider using kinematic bodies instead.

Wheel Joint

The wheel joint restricts a point on bodyB to a line on bodyA. The wheel joint also provides a suspension spring. See b2WheelJoint.h and Car.h for details.

Wheel Joint

Weld Joint

The weld joint attempts to constrain all relative motion between two bodies. See the Cantilever.h in the testbed to see how the weld joint behaves.

It is tempting to use the weld joint to define breakable structures. However, the Box2D solver is iterative so the joints are a bit soft. So chains of bodies connected by weld joints will flex.

Instead it is better to create breakable bodies starting with a single body with multiple fixtures. When the body breaks, you can destroy a fixture and recreate it on a new body. See the Breakable example in the testbed.

Friction Joint

The friction joint is used for top-down friction. The joint provides 2D translational friction and angular friction. See b2FrictionJoint.h and apply_force.cpp for details.

Motor Joint

A motor joint lets you control the motion of a body by specifying target position and rotation offsets. You can set the maximum motor force and torque that will be applied to reach the target position and rotation. If the body is blocked, it will stop and the contact forces will be proportional the maximum motor force and torque. See b2MotorJoint and motor_joint.cpp for details.

Wheel Joint

The wheel joint is designed specifically for vehicles. It provides a translation and rotation. The translation has a spring and damper to simulate the vehicle suspension. The rotation allows the wheel to rotate. You can specify an rotational motor to drive the wheel and to apply braking. See b2WheelJoint, wheel_joint.cpp, and car.cpp for details.

Contacts

Contacts are objects created by Box2D to manage collision between two fixtures. If the fixture has children, such as a chain shape, then a contact exists for each relevant child. There are different kinds of contacts, derived from b2Contact, for managing contact between different kinds of fixtures. For example there is a contact class for managing polygon-polygon collision and another contact class for managing circle-circle collision.

Here is some terminology associated with contacts.

contact point

A contact point is a point where two shapes touch. Box2D approximates contact with a small number of points.

contact normal

A contact normal is a unit vector that points from one shape to another. By convention, the normal points from fixtureA to fixtureB.

contact separation

Separation is the opposite of penetration. Separation is negative when shapes overlap. It is possible that future versions of Box2D will create contact points with positive separation, so you may want to check the sign when contact points are reported.

contact manifold

Contact between two convex polygons may generate up to 2 contact points. Both of these points use the same normal, so they are grouped into a contact manifold, which is an approximation of a continuous region of contact.

normal impulse

The normal force is the force applied at a contact point to prevent the shapes from penetrating. For convenience, Box2D works with impulses. The normal impulse is just the normal force multiplied by the time step.

tangent impulse

The tangent force is generated at a contact point to simulate friction. For convenience, this is stored as an impulse.

contact ids

Box2D tries to re-use the contact force results from a time step as the initial guess for the next time step. Box2D uses contact ids to match contact points across time steps. The ids contain geometric features indices that help to distinguish one contact point from another.

Contacts are created when two fixture's AABBs overlap. Sometimes collision filtering will prevent the creation of contacts. Contacts are destroyed with the AABBs cease to overlap.

So you might gather that there may be contacts created for fixtures that are not touching (just their AABBs). Well, this is correct. It's a "chicken or egg" problem. We don't know if we need a contact object until one is created to analyze the collision. We could delete the contact right away if the shapes are not touching, or we can just wait until the AABBs stop overlapping. Box2D takes the latter approach because it lets the system cache information to improve performance.

Contact Class

As mentioned before, the contact class is created and destroyed by Box2D. Contact objects are not created by the user. However, you are able to access the contact class and interact with it.

You can access the raw contact manifold:

b2Manifold * GetManifold()
Definition b2_contact.h:244
Definition b2_collision.h:100

You can potentially modify the manifold, but this is generally not supported and is for advanced usage.

There is a helper function to get the b2WorldManifold:

void b2Contact::GetWorldManifold(b2WorldManifold* worldManifold) const;
void GetWorldManifold(b2WorldManifold *worldManifold) const
Get the world manifold.
Definition b2_contact.h:254
This is used to compute the current state of a contact manifold.
Definition b2_collision.h:117

This uses the current positions of the bodies to compute world positions of the contact points.

Sensors do not create manifolds, so for them use:

bool touching = sensorContact->IsTouching();

This function also works for non-sensors.

You can get the fixtures from a contact. From those you can get the bodies.

b2Fixture* fixtureA = myContact->GetFixtureA();
b2Body* bodyA = fixtureA->GetBody();
MyActor* actorA = (MyActor*)bodyA->GetUserData().pointer;
b2BodyUserData & GetUserData()
Get the user data pointer that was provided in the body definition.
Definition b2_body.h:733
b2Body * GetBody()
Definition b2_fixture.h:289

You can disable a contact. This only works inside the b2ContactListener::PreSolve event, discussed below.

Accessing Contacts

You can get access to contacts in several ways. You can access the contacts directly on the world and body structures. You can also implement a contact listener.

You can iterate over all contacts in the world:

for (b2Contact* c = myWorld->GetContactList(); c; c = c->GetNext())
{
// process c
}
Definition b2_contact.h:89
b2Contact * GetNext()
Get the next contact in the world's contact list.
Definition b2_contact.h:286
b2Contact * GetContactList()
Definition b2_world.h:287

You can also iterate over all the contacts on a body. These are stored in a graph using a contact edge structure.

for (b2ContactEdge* ce = myBody->GetContactList(); ce; ce = ce->next)
{
b2Contact* c = ce->contact;
// process c
}
b2ContactEdge * GetContactList()
Definition b2_body.h:713
Definition b2_contact.h:78
b2ContactEdge * next
the next contact edge in the body's contact list
Definition b2_contact.h:82

You can also access contacts using the contact listener that is described below.

Caution: Accessing contacts off b2World and b2Body may miss some transient contacts that occur in the middle of the time step. Use b2ContactListener to get the most accurate results.

Contact Listener

You can receive contact data by implementing b2ContactListener. The contact listener supports several events: begin, end, pre-solve, and post-solve.

class MyContactListener : public b2ContactListener
{
public:
void BeginContact(b2Contact* contact)
{ /* handle begin event */ }
void EndContact(b2Contact* contact)
{ /* handle end event */ }
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{ /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{ /* handle post-solve event */ }
};
Definition b2_world_callbacks.h:87
virtual void BeginContact(b2Contact *contact)
Called when two fixtures begin to touch.
Definition b2_world_callbacks.h:92
virtual void PreSolve(b2Contact *contact, const b2Manifold *oldManifold)
Definition b2_world_callbacks.h:107
virtual void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse)
Definition b2_world_callbacks.h:119
virtual void EndContact(b2Contact *contact)
Called when two fixtures cease to touch.
Definition b2_world_callbacks.h:95
Definition b2_world_callbacks.h:71

Caution: Do not keep a reference to the pointers sent to b2ContactListener. Instead make a deep copy of the contact point data into your own buffer. The example below shows one way of doing this.

At run-time you can create an instance of the listener and register it with b2World::SetContactListener. Be sure your listener remains in scope while the world object exists.

Begin Contact Event

This is called when two fixtures begin to overlap. This is called for sensors and non-sensors. This event can only occur inside the time step.

End Contact Event

This is called when two fixtures cease to overlap. This is called for sensors and non-sensors. This may be called when a body is destroyed, so this event can occur outside the time step.

Pre-Solve Event

This is called after collision detection, but before collision resolution. This gives you a chance to disable the contact based on the current configuration. For example, you can implement a one-sided platform using this callback and calling b2Contact::SetEnabled(false). The contact will be re-enabled each time through collision processing, so you will need to disable the contact every time-step. The pre-solve event may be fired multiple times per time step per contact due to continuous collision detection.

void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
if (worldManifold.normal.y < -0.5f)
{
contact->SetEnabled(false);
}
}
void SetEnabled(bool flag)
Definition b2_contact.h:264
b2Vec2 normal
world vector pointing from A to B
Definition b2_collision.h:126

The pre-solve event is also a good place to determine the point state and the approach velocity of collisions.

void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
b2PointState state1[2], state2[2];
b2GetPointStates(state1, state2, oldManifold, contact->GetManifold());
if (state2[0] == b2_addState)
{
const b2Body* bodyA = contact->GetFixtureA()->GetBody();
const b2Body* bodyB = contact->GetFixtureB()->GetBody();
b2Vec2 point = worldManifold.points[0];
float approachVelocity = b2Dot(vB -- vA, worldManifold.normal);
if (approachVelocity > 1.0f)
{
MyPlayCollisionSound();
}
}
}
B2_API void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints], const b2Manifold *manifold1, const b2Manifold *manifold2)
b2PointState
This is used for determining the state of contact points.
Definition b2_collision.h:133
@ b2_addState
point was added in the update
Definition b2_collision.h:135
b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2 &worldPoint) const
Definition b2_body.h:580
b2Fixture * GetFixtureB()
Get fixture B in this contact.
Definition b2_contact.h:306
b2Fixture * GetFixtureA()
Get fixture A in this contact.
Definition b2_contact.h:296
b2Vec2 points[b2_maxManifoldPoints]
world contact point (point of intersection)
Definition b2_collision.h:127

Post-Solve Event

The post solve event is where you can gather collision impulse results. If you don't care about the impulses, you should probably just implement the pre-solve event.

It is tempting to implement game logic that alters the physics world inside a contact callback. For example, you may have a collision that applies damage and try to destroy the associated actor and its rigid body. However, Box2D does not allow you to alter the physics world inside a callback because you might destroy objects that Box2D is currently processing, leading to orphaned pointers.

The recommended practice for processing contact points is to buffer all contact data that you care about and process it after the time step. You should always process the contact points immediately after the time step; otherwise some other client code might alter the physics world, invalidating the contact buffer. When you process the contact buffer you can alter the physics world, but you still need to be careful that you don't orphan pointers stored in the contact point buffer. The testbed has example contact point processing that is safe from orphaned pointers.

This code from the CollisionProcessing test shows how to handle orphaned bodies when processing the contact buffer. Here is an excerpt. Be sure to read the comments in the listing. This code assumes that all contact points have been buffered in the b2ContactPoint array m_points.

// We are going to destroy some bodies according to contact
// points. We must buffer the bodies that should be destroyed
// because they may belong to multiple contact points.
const int32 k_maxNuke = 6;
b2Body* nuke[k_maxNuke];
int32 nukeCount = 0;
// Traverse the contact buffer. Destroy bodies that
// are touching heavier bodies.
for (int32 i = 0; i < m_pointCount; ++i)
{
ContactPoint* point = m_points + i;
b2Body* bodyA = point->fixtureA->GetBody();
b2Body* bodyB = point->FixtureB->GetBody();
float massA = bodyA->GetMass();
float massB = bodyB->GetMass();
if (massA > 0.0f && massB > 0.0f)
{
if (massB > massA)
{
nuke[nukeCount++] = bodyA;
}
else
{
nuke[nukeCount++] = bodyB;
}
if (nukeCount == k_maxNuke)
{
break;
}
}
}
// Sort the nuke array to group duplicates.
std::sort(nuke, nuke + nukeCount);
// Destroy the bodies, skipping duplicates.
int32 i = 0;
while (i < nukeCount)
{
b2Body* b = nuke[i++];
while (i < nukeCount && nuke[i] == b)
{
++i;
}
m_world->DestroyBody(b);
}

Contact Filtering

Often in a game you don't want all objects to collide. For example, you may want to create a door that only certain characters can pass through. This is called contact filtering, because some interactions are filtered out.

Box2D allows you to achieve custom contact filtering by implementing a b2ContactFilter class. This class requires you to implement a ShouldCollide function that receives two b2Shape pointers. Your function returns true if the shapes should collide.

The default implementation of ShouldCollide uses the b2FilterData defined in Chapter 6, Fixtures.

{
const b2Filter& filterA = fixtureA->GetFilterData();
const b2Filter& filterB = fixtureB->GetFilterData();
if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0)
{
return filterA.groupIndex > 0;
}
bool collideA = (filterA.maskBits & filterB.categoryBits) != 0;
bool collideB = (filterA.categoryBits & filterB.maskBits) != 0
bool collide = collideA && collideB;
return collide;
}
virtual bool ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB)
const b2Filter & GetFilterData() const
Get the contact filtering data.
Definition b2_fixture.h:274
This holds contact filtering data.
Definition b2_fixture.h:38
int16 groupIndex
Definition b2_fixture.h:56

At run-time you can create an instance of your contact filter and register it with b2World::SetContactFilter. Make sure your filter stays in scope while the world exists.

MyContactFilter filter;
world->SetContactFilter(&filter);
// filter remains in scope ...

World

The b2World class contains the bodies and joints. It manages all aspects of the simulation and allows for asynchronous queries (like AABB queries and ray-casts). Much of your interactions with Box2D will be with a b2World object.

Creating and Destroying a World

Creating a world is fairly simple. You just need to provide a gravity vector and a Boolean indicating if bodies can sleep. Usually you will create and destroy a world using new and delete.

b2World* myWorld = new b2World(gravity, doSleep);
// ... do stuff ...
delete myWorld;

Using a World

The world class contains factories for creating and destroying bodies and joints. These factories are discussed later in the sections on bodies and joints. There are some other interactions with b2World that I will cover now.

Simulation

The world class is used to drive the simulation. You specify a time step and a velocity and position iteration count. For example:

float timeStep = 1.0f / 60.f;
int32 velocityIterations = 10;
int32 positionIterations = 8;
myWorld->Step(timeStep, velocityIterations, positionIterations);
void Step(float timeStep, int32 velocityIterations, int32 positionIterations)

After the time step you can examine your bodies and joints for information. Most likely you will grab the position off the bodies so that you can update your actors and render them. You can perform the time step anywhere in your game loop, but you should be aware of the order of things. For example, you must create bodies before the time step if you want to get collision results for the new bodies in that frame.

As I discussed above in the HelloWorld tutorial, you should use a fixed time step. By using a larger time step you can improve performance in low frame rate scenarios. But generally you should use a time step no larger than 1/30 seconds. A time step of 1/60 seconds will usually deliver a high quality simulation.

The iteration count controls how many times the constraint solver sweeps over all the contacts and joints in the world. More iteration always yields a better simulation. But don't trade a small time step for a large iteration count. 60Hz and 10 iterations is far better than 30Hz and 20 iterations.

After stepping, you should clear any forces you have applied to your bodies. This is done with the command b2World::ClearForces. This lets you take multiple sub-steps with the same force field.

myWorld->ClearForces();
void ClearForces()

Exploring the World

The world is a container for bodies, contacts, and joints. You can grab the body, contact, and joint lists off the world and iterate over them. For example, this code wakes up all the bodies in the world:

for (b2Body* b = myWorld->GetBodyList(); b; b = b->GetNext())
{
b->SetAwake(true);
}
b2Body * GetNext()
Get the next body in the world's body list.
Definition b2_body.h:723
b2Body * GetBodyList()
Definition b2_world.h:267

Unfortunately real programs can be more complicated. For example, the following code is broken:

for (b2Body* b = myWorld->GetBodyList(); b; b = b->GetNext())
{
GameActor* myActor = (GameActor*)b->GetUserData().pointer;
if (myActor->IsDead())
{
myWorld->DestroyBody(b); // ERROR: now GetNext returns garbage.
}
}

Everything goes ok until a body is destroyed. Once a body is destroyed, its next pointer becomes invalid. So the call to b2Body::GetNext() will return garbage. The solution to this is to copy the next pointer before destroying the body.

b2Body* node = myWorld->GetBodyList();
while (node)
{
b2Body* b = node;
node = node->GetNext();
GameActor* myActor = (GameActor*)b->GetUserData().pointer;
if (myActor->IsDead())
{
myWorld->DestroyBody(b);
}
}

This safely destroys the current body. However, you may want to call a game function that may destroy multiple bodies. In this case you need to be very careful. The solution is application specific, but for convenience I'll show one method of solving the problem.

b2Body* node = myWorld->GetBodyList();
while (node)
{
b2Body* b = node;
node = node->GetNext();
GameActor* myActor = (GameActor*)b->GetUserData().pointer;
if (myActor->IsDead())
{
bool otherBodiesDestroyed = GameCrazyBodyDestroyer(b);
if (otherBodiesDestroyed)
{
node = myWorld->GetBodyList();
}
}
}

Obviously to make this work, GameCrazyBodyDestroyer must be honest about what it has destroyed.

AABB Queries

Sometimes you want to determine all the shapes in a region. The b2World class has a fast log(N) method for this using the broad-phase data structure. You provide an AABB in world coordinates and an implementation of b2QueryCallback. The world calls your class with each fixture whose AABB overlaps the query AABB. Return true to continue the query, otherwise return false. For example, the following code finds all the fixtures that potentially intersect a specified AABB and wakes up all of the associated bodies.

class MyQueryCallback : public b2QueryCallback
{
public:
bool ReportFixture(b2Fixture* fixture)
{
b2Body* body = fixture->GetBody();
body->SetAwake(true);
// Return true to continue the query.
return true;
}
};
// Elsewhere ...
MyQueryCallback callback;
b2AABB aabb;
aabb.lowerBound.Set(-1.0f, -1.0f);
aabb.upperBound.Set(1.0f, 1.0f);
myWorld->Query(&callback, aabb);
Definition b2_world_callbacks.h:129
virtual bool ReportFixture(b2Fixture *fixture)=0
An axis aligned bounding box.
Definition b2_collision.h:169
b2Vec2 lowerBound
the lower vertex
Definition b2_collision.h:220
b2Vec2 upperBound
the upper vertex
Definition b2_collision.h:221

You cannot make any assumptions about the order of the callbacks.

Ray Casts

You can use ray casts to do line-of-sight checks, fire guns, etc. You perform a ray cast by implementing a callback class and providing the start and end points. The world class calls your class with each fixture hit by the ray. Your callback is provided with the fixture, the point of intersection, the unit normal vector, and the fractional distance along the ray. You cannot make any assumptions about the order of the callbacks.

You control the continuation of the ray cast by returning a fraction. Returning a fraction of zero indicates the ray cast should be terminated. A fraction of one indicates the ray cast should continue as if no hit occurred. If you return the fraction from the argument list, the ray will be clipped to the current intersection point. So you can ray cast any shape, ray cast all shapes, or ray cast the closest shape by returning the appropriate fraction.

You may also return of fraction of -1 to filter the fixture. Then the ray cast will proceed as if the fixture does not exist.

Here is an example:

// This class captures the closest hit shape.
class MyRayCastCallback : public b2RayCastCallback
{
public:
MyRayCastCallback()
{
m_fixture = NULL;
}
float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float fraction)
{
m_fixture = fixture;
m_point = point;
m_normal = normal;
m_fraction = fraction;
return fraction;
}
b2Fixture* m_fixture;
b2Vec2 m_point;
b2Vec2 m_normal;
float m_fraction;
};
// Elsewhere ...
MyRayCastCallback callback;
b2Vec2 point1(-1.0f, 0.0f);
b2Vec2 point2(3.0f, 1.0f);
myWorld->RayCast(&callback, point1, point2);
Definition b2_world_callbacks.h:141
virtual float ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction)=0
void RayCast(b2RayCastCallback *callback, const b2Vec2 &point1, const b2Vec2 &point2) const

Caution: Due to round-off errors, ray casts can sneak through small cracks between polygons in your static environment. If this is not acceptable in your application, trying slightly overlapping your polygons.