Box2D C++ tutorials - User data

Last edited: July 14 2013

Chinese version -> 中文

User data


In the previous topic, we saw how useful it was to have a reference to a physics object from a game entity class. Sometimes it is also useful to have the opposite - a pointer from a physics object to an entity in your game. In Box2D this is called user data, and it is just a pointer which you can set to hold some information that may be useful for you. The following classes have this functionality:
  • b2Body
  • b2Fixture
  • b2Joint
Box2D doesn't care what this information is, and it doesn't do anything with it. It just holds it and tells you what it is when you ask. The above classes all have the following functions to do this:
1
2
3
  //in b2Body, b2Fixture, b2Joint
  void SetUserData(void* data);
  void* GetUserData();
Setting something in the user data for bodies and fixtures will be extremely useful in upcoming topics, so let's try a simple example to get the hang of it. In this example we will implement exactly what we just did in the previous topic (getting the render position and velocity of the game entity) but we will do it without storing a pointer to the physics body in the Ball class. Instead, we will store a pointer to a Ball object in each physics body, and after each time step we will update class member variables of the ball object with the new information. Note that this is not really a practical way to approach the task, it's just for demonstration.

In order to access the user data for each physics body, we'll also need to try out a method for looping across all bodies in the scene. Instead of a loop in the proper sense, this is done by a linked list of bodies. We can use b2World::GetBodyList() to get the first element in the list to start iterating on.

So, start with the source code from the previous topic and modify it a bit. Firstly, take out all references to the m_body member variable of the Ball class, and alter its constructor to set the Ball class itself in the user data of the created physics body:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    Ball(b2World* world, float radius) {
      m_radius = radius;
  
      //set up dynamic body
      b2BodyDef myBodyDef;
      myBodyDef.type = b2_dynamicBody;
      myBodyDef.position.Set(0, 20);    
      b2Body* body = world->CreateBody(&myBodyDef);
      
      //set this Ball object in the body's user data
      body->SetUserData( this ); 
  
      //add circle fixture
      b2CircleShape circleShape;
      circleShape.m_p.Set(0, 0); 
      circleShape.m_radius = m_radius;
      b2FixtureDef myFixtureDef;
      myFixtureDef.shape = &circleShape;
      myFixtureDef.density = 1; 
      body->CreateFixture(&myFixtureDef); 
    }
Next, add some member variables to the Ball class to hold the physics information we'll need:
1
2
3
    b2Vec2 m_position;
    float m_angle;
    b2Vec2 m_linearVelocity;
... and replace the locations where calls to m_body->GetPosition(), m_body->GetAngle() and m_body->GetLinearVelocity() were previously used, to simply use these new member variables. For example, the section in renderAtBodyPosition to position the smiley face will now be:
1
2
  glTranslatef( m_position.x, m_position.y, 0 );
  glRotatef( m_angle * RADTODEG, 0, 0, 1 );
Running this as is, you'll see we are back at the initial stage of the last topic where the all the balls are rendered at (0,0) with no rotation: User data So to fix this in the Step() function, after the Test::Step() call and before we do our own rendering, we need to update the ball object positions from their physics bodies. To do this, iterate over all bodies in the world, get the necessary position/angle/velocity values and set them in the Ball object contained in the user data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    b2Body* b = m_world->GetBodyList();//get start of list
    while ( b != NULL ) {
  
      //obtain Ball pointer from user data
      Ball* ball = static_cast<Ball*>( b->GetUserData() );
      if ( ball != NULL ) {
        ball->m_position = b->GetPosition();
        ball->m_angle = b->GetAngle();
        ball->m_linearVelocity = b->GetLinearVelocity();
      }
  
      //continue to next body
      b = b->GetNext();
    }
This should get the behaviour back to how it was before. Once again, this is not a recommended way of linking your game entities to a physics body for the purposes of rendering, it's just to demonstrate the user data functionality. For rendering, the previous method was much easier to implement and manage. Driving the information updates from the physics body doesn't help us much, because we are continuously rendering all the time regardless of what's happening in the physics simulation.

So what kind of practical uses does this user data feature have then? The usefulness comes when we want to be informed about something happening in the physics engine that we can't easily predict, such as when fixtures collide, what they collided with and what the reaction forces will be, etc. Other useful things include ray-casting or AABB queries to find intersected fixtures (and get the related game entity from the user data in the fixture).


Setting complex user data


Since the user data accepts a void pointer, anything that can be cast to a void pointer can be set in the user data. This could be a single number, an existing object pointer (as above) or a pointer that you make specifically to hold some complex information relating to the physics object. Here are some examples:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  //setting and retrieving an integer
  int myInt = 123;
  body->SetUserData( (void*)myInt );
  ...later...
  int udInt = (int)body->GetUserData();
  
  
  //setting and retrieving a complex structure
  struct bodyUserData {
      int entityType;
      float health;
      float stunnedTimeout;
  };
  bodyUserData* myStruct = new bodyUserData;
  myStruct->health = 4;//set structure contents as necessary
  body->SetUserData(myStruct);
  ...later...
  bodyUserData* udStruct = (bodyUserData*)body->GetUserData();
In each case, you should set the same type of value for the user data. For example, if you give a fixture an integer user data as in the first example here, then all fixtures should be given an integer for their user data. If you were to give some fixtures an integer and other fixtures a structure, when retrieving the user data from a fixture with GetUserData() it would be difficult to tell whether you are dealing with an integer or a structure (the collision callbacks topic will explain why you cannot always know which fixture or body you are dealing with when a collision is detected).

For most applications it is very handy to set a structure with multiple members in the user data. Box2D does not delete any of your user data objects when you destroy a body/fixture/joint, so you must remember to clean these up yourself when they are no longer needed.

In the structure example above the members of the structure are fixed, which gives a limited set of attributes to use, and not much flexibility if you have different entity types in your game. See the section of the collision callbacks topic titled 'real scenarios' for an example of using class inheritance for a more practical approach for when you have many types of entities.