libGDX Tiled Box2D - object layers

25th March 2021, 16:00:00

Intro

This is the object layer sub page of the example. If you are new to the series, click here to access the main page first.

Map setup

  1. Create an object layer and give it a name, e.g. “Collisions”.
  2. Draw your collisions with the object tools. Hold ctrl to snap to corners.

Comparison

Object layer

Tile collisions

As you see, the object layer version creates a lot less rectangles, therefore is faster to parse and might work better. The tile collision version however is automated and you don’t need to care about creating collisions shapes.

Implementation

Now for the fun part!

Let’s iterate through the objects.

1
2
3
4
MapObjects collisions = map.getLayers().get("Collisions").getObjects();
for (int i = 0; i < collisions.getCount(); i++)
{
MapObject mapObject = collisions.get(i);

Then we’ll need to get the actual shape in the map object.
This is done by checking which class it actually is (then converting to it), and calling .getXXX() on it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (mapObject instanceof RectangleMapObject)
{
RectangleMapObject rectangleObject = (RectangleMapObject) mapObject;
Rectangle rectangle = rectangleObject.getRectangle();
}
else if (mapObject instanceof EllipseMapObject)
{
EllipseMapObject circleMapObject = (EllipseMapObject) mapObject;
Ellipse ellipse = circleMapObject.getEllipse();
}
else if (mapObject instanceof PolygonMapObject)
{
PolygonMapObject polygonMapObject = (PolygonMapObject) mapObject;
Polygon polygon = polygonMapObject.getPolygon();
}

Box2d body creation

Now inside each if …

Rectangle

In Tiled every object’s x/y coordinates are bottom left. Sadly Box2D uses center coordinates. Therefore we’ll need to add half the width/height to the position.

1
2
if (mapObject instanceof RectangleMapObject) {
BodyDef bodyDef = getBodyDef(rectangle.getX() + rectangle.getWidth() / 2f, rectangle.getY() + rectangle.getHeight() / 2f);

.setAsBox() accepts half width/height parameters, therefore we’ll need to half the width/height.

1
2
3
4
5
Body body = world.createBody(bodyDef);
PolygonShape polygonShape = new PolygonShape();
polygonShape.setAsBox(rectangle.getWidth() / 2f, rectangle.getHeight() / 2f);
body.createFixture(polygonShape, 0.0f);
polygonShape.dispose();

Circle

Here we have another little problem, Tiled allows ellipses, Box2D only circles. Therefore we’ll need to check if the ellipse is actually a circle.

Additionally ellipse coordinates are already centered, so we don’t have that problem here.

1
2
else if (mapObject instanceof EllipseMapObject) {
BodyDef bodyDef = getBodyDef(ellipse.x, ellipse.y);

Then we’ll check if it’s a circle, if not we’ll exit.

1
2
if (ellipse.width != ellipse.height)
throw new IllegalArgumentException("Only circles are allowed.");
1
2
3
4
5
Body body = world.createBody(bodyDef);
CircleShape circleShape = new CircleShape();
circleShape.setRadius(ellipse.width / 2f);
body.createFixture(circleShape, 0.0f);
circleShape.dispose();

Polygon

Polygons are probably the most easiest. However you can only load polygons with a maximum of 8 points.

1
2
3
4
5
6
7
8
else if (mapObject instanceof PolygonMapObject) {
BodyDef bodyDef = getBodyDef(polygon.getX(), polygon.getY());

Body body = world.createBody(bodyDef);
PolygonShape polygonShape = new PolygonShape();
polygonShape.set(polygon.getVertices());
body.createFixture(polygonShape, 0.0f);
polygonShape.dispose();

That’s pretty much everything you need!

Repo

https://github.com/lyze237-examples/LibgdxTiledBox2DExample