Tiled map loader for SFML and box2D

A couple of posts back I covered how I use the tmx map parser for collision detection. In that I speculated that it ought to be possible to parse the MapObject geometry data into physics bodies for box2D, which I've since decided to follow up. I know box2D is not for everyone, so I've written a BodyCreator class and added it to the source on github, which is optional to include. If you want to use the map loader without box2D simply leave out the tmx2box2d source files from your project (if you try including them without linking against box2D you'll get errors). In this post I'm going to assume you have at least some basic knowledge and/or experience of box2D but if all else fails there's always the manual.

    I've tried to keep the interface as simple as possible, so the class contains a collection of static functions of which five are public, most notably:

b2Body* BodyCreator::Add(const MapObject& object, b2World* world, bool dynamic);

This function takes a MapObject as a parameter from which the box2D body will be created, a pointer to the physics world to which to add it, and an optional boolean variable which states whether or not the created body will be dynamic, which is false by default. The function also returns a pointer to the newly created box2D body which you can then use to process physics objects in any way you wish. Static and dynamic bodies are supported, but kinematic bodies are not, although I'll probably add support at some point. All MapObject shape types are supported; Rectangles, Circles/Ellipses, Polygons and Chain shapes. Non-convex shapes (which are not supported by box2D) are broken down into smaller convex shapes when necessary. The code for that is based on this article which details an ActionScript class written by Antoan Angelov. I've tested each case as best I can although there may be some edge cases which throw an error, in which case I'd be happy to hear about them / try to fix them.
    The four other public functions are actually sat in the tmx namespace and are utilities for converting world coordinates. Box2D not only uses real world units, metres, kilograms, seconds, it also uses inverted Y coordinates compared to SFML so it made sense to wrap the conversion in these functions. It also takes care of the fact that box2D has its own 2D vector class, by converting the data from one type to another.

    b2Vec2 SfToBoxVec(const sf::Vector2f& vec);
    sf::Vector2f BoxToSfVec(const b2Vec2& vec);
    float SfToBoxFloat(float val);
    float BoxToSfFloat(float val);

The names, I think, are self-explanatory, and the functions should be used wherever you need to convert data from one world space to another. The scale factor which defines SFML units per metre is declared at the top of tmx2box2d.cpp and is set to 100 by default. Adjusting this will affect the outcome of the conversion functions. To save on writing  lengthy passages of code in this post I've also added an example to the source on github. It takes a simple tmx file and creates a selection of static and dynamic bodies from the objects contained within. The map file looks like this:

The green objects are stored on a layer called 'Static' and the white objects on a layer called 'Dynamic'. The example code then uses the separate layers to decide which kind of object to create. Here's a short video of it in action:


As always comments are always welcome below, or on the github page.

Popular Posts