How can I add click listeners for the tiles from tiled map so that when you select a tile with the mouse it becomes highlighted?
1 Answers
That's not supported directly by libGDX as the TiledMap stuff is only for rendering.
You could easily create a Stage
though, which will act as some kind of overlay-input-layer for your TiledMap. Just create an Actor
for each tile which has the same size as position as that tile. Then you are able to add EventListener
s to those actors to be able to recognize things like clicks on those actors.
Those actors should keep a reference to their "origin", namely TiledMapTileLayer.Cell
. So you are able to go back from the actor to the cell anytime when processing those events.
The following shows how you might do it:
This Actor is responsible to catch the events and keep the information about the tile it's based on:
public class TiledMapActor extends Actor {
private TiledMap tiledMap;
private TiledMapTileLayer tiledLayer;
private TiledMapTileLayer.Cell cell;
public TiledMapActor(TiledMap tiledMap, TiledMapTileLayer tiledLayer, TiledMapTileLayer.Cell cell) {
this.tiledMap = tiledMap;
this.tiledLayer = tiledLayer;
this.cell = cell;
}
}
This little listener can be attached to one of those actors and will do any kind of logic:
public class TiledMapClickListener extends ClickListener {
private TiledMapActor actor;
public TiledMapClickListener(TiledMapActor actor) {
this.actor = actor;
}
@Override
public void clicked(InputEvent event, float x, float y) {
System.out.println(actor.cell + " has been clicked.");
}
}
The following class actually creates the actors from a given map and wires them to the listeners:
public class TiledMapStage extends Stage {
private TiledMap tiledMap;
public TiledMapStage(TiledMap tiledMap) {
this.tiledMap = tiledMap;
for (MapLayer layer : tiledMap.getLayers()) {
TiledMapTileLayer tiledLayer = (TiledMapTileLayer)layer;
createActorsForLayer(tiledLayer);
}
}
private void createActorsForLayer(TiledMapTileLayer tiledLayer) {
for (int x = 0; x < tiledLayer.getWidth(); x++) {
for (int y = 0; y < tiledLayer.getHeight(); y++) {
TiledMapTileLayer.Cell cell = tiledLayer.getCell(x, y);
TiledMapActor actor = new TiledMapActor(tiledMap, tiledLayer, cell);
actor.setBounds(x * tiledLayer.getTileWidth(), y * tiledLayer.getTileHeight(), tiledLayer.getTileWidth(),
tiledLayer.getTileHeight());
addActor(actor);
EventListener eventListener = new TiledMapClickListener(actor);
actor.addListener(eventListener);
}
}
}
}
Now the TiledMapStage
will do all work for you. All you need to do is the following:
Stage stage = new TiledMapStage(tiledMap);
Gdx.input.setInputProcessor(stage);
And in render(...) you need to call stage.act()
. Remember to use the same Viewport
for the stage as you are using to render the TiledMap. Otherwise the input and your rendered map won't be aligned.

- 19,520
- 5
- 61
- 76
-
I cant manage to set the camera for the stage so that the input layer would be aligned with the tile layers... How can I solve the problem? – Andrew Jun 06 '14 at 18:57
-
1Usually you'd do that via `stage.getViewport().setCamera(camera)` where `camera` is the one that you use to draw the TiledMap with. – noone Jun 06 '14 at 19:47
-
@noone I apologize for bumping you out of the nice 10101 rep score you had, but the `stage.getViewport().setCamera(camera)` is exactly what I've missed and caused me a large amount of time going back and forth. You rock. – James Skemp Apr 11 '15 at 00:23
-
Adding to this for those using an OrthogonalTiledMapRenderer with a scale, you will want to adjust the `actor.setBounds...` line to be `actor.setBounds(x, y , 1, 1);`. In my case, I had a scale of 32f set for my 10x10 tilemap, and using the logic in the example, would always get the 0,0 tile. I'm absolutely new to libGDX so I'm totally open to hearing other / better ways to accomplish this. – Levi Rosol Dec 26 '15 at 02:20
-
How efficient is this, performance-wise? If I have a huge map, is there going to be a noticeable performance difference from creating a ton of actors vs just checking the mouse coordinates directly? – Mar 02 '16 at 14:59
-
1@Caketray It's semi-efficient I'd say. If you check the coordinates of each tile yourself, it is pretty much the same what `Stage` does, when it checks the `Actor`s. However, if you are able to directly calculate the matching tile, based on the coordinates, this would be much more efficient and independent of the map size. – noone Mar 03 '16 at 12:30