Box2D C++ tutorials - Collision callbacks

Last edited: July 14 2013

Chinese version -> 中文

Collision callbacks


When bodies move around in the physics scene and bounce off each other, Box2D will handle all the necessary collision detection and response so we don't need to worry about that. But the whole point of making a physics game is that occasionally something should happen in the game as a result of some of the bodies hitting each other eg. when the player touches a monster he should die, or a ball bouncing on the ground should make a sound etc. We need a way to get this information back from the physics engine.

In the drawing your own objects topic, we held a reference to the body in our game entity, and queried it every frame to get the current location of the body to draw it. This was a reasonable thing to do because we will be rendering the body every frame, and the location/rotation are likely to be changing every frame too. But collisions are a bit different - they don't occur every frame, they usually happen much less frequently. So asking the physics engine every time step if a body had collided with something would be like the child in the back seat on a car trip continually saying "are we there yet...?". Almost all the time the answer is no, nothing new is accomplished and if you consider that we would have to do this for every entity in the world, it's inefficient too. It would be far better for the driver to say "just keep quiet and I'll let you know when something happens".

In Box2D we do this with a callback function. This is a function that we write to take some action when two entities collide. We don't know yet what the two entities will be, so they must be passed to the function as a parameter when the collision actually happens. Then we give this function to Box2D as if to say "when a collision occurs, call back to this function".

Callback timing


Collisions between entities in the world will be detected during the b2World::Step() function that we call every time step. As we saw in the topic on worlds, the b2World::Step function advances the simulation, moving all the bodies around and so on. As soon as a collision is detected, the program flow will be given to your callback function to do something, and then goes back to b2World::Step to continue with more processing. It's important to note that since your callback is being called right in the middle of the stepping process, you shouldn't do anything to change the scene right away - there may be more collisions occuring in the same time step. Collision callbacks Setting up a collision callback function is done in the same way as customizing the debug draw. We make a subclass of the b2ContactListener class, which has a bunch of virtual functions that can be overridden. These are the functions we'll use:
1
2
3
4
5
6
  //b2ContactListener
    // Called when two fixtures begin to touch
    virtual void BeginContact(b2Contact* contact);
  
    // Called when two fixtures cease to touch
    virtual void EndContact(b2Contact* contact);
Notice that we can also detect when a collision finishes, so we'll try using both of these a bit later.

Callback information


Once we've set up a subclass for b2ContactListener, we will know when a pair of entites has collided, and do something with them. But hang on... there are no bodies supplied to BeginContact/EndContact, so how can we tell what entities collided? The contact parameter contains all the information we need. The main thing we want to know is what two fixtures were involved in the collision, and we can get these from the contact with these functions:
1
2
3
4
5
6
  //b2Contact
    // Get the first fixture in this contact
    b2Fixture* GetFixtureA();
  
    // Get the second fixture in this contact
    b2Fixture* GetFixtureB();
But still no bodies...? The fixture class has a GetBody() function which we can use to get the body of each fixture. It might be nice if the contact also had a function to get the body directly, but it's not really necessary and I actually find it a good reminder that collisions occur between fixtures, not bodies. To reinforce that point, and to clarify how things are related, this may help: Collision callbacks In this example the dynamic body has four fixtures, one of which has just begun to contact the single fixture of the static body under it. The contact parameter given to BeginContact will return one of these fixtures with GetFixtureA(), and the other with GetFixtureB(). We don't know which is which, so we'll need to check.

Example


For this topic's demonstration, let's use the BeginContact/EndContact collision callbacks to change the color of a ball when it hits something. Start with the scene we had in the drawing your own objects topic, just after we set the smiley face to draw in the correct position. At this point there was only one ball in the scene.

Add a boolean member variable to the Ball class to track whether it is currently hitting something, and functions to call when the physics engine tells us about contacts changing. In the render function, we will set the color depending on the current contact state.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  //Ball class member variable
  bool m_contacting;
  
  //in Ball class constructor
  m_contacting = false;
  
  //Ball class functions
  void startContact() { m_contacting = true; }
  void endContact() { m_contacting = false; }
  
  //in Ball::render
  if ( m_contacting )
    glColor3f(1,0,0);//red
  else
    glColor3f(1,1,1);//white
We will also need to set the user data of the ball body to be our Ball object in the constructor, as in the user data topic:
1
2
  //in Ball constructor
  body->SetUserData( this ); //set this Ball object in the body's user data
Now, we want Box2D to tell us when the contact state changes. Make a subclass of b2ContactListener and implement the BeginContact/EndContact functions as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  class MyContactListener : public b2ContactListener
  {
    void BeginContact(b2Contact* contact) {
  
      //check if fixture A was a ball
      void* bodyUserData = contact->GetFixtureA()->GetBody()->GetUserData();
      if ( bodyUserData )
        static_cast<Ball*>( bodyUserData )->startContact();
  
      //check if fixture B was a ball
      bodyUserData = contact->GetFixtureB()->GetBody()->GetUserData();
      if ( bodyUserData )
        static_cast<Ball*>( bodyUserData )->startContact();
  
    }
  
    void EndContact(b2Contact* contact) {
  
      //check if fixture A was a ball
      void* bodyUserData = contact->GetFixtureA()->GetBody()->GetUserData();
      if ( bodyUserData )
        static_cast<Ball*>( bodyUserData )->endContact();
  
      //check if fixture B was a ball
      bodyUserData = contact->GetFixtureB()->GetBody()->GetUserData();
      if ( bodyUserData )
        static_cast<Ball*>( bodyUserData )->endContact();
  
    }
  };
