[LibGDX] TiledMapTile IDs or something else to determine...

Hi,
So I am trying to get my characters to respect to the tiledmap I created, and detect the collision when it happens.

I thought I could make a collision layer, mark the tiles I want for collision and then read them in the code. I don’t know if this is doable or a good way of doing it, but that is how I thought I will achieve this if I can.

I created a map with Tiled software. Here is my map and the pictures I used for it: https://dl.dropboxusercontent.com/u/19432607/TiledMap.zip

I thought I could read the tile info from map.tmx and get the collision tile with its id. But it is encoded with Base64 :slight_smile: So, that failed.
I tried to get all of the tiles, then list their ids etc. But that failed too as the ids are something like this: com.badlogic.gdx.maps.tiled.tiles.StaticTiledMapTile@69acd952

I realized that I could use XML to create map.tmx. I did it and my collision tile has an id: 121. But I cannot use it. Because libgdx does not support XML with maps, or I couldn’t get it to do so.

What is the direction I should be heading now?

What’s your code to load the .tmx?

Hi,
For now, it is very simple. The whole class is here: http://www.java-gaming.org/?action=pastebin&id=577
I call loadMap from my WorldRendering class. Then render it with an OrthogonalTiledMapRenderer.

I used to render it layer by layer. But I couldn’t see any benefits to that (Except for, characters could hide behind trees etc) for now.

In the beginning, I just loaded and rendered it in the WorldRendering class, but when I started to try map collision detection, I decided to move it to another class. I thought I could modify it without messing with other stuff.

I made a class called Wall and I set a tileproperty for my walltile to “solid” in my tilemap editor. Then when I read the .tmx file I made a new Wall object and stored it in a list. That way I had a list of bounding boxes to test collision against.

Hi Axeman,
I think I am not as experienced as you are with tile maps. Can you explain it in more detail or if you don’t mind, can you share the code?
I felt like I needed to change something in the editor but I was not sure.

