1
\$\begingroup\$

TiledMapEditor supports the placement of text-labels nowdays, but I'm not able to load the text in a String.

I've tried iterating through the MapProperties of a MapObject, but the text is not part of them.

for(MapObject object : map.getLayers().get("id of textlabels").getObjects())
{
  MapProperties props = object.getProperties();    
  Iterator<String> valueIta = props.getValues();
  while (valueIta.hasNext()){ 
   String currentValue = String.valueOf(valueIta.next());
   sout(currentValue); //prints id,x,y,width,height
  }
}

I also looked at the usages of the MapObject interface if there is anything like a ''TextLabelMapObject'' (like RectangularMapObject), but found none.

Looking in my .tmx file I can find this description of my object, but I have no idea how to parse that text attribute.

<object id="1594" x="1512.5" y="7170.5" width="83" height="19">
 <text wrap="1">Hello World</text>
</object>

My idea was to iterate through the layer's objects, parsing the current object to a TextLabelMapObject (which not exists) that implements a method getText() that returns the String inside <text>.

I'm a missing something here?

Any hint is greatly appreciated.


EDIT:

So, as @bornander suggested I've created the following classes:

public class CustomMapLoader extends CustomBaseTmxMapLoader<TmxMapLoader.Parameters> {

https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/maps/tiled/TmxMapLoader.java

public abstract class CustomBaseTmxMapLoader<P extends AssetLoaderParameters<TiledMap>> extends AsynchronousAssetLoader<TiledMap, P> {

//added to loadObject(TiledMap map, MapLayer layer, XmlReader.Element element) 
...
} else if ((child = element.getChildByName("ellipse")) != null) {
   object = new EllipseMapObject(x, flipY ? y - height : y, width, height);
} else if ((child = element.getChildByName("text")) != null) {
   object = new TextLabelMapObject(child.getText(), x, flipY ? y - height : y, width, height); //this line will create a text object with position data
}

https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/maps/tiled/BaseTmxMapLoader.java

so that I can load my map like this:

gameWorld = new CustomMapLoader().load(Constants.MAP);

Ans here is the TextLabelMapObject

import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.math.Rectangle;

public class TextLabelMapObject  extends MapObject {

    private Rectangle rectangle;
    private String text;

    /** @return rectangle shape */
    public Rectangle getRectangle () {
        return rectangle;
    }
    /** @return text as string */
    public String getText () {
        return text;
    }

    /** Creates a rectangle object which lower left corner is at (0, 0) with width=1 and height=1 */
    public TextLabelMapObject () {
        this("", 0.0f, 0.0f, 1.0f, 1.0f);
    }

    /** Creates a {@link Rectangle} object with the given X and Y coordinates along with a given width and height.
     *
     * @param x X coordinate
     * @param y Y coordinate
     * @param width Width of the {@link Rectangle} to be created.
     * @param height Height of the {@link Rectangle} to be created. */
    public TextLabelMapObject (String text, float x, float y, float width, float height) {
        super();
        rectangle = new Rectangle(x, y, width, height);
        this.text = text;
    }
}

In my B2DWorldCreator I do

for (MapObject object : GameEngine.mapLoader.gameWorld.getLayers().get(Constants.LAYER_TEXTLABELS).getObjects()) {
  Rectangle rect = ((TextLabelMapObject) object).getRectangle();
  String text = ((TextLabelMapObject) object).getText();
  infoList.add(new InfoSign(main, text, rect.getX()/ Constants.PPM, rect.getY() / Constants.PPM));
}

with the InfoSign (thats later going to be a Sprite) being

public class InfoSign  {
    private String text;
    private float x;
    private float y;

    public InfoSign(String text, float x, float y){
        this.main = main;
        this.text = text;
        this.x = x;
        this.y = y;
    }


