Box2D C++ tutorials - Bodies

Last edited: July 14 2013

Chinese version -> 中文

Bodies


Bodies are the fundamental objects in the physics scene, but they are not what you actually see bouncing around and colliding with each other. Sound confusing? Hold on, I'll explain.

You can think of a body as the properties of an object that you cannot see (draw) or touch (collide with). These invisible properties are:
  • mass - how heavy it is
  • velocity - how fast and which direction it's moving
  • rotational inertia - how much effort it takes to start or stop spinning
  • angular velocity - how fast and which way it's rotating
  • location - where it is
  • angle - which way it is facing
Even if you know all of these characteristics of an object, you still don't know what it looks like or how it will react when it collides with another object. To define the size and shape of an object we need to use fixtures, which are the subject of the next topic in this series, so for now we will just use a simple box and cover the details of fixtures later. Let's create a body and try setting some basic properties of it to see how they work.

There are three types of body available: static, dynamic and kinematic. The first two of these should be readily understandable, while the last one is probably not so intuitive. I'll cover the details a little further along. First we will make a dynamic body so we can see something moving around the scene, and we can try setting the velocity etc. for it.

Creating a body


Bodies are made by first setting up a definition, and then using this to create the body object itself. This can be handy if you want to make many bodies which are all the same, or very similar. In the constructor of the FooTest class, add the following code to set up a definition for a body:
1
2
3
4
  b2BodyDef myBodyDef;
  myBodyDef.type = b2_dynamicBody; //this will be a dynamic body
  myBodyDef.position.Set(0, 20); //set the starting position
  myBodyDef.angle = 0; //set the starting angle
That's enough to define a basic body definition. Remember a body does not have any size, shape, so we don't define those here. You may be wondering why it has no mass yet - the usual way of providing a mass for a body is by adding fixtures to it, which is coming up in the next step. Now, use this definition to create the actual body instance:
1
  b2Body* dynamicBody = m_world->CreateBody(&myBodyDef);
Here, we are using the m_world member variable of the parent class Test which is a b2World object. The world object is like the boss of everything in Box2D, it handles the creation and deletion of physics objects. We will take a look at the properties of the world in more detail a bit later. Ok, so now we have a body, but as we noted at the beginning of this page, a body is basically invisible, so if you build and run the program like this, there is nothing to see yet (if you turn on the 'Center of Masses' display you can see the position of the body falling though).

To give a body its size, shape, and other tangible characteristics, we add fixtures to it. Also, the default behaviour is that adding fixtures will affect the mass of the body too. A body can have many fixtures attached to it, each fixture added will affect the total mass of the body. For now, let's add one simple fixture to this body, a square, and look a bit further at fixtures in the next topic.
1
2
3
4
5
6
7
  b2PolygonShape boxShape;
  boxShape.SetAsBox(1,1);
  
  b2FixtureDef boxFixtureDef;
  boxFixtureDef.shape = &boxShape;
  boxFixtureDef.density = 1;
  dynamicBody->CreateFixture(&boxFixtureDef);
Although you can ignore most of the above section for now, notice the line referring to density. The area of the fixture is multiplied by the density of the fixture to calculate its mass, and this becomes the mass of the body.

Now when you run the program you should see a small box falling downwards - if you are quick enough you can catch it with the mouse cursor and throw it around, press restart (R key) if you lose it off the screen. Since this is a dynamic body it is able to move and rotate, and is affected by gravity. Body

Setting body properties


Now let's see what happens when we set some of the properties mentioned at the beginning of this topic. For example, change the starting position and angle:
1
  dynamicBody->SetTransform( b2Vec2( 10, 20 ), 1 );
This will make the body start 10 units further to the right, 20 units higher, and rotated 1 radian counter-clockwise. Box2D uses radians for angle measurements, so if you are like me and more used to thinking in angles, you could do something like this:
1
2
3
4
  #define DEGTORAD 0.0174532925199432957f
  #define RADTODEG 57.295779513082320876f
  
  dynamicBody->SetTransform( b2Vec2( 10, 20 ), 45 * DEGTORAD ); //45 degrees counter-clockwise
We can also set the linear velocity and angular velocity of the body:
1
2
  dynamicBody->SetLinearVelocity( b2Vec2( -5, 5 ) ); //moving up and left 5 units per second
  dynamicBody->SetAngularVelocity( -90 * DEGTORAD ); //90 degrees per second clockwise