Ough… that’s not the tile id :wink: It’s the output of the tile with the default toString() method. (what’s after the @ is the heap space location of the instance, if I remember that correctly… try out [icode]System.out.println(new Object());[/icode] to get what I mean.

Moving on. This is you would get the ID of a Tile with libgdx:


// First, we need to get the layer in which you create the tiles.
// In this case I assume you call the layer 'collision' layer in Tiled.
private int computeCollisionLayerIndex(TiledMap map) {
    for (int i = 0; i < map.getLayers().getCount(); i++) {
        // This is used to get the layer with the name "collision" from all layers
        // (The layers name in Tiled)
        if (map.getLayers().get(i).getName().equalsIgnoreCase("collision")) {
            return i;
        }
    }
    return -1;
}

// Now we surround getting the layer from the index
// with a little error handling:
public void whatevername(TiledMap map) {
    int collisionLayerIndex = computeCollisionLayerIndex(map);
    if (collisionLayerIndex != -1) {
        MapLayer layer = map.getLayers().get(collisionLayerIndex
        if (layer instanceof TiledMapTileLayer) {
            getCollisionTilesFrom((TiledMapTileLayer) layer);
        } else throw some kind of error
    } else throw some kind of error
}

// And finally we print the ID of each tile in the layer
// I don't know what you would do with the tiles in the end,
// and since I don't know what tile ID's your tiles have,
// I simply print them.
public void getCollisionTilesFrom(TiledMapTileLayer layer) {
    for (int x = 0; x < layer.getWidth(); x++) {
        for (int y = 0; y < layer.getHeight(); y++) {
            TiledMapTileLayer.Cell cell = layer.getCell(x, y);
            if (cell == null) continue; // There is no cell
            if (cell.getTile() == null) continue; // No tile inside cell
            
            System.out.println(cell.getTile().getID()); // Get the ID.
        }
    }
}

matheus23, I thank you.
I think I’ll have to look into your code a little bit and get back to you if I have questions :slight_smile: In the first look, what makes your code complex to me looks like your error handling codes. So it should be fine.

Honestly, I am not sure what to do with tile ids :slight_smile: I think I was going to do this:
1- Get the collision layer in which I only have two or three tiles filled. These tiles are my collision layers, the player won’t pass through these.
2- Get the id of the tiles I filled in the collision layer in the Tiled software. I’m assuming this will give me some clues as to where these tiles are in the map.
3- Draw rectangles around these tiles so that I become able to use them as normal rectangles in the map.
4- Perform basic rectangle based collision detection.

Does that seem doable to you guys?

Yes. Definitely possible. Did that myself already with RuinsOfRevenge (see signature)… (though I did it somehow different)

The error handling (i. e. “[icode]throw some kind of error[/icode]”) is pseudocode, It’s not actual code, it was some kind of comment…

You could run my code over the tiles you have in your collision layer and look what ID’s they return. Or simply allow each tile in the collision layer to be a collidable. Finally with the x and y position in the loop, you have the position of the tiles and you finally create Rectangle’s out of them.

Thanks man. I’ll look into it and get back this thread about whether I did it or failed.

I was using Tiled as my tilemap editor. I right clicked my tile representing my wall and set tile properties for that specific tile. Notice I´m not setting the property for the layer or anything in the map: I´m using the specific tile. That way all tiles on the map have the same property. I had a property name “checkCollision”, since different tiles reacted differently to collision. Walls were solid and Conveyor belt sped up the entity checking for collision.

Anyway, in my levelloader I wrote something like this:


int tileHeight = 32;
int tileWidth = 32;
String type = "";
Array<Wall> wallTiles  = new Array<Wall>();
		
for(int layers = 0; layers < map.layers.size(); layers++) {
	for(int y = 0; y < map.height; y++)
		for(int x = 0; x < map.width; x++) {
				
		        type = (map.getTileProperty(map.layers.get(layers).tiles[y][x], "CheckCollision"));
			     if(type != null && type.equals("solid")) {
				     Wall wall = new Wall(x * tileWidth, y * tileHeight, tileHeight, tileWidth);
                 wallTiles.add(wall); 
               }}

Note that this code is based on the old TiledMap API in LibGDX, but I figured it might be easier to read in code…

So basically I read the tilemap and check each tile if it has the property name “CheckCollision”. If it returns the property value “solid” I create a new wall with position and tilesize and store it in the list.

Thank you guys. I finally can detect my collision tiles and draw a rectangle around them.

It seems I should read a lot about tiled maps. Because I was not aware of a cell concept. I mean, I thought a tile is also a cell. So, if you guys direct me to a nice beginner documentation, it would be appreciated.

So I modified matheus23’s code, because I already knew what layer and what name my collision layer had. This is what I have:

public void getCollisionTilesFrom() {
		TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(0);
		for (int x = 0; x < layer.getWidth(); x++) {
			for (int y = 0; y < layer.getHeight(); y++) {
				TiledMapTileLayer.Cell cell = layer.getCell(x, y);
				if (cell == null) {
					continue; // There is no cell
				}
				if (cell.getTile() == null) {
					continue; // No tile inside cell
				}
				// Get the ID
				System.out.println(cell.getTile().getId() + " x:" + x + " y:" + y);
			}
		}
	}

Then I thought assuming I want to draw a rectangle around one of these tiles, the position would be: x * tilewidth, y * tileheight, and the other parameters would be tilewidth, and tileheight So; Rectangle rect = new Rectangle(x *tilewidth, y * tileheight, tilewidth, tileheight);
That is right.

So, in a loop;

rend = new ShapeRenderer(); 
rend.begin(ShapeType.Filled); 
rend.rect(x * tileWidth, y * tileHeight, tileWidth, tileHeight); 
rend.end();

If anyone read, most of my problems I mentioned here (Deleted now) are gone.
I was trying to make camera movement and rectangle positions work as it should since this morning. It turns out I forgot to set projection matrix for the boxes. That was why it did not draw rectangles out of the viewport. It was also why the rectangles moved as the camera moved.

I am using the same tile editor and decided to use the object layer to draw all sorts of objects including walls, when loading a map I load in all the objects then use this when moving, I did this as I don’t want to mark each tile as passable.

This is a cut down version of my can_move function as there are other types of objects. So I am saying if the next move creates a collision don’t allow it, so you stop a pixel or so away from a wall.

	
public boolean can_move(float move_x, float move_y){
		boolean next_move_allowed = true;
		
		ArrayList<Collision> objArray = renderer.objArray;
		Rectangle player = hero.getHitbox();
		player.y = player.y + move_y;
		player.x = player.x + move_x;
				
		for (Collision obj : objArray) {		
			if (obj.getBounds().overlaps(player) && obj.isSolid()){
				next_move_allowed = false;		
			}	
		}	
		
		return next_move_allowed;
	}

Part of the code for loading my objects in:


for (TiledObjectGroup group : this.getWorld().getMap().objectGroups) {
			for (TiledObject object : group.objects) {
				//System.out.println("Load: " + object.name + " type: " + object.type);
                        }
}

Under this I check what type of object it is and load it, also I flip the Y position as the co-ords between the map objects and screen are different.