    public void draw(Batch batch){
        main.assets.infoFont.draw(batch, text , x,y);
    }
}

Lightheart Ed

Thanks a bunch!

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If you're using the TmxMapLoader that comes with libGDX then you won't get a TextLabelMapObject for your Texts, this is because that implementation does not cater for Text.

TmxMapLoader derives from BaseTmxMapLoader which reads objects in object layers using the loadObject method, which looks something like this:

protected void loadObject (TiledMap map, MapObjects objects, Element element, float heightInPixels) {
    if (element.getName().equals("object")) {
        MapObject object = null;

        float scaleX = convertObjectToTileSpace ? 1.0f / mapTileWidth : 1.0f;
        float scaleY = convertObjectToTileSpace ? 1.0f / mapTileHeight : 1.0f;

        float x = element.getFloatAttribute("x", 0) * scaleX;
        float y = (flipY ? (heightInPixels - element.getFloatAttribute("y", 0)) : element.getFloatAttribute("y", 0)) * scaleY;

        float width = element.getFloatAttribute("width", 0) * scaleX;
        float height = element.getFloatAttribute("height", 0) * scaleY;

        if (element.getChildCount() > 0) {
            Element child = null;
            if ((child = element.getChildByName("polygon")) != null) {
                String[] points = child.getAttribute("points").split(" ");
                float[] vertices = new float[points.length * 2];
                for (int i = 0; i < points.length; i++) {
                    String[] point = points[i].split(",");
                    vertices[i * 2] = Float.parseFloat(point[0]) * scaleX;
                    vertices[i * 2 + 1] = Float.parseFloat(point[1]) * scaleY * (flipY ? -1 : 1);
                }
                Polygon polygon = new Polygon(vertices);
                polygon.setPosition(x, y);
                object = new PolygonMapObject(polygon);
            } else if ((child = element.getChildByName("polyline")) != null) {
                String[] points = child.getAttribute("points").split(" ");
                float[] vertices = new float[points.length * 2];
                for (int i = 0; i < points.length; i++) {
                    String[] point = points[i].split(",");
                    vertices[i * 2] = Float.parseFloat(point[0]) * scaleX;
                    vertices[i * 2 + 1] = Float.parseFloat(point[1]) * scaleY * (flipY ? -1 : 1);
                }
                Polyline polyline = new Polyline(vertices);
                polyline.setPosition(x, y);
                object = new PolylineMapObject(polyline);
            } else if ((child = element.getChildByName("ellipse")) != null) {
                object = new EllipseMapObject(x, flipY ? y - height : y, width, height);
            }
        }
        if (object == null) {
            String gid = null;
            if ((gid = element.getAttribute("gid", null)) != null) {
                int id = (int)Long.parseLong(gid);
                boolean flipHorizontally = ((id & FLAG_FLIP_HORIZONTALLY) != 0);
                boolean flipVertically = ((id & FLAG_FLIP_VERTICALLY) != 0);

                TiledMapTile tile = map.getTileSets().getTile(id & ~MASK_CLEAR);
                TiledMapTileMapObject tiledMapTileMapObject = new TiledMapTileMapObject(tile, flipHorizontally, flipVertically);
                TextureRegion textureRegion = tiledMapTileMapObject.getTextureRegion();
                tiledMapTileMapObject.getProperties().put("gid", id);
                tiledMapTileMapObject.setX(x);
                tiledMapTileMapObject.setY(flipY ? y : y - height);
                float objectWidth = element.getFloatAttribute("width", textureRegion.getRegionWidth());
                float objectHeight = element.getFloatAttribute("height", textureRegion.getRegionHeight());
                tiledMapTileMapObject.setScaleX(scaleX * (objectWidth / textureRegion.getRegionWidth()));
                tiledMapTileMapObject.setScaleY(scaleY * (objectHeight / textureRegion.getRegionHeight()));
                tiledMapTileMapObject.setRotation(element.getFloatAttribute("rotation", 0));
                object = tiledMapTileMapObject;
            } else {
                object = new RectangleMapObject(x, flipY ? y - height : y, width, height);
            }
        }
        object.setName(element.getAttribute("name", null));
        String rotation = element.getAttribute("rotation", null);
        if (rotation != null) {
            object.getProperties().put("rotation", Float.parseFloat(rotation));
        }
        String type = element.getAttribute("type", null);
        if (type != null) {
            object.getProperties().put("type", type);
        }
        int id = element.getIntAttribute("id", 0);
        if (id != 0) {
            object.getProperties().put("id", id);
        }
        object.getProperties().put("x", x);

        if (object instanceof TiledMapTileMapObject) {
            object.getProperties().put("y", y);
        } else {
            object.getProperties().put("y", (flipY ? y - height : y));
        }
        object.getProperties().put("width", width);
        object.getProperties().put("height", height);
        object.setVisible(element.getIntAttribute("visible", 1) == 1);
        Element properties = element.getChildByName("properties");
        if (properties != null) {
            loadProperties(object.getProperties(), properties);
        }
        objects.add(object);
    }
}

As you can see, the method tries to load polygons, polylines, ellipses and texture regions, and if it's not one of those it falls back to assuming the object is a rectangle.

One way to solve this would be to create a new version of TmxMapLoader and have it derive from a new version of BaseTmxMapLoader and in that class extend the loadObject method to handle texts, possibly by adding a class called TextMapObject and modify the new version BaseTmxMapLoader to include something like this:

} else if ((child = element.getChildByName("text")) != null) {
    object = new TextMapObject(x, flipY ? y - height : y, width, height, child.getText());
}

BaseTmxMapLoader on GitHub

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .