Detecting object collision

The basic set of features that the Box2D library offers might be sufficient for simple games. However, sometimes you need to know when objects collide. For instance, in action games you usually shoot things and need to know what object was hit by your projectile.

Fortunately, the Box2D library offers an interface for collision detection in the form of callbacks. Using callbacks in the Lua language might not be straightforward because of the Lua language design. LuaBox2D contains a simple interface to set up callback functions for collision detection.

This recipe shows you how to define your own callback function in the Lua environment and how to process events when collision occurs.

Getting ready

First of all, you'll need a World object, some static walls, and at least one dynamic object. You can use the createWall and createBullet functions from the Setting up bullets recipe.

How to do it…

Object collision can be detected with the ContactListener object. It provides a simple interface to a set of callback functions that are called in various stages of collision. To be precise, there are four callback functions you can override: beginContact, endContact, preSolve, and postSolve.

First, you'll have to create the ContactListener object. After this step, you can set one of these callback functions to point to your function in the Lua environment.

The last step consists of setting a current contact listener in the World object to your new ContactListener object. The following sample code sets a new contact listener with callback functions:

local contact_listener = box2d.ContactListener()
contact_listener.beginContact = function(contact)
end
contact_listener.endContact = function(contact)
end
contact_listener.preSolve = function(contact, oldManifold)
end
contact_listener.postSolve = function(contact, contactImpulse)
end
world.contactListener = contactListener

How it works…

The Box2D library allows you to observe and analyze various stages of the object collision test. An important thing to remember is that callback functions are called during the time step. All the objects are in a locked state during this stage and you shouldn't change the objects' properties. This would lead to computational errors and instability. Now, because all the callback functions are defined in the Lua environment, it's fairly easy to postpone such changes on objects until the current time step is complete.

The beginContact callback

This function is called before fixtures begin to touch. Although this function gives you only one parameter in the form of a Contact object, it offers you everything you'll need.

The Contact object consists of many properties, but most notable among them are manifold, isTouching, enabled, fixtureA, fixtureB, and next.

The manifold contains a list of contact points between two fixtures. A property isTouching tells you if these two fixtures are actually touching. You can disable further collision testing for these two fixtures by setting the enabled property to false. Both fixtures are available from the fixtureA and fixtureB properties. You can access respective body objects for each of these two fixtures, and it's often used in conjunction with user data to get information about which game objects have collided.

Don't forget that there might be more than one contact. You can get the next Contact object with the next property.

The endContact callback

This function is used when two objects cease to collide. Similarly, as with the beginContact callback function, you've got only one parameter—the Contact object.

The preSolve callback

The Box2D library calls this function whenever contacts are updated. This gives you a chance to inspect a contact just before it's used in the solver. This function gives you two parameters: the Contact object and the oldManifold object. This way, you detect changes in contact points.

This function is rarely used in games.

The postSolve callback

This function lets you inspect resulting contacts after the solver has finished its job. This is particularly useful if you want to inspect contact impulses. Contact impulses can help you determine the outcome of the collision response after the solver has processed all the contacts.

The PostSolve callback accepts two parameters—the Contact object and the ContactImpulse object, which contains a list of contact impulses.

Do note that Box2D might call the preSolve and postSolve callbacks many times even when there's only one collision. This is a result of approximation in the solver.

There's more…

The following sample code shows how to use ContactListener with user data to know exactly which game objects did collide:

local wall = createWall(Vec2(0,0), Vec2(5,1))
local bullet = createBullet(Vec2(0, 5), 1)
wall.userData = {
  name = 'Wall'
}
bullet.userData = {
  name = 'Bullet'
}

local contact_listener = box2d.ContactListener()
contact_listener.beginContact = function(contact)
  local bodyA = contact.fixtureA.body
  local bodyB = contact.fixtureB.body
  local dataA = bodyA.userData
  local dataB = bodyB.userData
  if type(dataA)=="table" and type(dataB)=="table" then
    print(dataA.name, 'has collided with', dataB.name)
  end
end

As you can see, the userData property can refer to any Lua value. This value is bound to the Body object and if you destroy the Body object, you'll lose the reference to the userData value as well. Therefore, it's always better to store the object data somewhere in your Lua environment and use userData only to store references in it.

You can use userData on the Fixture object as well to store fixture-specific information.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.65.130