Sensors in Box2D (or how to make a basic platformer)

After playing around with Box2D, I tried to make a simple platformer. After setting up a static body to represent the ground, and a dynamic box to represent the character, I ran into a problem – how do you know whether your character can jump? Essentially you need to know whether he is standing on the ground. If he is on the ground, and the player presses some button, you can do your jumping physics (set a velocity or apply a force/impulse). One way to approach this problem is to use sensors. Sensors are fixtures that don’t affect the result of an actual collision, but can detect when a collision would have occurred. If you place a sensor under your character’s main area, you can detect when there is something right under him. Here is a diagram:

Now when the sensor starts colliding with something else, you can set a flag to start accepting jumps.  When it stops colliding with something, you can set the flag to stop accepting jumps.  Here’s some sample code to set this up:

local dynamicBody = self:addBody( MOAIBox2DBody.DYNAMIC )
dynamicBody:setTransform( 0, 60 )

local rectFixture = dynamicBody:addRect( -20, 20, 20, -20 )

local sensorFixture = dynamicBody:addRect( -20, -21, 20, -25 )

The key is setSensor(true) – which marks sensorFixture as a sensor.  Even though it is part of the body, the actual collisions will occur as if it wasn’t.  However, now you can hook into a collision event handler like this:

sensorFixture:setCollisionHandler(handleCollision, MOAIBox2DArbiter.BEGIN + MOAIBox2DArbiter.END)

Note that you need to subscribe to the beginning and end of collisions.  Then define a collision handler like this:

function handleCollision(phase, a, b, arbiter)
  if phase == MOAIBox2DArbiter.BEGIN then
    character.canJump = true
  elseif phase == MOAIBox2DArbiter.END then
    character.canJump = false

Finally, just check the canJump flag when you handle user input!

Leave a Reply