Maintaining Fixture Lists for Box2D Bodies

If you search through general Box2D help or tutorials, you’ll realize that there are references to many functions that are not available in the Moai.  This is because everything we can access in Lua has to be exposed in the C++ source code, and they only did this for certain important functions.  Some examples of missing functions are ray casting or getting a list of fixtures for a given body.  Since Moai is open source, we can download the code, edit it and then have your own custom build that lets you access this extra functionality.  However, this sounds like a lot of work, and there is an easier way.

Since getting a list of fixtures is conceptually pretty simple, we can actually implement it ourselves in Lua.  Whenever someone calls the add* functions on MoaiBox2DBody (like addCircle() or addRect()), we want to keep track of the result and store it in a list.  Then we need to create a new function getFixtureList() that returns this list.  Using the same technique as I showed last time to override the dofile() function, we can override the add* calls to keep track of the fixture list.  It looks something like this:

function CustomizeBox2DBody(body)
  body.fixtures = {}
  body.oldAddCircle = body.addCircle
  function body:addCircle(...)
    local fixture = self:oldAddCircle(...)
    CustomizeBox2DFixture(fixture)
    table.insert(self.fixtures, fixture)
    return fixture
  end

  --do the same for the other add*() functions here ...

  function body:getFixtureList()
    return self.fixtures
  end
end

We add a new entry to the body table called “fixtures”. We keep a reference to the existing definition of addCircle() naming it oldAddCircle(), and then define a new addCircle() function that calls the old one, and saves the result that fixtures list. Then we return the fixture, so the caller doesn’t know that the implementation changed. We have to do this for every fixture creation function we use.

Then we have the actual getFixtureList() function to call, which just returns the fixtures property.

Note that in order for this fixture list to work, we also need to remove the fixture whenever MOAIBox2DFixture:destroy() is called. We can override it like this:

function CustomizeBox2DFixture(fixture)
  fixture.oldDestroy = fixture.destroy
  function fixture:destroy()
    local body = fixture:getBody()
    for i,v in ipairs(body.fixtures) do
      if v == fixture then
        table.remove(body.fixtures, i)
        break
      end
    end
    fixture:oldDestroy()  
  end
end

I don’t think this is the most efficient way to do this, but assuming there are only every a few fixtures on a body, it shouldn’t be a big deal. Whenever destroy() is called, we first remove it from the body’s fixtures table.

Finally, we have to remember to call the CustomizeBox2DBody() function on every body we create:

local body = box2dworld:addBody(type)
CustomizeBox2DBody(body)
--now we can call body:getFixtureList()!

Remember this only works because the functionality we are trying to achieve is pretty simple. If you want to access the ray casting functionality in Moai, it would be a lot easier and more efficient to expose the Box2D version of it through C++.

Leave a Reply