Static bodies


Now let's see what a static body does. Since we already have definitions for a body and a fixture, we can re-use them and just change the necessary features:
1
2
3
4
  myBodyDef.type = b2_staticBody; //this will be a static body
  myBodyDef.position.Set(0, 10); //slightly lower position
  b2Body* staticBody = m_world->CreateBody(&myBodyDef); //add body to world
  staticBody->CreateFixture(&boxFixtureDef); //add fixture to body
Notice here we didn't need to change the square fixture at all. Running the program now you should see another box in the scene, but this time it will not move. You will also find that while you can successfully use setTransform as above to change the location of this static body, setting the velocity properties for a static body will have no effect. Body

Kinematic bodies


Lastly, let's see what a 'kinematic' body is all about. As we have seen so far, dynamic bodies move and static bodies don't. When a static body and a dynamic body collide, the static body always 'wins' and holds its ground, and the dynamic body will retreat as necessary so that the two are not overlapping. A kinematic body is very similar to a static body in that when it collides with a dynamic body it always holds its ground and forces the dynamic body to retreat out of the way. The difference is that a kinematic body can move.

Try setting up a kinematic body like this:
1
2
3
4
5
6
7
  myBodyDef.type = b2_kinematicBody; //this will be a kinematic body
  myBodyDef.position.Set(-18, 11); // start from left side, slightly above the static body
  b2Body* kinematicBody = m_world->CreateBody(&myBodyDef); //add body to world
  kinematicBody->CreateFixture(&boxFixtureDef); //add fixture to body
  
  kinematicBody->SetLinearVelocity( b2Vec2( 1, 0 ) ); //move right 1 unit per second
  kinematicBody->SetAngularVelocity( 360 * DEGTORAD ); //1 turn per second counter-clockwise
Body The new body in the scene can move and rotate, but is not affected by gravity, and not affected when the dynamic body collides with it. Notice that when it touches the static body, there is no interaction between them.

For most games, dynamic bodies are used for the player and other actors in the scene, and static bodies are used for walls, floors and so on. Kinematic bodies came about to fill the need for a body which can move and rotate but doesn't get bumped around by the dynamic bodies. A perfect example is a moving platform in a platform game - it should always stay on its track no matter how it is jumped on or collided with.

Getting body properties


Often you will want to know where a body is or how fast it is moving, rotating etc. This is pretty easy so lets give it a try. For this we will need to access the body variables in the Step() function, so we'll need to make them a class member variable instead of just declaring them inside the constructor:
1
2
  //in the class itself, not inside the constructor!
  b2Body* dynamicBody;
... and change the declarations where the bodies are created to use these class member variables. Now inside the Step() function, we can do this to print some information for a body:
1
2
3
4
5
6
7
8
9
10
  b2Vec2 pos = dynamicBody->GetPosition();
  float angle = dynamicBody->GetAngle();
  b2Vec2 vel = dynamicBody->GetLinearVelocity();
  float angularVel = dynamicBody->GetAngularVelocity();
  m_debugDraw.DrawString(5, m_textLine, 
    "Position:%.3f,%.3f Angle:%.3f", pos.x, pos.y, angle * RADTODEG);
  m_textLine += 15;
  m_debugDraw.DrawString(5, m_textLine, 
    "Velocity:%.3f,%.3f Angular velocity:%.3f", vel.x, vel.y, angularVel * RADTODEG);
  m_textLine += 15;
Body You can feed the GetPosition() and GetAngle() results back into SetTransform so that no change is made. For example, the following code will cause no change to a body's movement at all:
1
  body->SetTransform( body->GetPosition(), body->GetAngle() );
Of course that's not very useful, but if you wanted to change only the position, or only the angle, you can do it in this way.

Iterating over the bodies in the world


If you want to look at all the bodies in the world, you can do it as below. The function GetBodyList() returns the first element in a linked list of bodies.
1
2
3
4
  for ( b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
  {
      //do something with the body 'b'
  }

Cleaning up


When you're done with a body, you can remove it from the scene by calling the world's DestroyBody function:
1
  m_world->DestroyBody(dynamicBody);
When a body is destroyed like this, it takes care of deleting all the fixtures and joints attached to it. Remember not to use the deleted body pointer after this!


Next: Fixtures