That seems like a lot of code but if you take a look it's mostly just repeated. First we check if the body of the fixture has any user data. If it does it must be a ball, if it doesn't it must be one of the wall fixtures of the static body. For a simple scene like this it's easy to say make this kind of deduction, but for a real game you would need to have something more sophisticated. Anyway, once we've decided that the fixture belongs to a Ball entity, we cast the user data pointer to a Ball object and call the appropriate state change function. Note that we need to do this for both fixtures A and B because either of them could be a ball.

Now to tell the Box2D world to use these functions for collisions, we use the SetContactListener function. This function takes a pointer to a b2ContactListener object, so we'll need to have an instance of the class to point to. This is easily done by just declaring a variable of your new class at global scope.
1
2
3
4
5
  //at global scope
  MyContactListener myContactListenerInstance;
  
  //in FooTest constructor
  m_world->SetContactListener(&myContactListenerInstance);
That's it. Now when the ball touches a wall it should appear red, and when it moves away again it should return to white. Collision callbacks This seems to work ok, especially for a simple scene like this one, but there is a problem with this method. Grab the ball with the mouse and pull it into a corner so that it is touching two walls at the same time. Now slide it along one wall, out of the corner. You will find that the ball returns to white, even though it is still touching a wall! What's happening here is that when the ball moves out of the corner, an EndContact occurs for the wall that is no longer touching, so the m_contacting boolean variable of the ball gets set to false. Fortunately that's easy to fix - instead of using a boolean to store a simple on/off state, we just need to store an integer and increment/decrement it to count the number of other fixtures currently being touched.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  //replace old boolean variable m_contacting in Ball class
  int m_numContacts;
  
  //in Ball constructor
  m_numContacts = 0;
  
  //new implementation for contact state change
  void startContact() { m_numContacts++; }
  void endContact() { m_numContacts--; }
  
  //altered rendering code
  if ( m_numContacts > 0 )
    glColor3f(1,0,0);//red
  else
    glColor3f(1,1,1);//white
Now try the corner contact test again, and the problem should be fixed. Adding a whole bunch of balls and bashing them around can be a good way to check if you've got this right. Notice that when things are in a pile bouncing around, the contact state can flicker on and off at a very quick rate. There's nothing wrong with that, but if you are running game logic from these state changes, keep this in mind. Collision callbacks How about one more example to demonstrate how we can use the relationship between the contacting objects. So far all we've done is look at whether a ball touched something, now we will look at what it touched. Let's set up a scene where only one ball is red, and when it hits another ball the red will pass onto the other ball, kind of like playing tag where one ball is 'it'.

Add a boolean variable to the Ball class to track whether it is currently 'it', and set up a function at global scope that takes two balls and switches their 'it' status.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  //in Ball class
  bool m_imIt;
  
  //in Ball constructor
  m_imIt = false;
  
  //in Ball::render
  if ( m_imIt )
    glColor3f(1,0,0);//red
  else
    glColor3f(1,1,1);//white
  
  //in global scope
  void handleContact( Ball* b1, Ball* b2 ) {
    bool temp = b1->m_imIt;
    b1->m_imIt = b2->m_imIt;
    b2->m_imIt = temp;
  }
This time in the contact listener callback, we only need to implement a BeginContact function:
1
2
3
4
5
6
7
8
  void BeginContact(b2Contact* contact) {
      //check if both fixtures were balls
      void* bodyAUserData = contact->GetFixtureA()->GetBody()->GetUserData();
      void* bodyBUserData = contact->GetFixtureB()->GetBody()->GetUserData();
      if ( bodyAUserData && bodyBUserData )
          handleContact( static_cast<Ball*>( bodyAUserData ),
                         static_cast<Ball*>( bodyBUserData ) );
  }
Finally, we need to make one of the balls 'it' to begin with:
1
2
  //at end of FooTest constructor
  balls[0]->m_imIt = true;
In order to more clearly see whats happening you might want to turn off gravity so the balls can spread out a bit more, and give the balls a higher restitution so they keep bouncing for longer without needing to push them around manually. Collision callbacks

Real scenarios


This was a pretty basic demonstration, but the idea can be expanded on to handle more interesting logic in your game, for example when a player touches a monster, etc. In a more complex scene with different kinds of entities colliding, you would want to set something in the fixture user data from which you can tell what kind of entity it represents. One possibility is instead of directly putting the Ball pointer in the user data, you could set an object of a generic parent class, of which Ball and every other entity are subclasses. This parent class would have a virtual function to return what type of entity it is, something like this:
1
2
3
4
5
6
7
8
9
  class Entity
  {
     virtual int getEntityType() = 0;
  };
  
  class Ball : public Entity
  {
     int getEntityType() { return ET_BALL; }
  }
In the collision callback you could then use this to check what kind of entities are colliding and cast them appropriately.

Another way might be to use dynamic casting. To be honest I haven't really come up with a method that I like much, because somewhere along the way they all seem to end up in bloated routines with a lot of if/else checks to get the right case. If anyone has a nice clean way to handle this, let us know!

Update: As Marcos points out in the comments, C++ also has the 'typeid' method for determining what class a pointer is. See also http://en.wikipedia.org/wiki/Typeid.