I realise this is five months old, but still relevant. The way I do it is by creating a Physics
utility class for my unit calculation and conversion:
public final class Physics {
public static final float PIXELS_PER_UNIT = 32f;
private Physics() {}
// UNIT CALCULATION AND CONVERSION:
public static float toUnits(float pixels) {
return pixels / PIXELS_PER_UNIT;
}
public static Vector toUnits(Vector2 pixels) {
return new Vector2(toUnits(pixels.x), toUnits(pixels.y));
}
public static float toPixels(float units) {
return units * PIXELS_PER_UNIT;
}
public static Vector2 toPixels(Vector2 units) {
return new Vector2(toPixels(units.x), toPixels(units.y));
}
}
I then create a ShapeFactory
class which converts MapObject
s into shapes of the same type:
public final class ShapeFactory {
private ShapeFactory() {}
public static PolygonShape getRectangle(RectangleMapObject rectangleObject) {
return getRectangle(rectangleObject.getRectangle());
}
public static PolygonShape getRectangle(Rectangle rectangle) {
PolygonShape polygon = new PolygonShape();
Vector2 size = new Vector2(
Physics.toUnits(rectangle.x + rectangle.width * 0.5f),
Physics.toUnits(rectangle.y + rectangle.height * 0.5f)
);
polygon.setAsBox(
Physics.toUnits(rectangle.width * 0.5f),
Physics.toUnits(rectangle.height * 0.5f),
size,
0.0f
);
return polygon;
}
public static CircleShape getCircle(CircleMapObject circleObject) {
return getCircle(circleObject.getCircle());
}
public static CircleShape getCircle(Circle circle) {
CircleShape circleShape = new CircleShape();
circleShape.setRadius(Physics.toUnits(circle.radius));
circleShape.setPosition(new Vector2(Physics.toUnits(circle.x), Physics.toUnits(circle.y)));
return circleShape;
}
public static PolygonShape getPolygon(PolygonMapObject polygonObject) {
return getPolygon(polygonObject.getPolygon());
}
public static PolygonShape getPolygon(Polygon polygon) {
PolygonShape polygonShape = new PolygonShape();
float[] vertices = polygon.getTransformedVertices();
float[] worldVertices = new float[vertices.length];
for (int i = 0; i < vertices.length; ++i) {
worldVertices[i] = Physics.toUnits(vertices[i]);
}
polygonShape.set(worldVertices);
return polygonShape;
}
public static ChainShape getPolyline(PolylineMapObject polylineObject) {
return getPolyline(polylineObject.getPolyline());
}
public static ChainShape getPolyline(Polyline polyline) {
ChainShape chain = new ChainShape();
float[] vertices = polyline.getTransformedVertices();
Vector2[] worldVertices = new Vector2[vertices.length / 2];
for (int i = 0; i < vertices.length / 2; ++i) {
worldVertices[i] = new Vector2();
worldVertices[i].x = Physics.toUnits(vertices[i * 2]);
worldVertices[i].y = Physics.toUnits(vertices[i * 2 + 1]);
}
chain.createChain(worldVertices);
return chain;
}
}
Because I use Ashley (an Entity Component System created for libGDX), I create a system which converts all MapObject
s from my map's Collision layer into bodies:
public class TiledMapCollisionSystem extends EntitySystem {
public TiledMapCollisionSystem() {
MapObjects objects = LevelManager.getActiveMap().getLayers().get(Layers.COLLISION).getObjects();
for (MapObject object : objects) {
if (object instanceof TextureMapObject) {
continue;
}
Shape shape;
if (object instanceof RectangleMapObject) {
shape = ShapeFactory.getRectangle((RectangleMapObject) object);
} else if (object instanceof PolygonMapObject) {
shape = ShapeFactory.getPolygon((PolygonMapObject) object);
} else if (object instanceof PolylineMapObject) {
shape = ShapeFactory.getPolyline((PolylineMapObject) object);
} else if (object instanceof CircleMapObject) {
shape = ShapeFactory.getCircle((CircleMapObject) object);
} else {
continue;
}
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
Body body = WorldManager.world.createBody(bodyDef);
body.createFixture(shape, 1);
shape.dispose();
}
}
}
Note that the map is already loaded and the Box2D world is already created before the system is instantiated. Layers.COLLISION
is a simple constant String "Collision". You don't need to create a System if you aren't using Ashley, as you can simply create another utility class which does the same thing.