Tag Archives: impulse

Controlling character movement with Box2D

So – the next challenge is a nice way to move the player’s character with Box2D. I would like the user to touch a spot in the game, and have the character try to move to that location (noting that the place on the screen may be different if the world scrolls).  The character should move at constant speed while on the ground, and follow normal physics while falling. I also like the little bounce the character gets with Box2D on landing on the ground after a fall.

For now, I am just representing the character as a ball, but ignoring its rotation for drawing.  I realise now this representation actually matters, since a ball rolls along the ground differently to how a box slides. If I need more realism, I expect to replace the ball representation with a small ball for the legs and a custom shape for the body, with a (wheel?) joint holding the two together, like a car.

Here are some alternatives:

  1. Apply an impulse to the character every update (1/60th of a second)
    I was using code like this in GameElement:

    -(void) applyImpulseToVelocity:(Point3D)targetVelocity {
        b2Vec2 vel = self.body->GetLinearVelocity();
        float dvx = targetVelocity.x - vel.x;
        float dvy = targetVelocity.y - vel.y;
        float mass = self.body->GetMass();
        self.body->ApplyLinearImpulse( b2Vec2(mass * dvx,mass * dvy),
                   self.body->GetWorldCenter() );
    }

    The target velocity is basically proportional to the distance between the character’s current location and the touch location (modified so that the character can’t fly).
    The problem is, this doesn’t look realistic at all: when the character is falling, gravity has very little effect on it – it just drifts down slowly.

  2. Use a mouse joint
    This is inspired by Ray Wenderlich’s breakout tutorial. According to the Box2D manual, a mouse joint attempts to drive a point on the body to the target. It required a bit of a rewrite of GameElement and GameModel, because the mouse joint needs to know the world and the ground body, which I was hoping to isolate from the GameElement.
    Quite an interesting effect: the character speeds to the touched location and then spins around it at a small radius as if on a rope.  Gravity does act on it at this point, if not while it speeds along. Not the game play I was after.
    Also, the manual advises “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.” Hmmm… kinematic bodies, the manual says, do not respond to forces, and do not collide with static or other kinematic bodies. You normally move them by setting their velocity.  I don’t think I’ll pursue this option: I definitely want forces to apply in some situations, and want them to collide with static bodies.

  3. Apply an impulse to the character every update (1/60th of a second), but only when in contact with the ground or a platform
    This approach most closely matches the description of what I want. It felt like a hack but in fact, humans can only propel themselves when on the ground, so it is (somewhat) realistic. With the contact listener already working, this was not too hard to implement. The main work was changing the ground to a GameElement (it was previously just a part of the GameModel), and setting user data for the ground, platforms and ladders as well as animals. The contact listener needs the user data to send a begin/end contact message to the object.
    This is virtually the same as option 1 above, but is only applied if a flag is set on the character’s GameElement saying that it is in contact with the ground, a platform or a ladder.  In fact all these are subclasses of the Platform class, so the test is very simple.
    Great news – this works pretty well!

Nonetheless I expect this is not the end of the story…