[Libgdx]Tilemap rendering issue

I’m trying to render a tilemap with 3 different layers.

  • terrain (grass, dirt etc)
  • objects (bottom part of trees, chest, houses, items etc)
  • top (top part of trees, top part of houses)

Rendering is done in this order :

  • draw terrain layer
  • draw objects layer
  • draw character sprites
  • draw top layer

Everything works well only if my character sprites are 1 tile in height.
Problem is some characters are bigger and the render becomes messy, especially
with trees.
Here is what I mean (the red rectangle is the character) :

http://image.noelshack.com/fichiers/2016/24/1466340217-tm.png

It’s a custom tilemap system I made to suit my own needs. Each cell is represented in an array of int (tile id).
It’s quite large (10,000x10,000) and some cells are frequently replaced (animated tiles, dynamic tiles),

I don’t know how to fix this without using a derivated Sprite class for cells with z-sorting, but performances are awful.
What are my other options ?

Won’t it Also be a problem that you character never gets rendered behind objects?

Is there any reason that you aren’t rendering all your objects from the top of the screen to the bottom of the screen? I’m assuming that you render each sprite individually and are not batching them.

There are 2 distinct entities in world. Cells (or tiles) which are stored as int in 3 arrays (each array is a layer) and a list of sprites for characters.
The tilemap contains 3 layers (terrain, object, top) that are rendered one after the other and the sprites/characters are drawn between the object layer and the top layer.
That’s how I manage to draw characters behind some objects. For instance, a big tree is in 2 parts : the bottom part, drawn in the object layer and the top part (leaves) drawn in the top layer.
But as I said, it works only if the sprite size isn’t too big on the Y axis (1 tile in size, or 16 pixels).
I’m trying to find another solution to fix this issue without killing performances, the tilemap can contain up to 300 million tiles (10,000x10,000x3 layers), so using class objects for cells isn’t an option.

Anyone ?
I need help please.

I’m not am expert by any stretch, but if z-ordering is not an option, what I would try would be to sort things so that the map gets rendered row by row from top to bottom. This way, it’s the y value that determines what gets drawn first.

Do you have the tree placed directly in tiled, or are you just picking the locations to spawn trees?

Again, not expert, just trying to be helpful.

Normally I wouldn’t say this, but if you are batching the sprites then you should probably rethink your design on this (I would redo it anyway). Having separate tile maps just for sorting seems like a bad idea (most of the space is empty).

You didn’t say one way or another how you were rendering, but either way there shouldn’t be any z sorting, when you render the objects (or grabbing them for a batch) you just start with the top of the screen and work your way down. You don’t even need to cut your object sprites in half.

In fact, I’m already drawing tiles rows by rows from top to bottom. The problem isn’t about tile order but the rendering order between tiles and characters, and both are complete different things in my code. Tiles are integers stored in arrays and characters are class objects (Sprite). I used a simple layer system (so I could draw characters between layers) thinking it would be enough for my needs, but it isn’t.
There’s probably a better way to structure the whole thing but I don’t know how.

The renderer code looks like that :


renderLayer(TERRAIN_LAYER);
renderLayer(OBJECT_LAYER);

// characters drawn between object and top
for(Sprite entity : entities) {
	// render characters
	[...]
}

renderLayer(TOP_LAYER);

And the renderLayer method :

public void renderLayer(int layer) {	
	int[][] tiles = getLayer(layer);
	for(int y = getMaxY(); y >= 0; y--) {
		for(int x = getMaxX(); x >= 0; x--) {
			drawTile(tiles[x][y]);
		}
	}
}

The renderLayer method is a bit more complex as I use a Mesh for each chunk of the map but the result is the same.
As explained above, it works very well if my characters don’t exceed one tile on the Y-axis, otherwise I get a rendering issue. For instance, if I put a tree which is made of two tiles (trunk in the object layer and leaves in the top layer), a part of the character sprite will be drawn behind the leaves, whereas it is “in front” of the tree.

I’m sorry if it’s not very clear, english isn’t my native language, I’m trying to do my best but thanks for your answers :slight_smile:

I still think we are talking past eachother so sorry about all the questions. What is rendered in renderLayer(OBJECT_LAYER); tiles or objects?

Can the player ever get rendered behind the bottom of the tree?

No problem :slight_smile:
Every layers contain tiles only, nothing else. It’s called object layer because it contains objects like chests in a tile form.

int[][] terrainLayer;
int[][] objectLayer;
int[][] topLayer;

[...]

int tile = objectLayer[x][y];
if(tile == CHEST_TILE_ID) {
	// logic
}

The player is never rendered behind this layer, that’s why I added another one on top of it.

you can’t render objects that way, because you need to sort/order them along with all other game objects (players, bullets, monsters, etc)

so trees should be objects (think of them as idle-monsters that don’t do anything)

and then you sort all your objects from top-of-screen to bottom-of-screen and render them in that order

Have you tried putting all entities in a list and then order them based on y coordinates?

There is no other way that to add them as sprite entities in the scene ?
Trees, rocks, 2 tile huts etc… these are static images that never change. If I convert them to entities, I would have to sort a big list each time an entity moves in the scene, and things will get complicated if some parts are filled with many trees/rocks.
Not to mention the batching, sending hundreds and hundreds of quads each frame will be much less optimized than using a VBO which gets updated when the layer changes.

It would be the easiest solution yes, but tiles aren’t entity sprites, only an array of integers so I can’t do any sorting between tiles and entities.

You do not need to sort all your entities and you do not need to have an entity/object for every single thing on your whole map.

Instead just build the representation of what is visible on the screen once every frame. Sorting and building this will take fractions of a millisecond.

You can even keep your current representation, just change how it is displayed, LibGDX has highly optimized methods for this.

My map is divided into chunks because of the size (10,000x10,000), I draw only visible tiles/entities ofcourse but if I start using entities for things like trees or rocks, the memory taken won’t be the same.
I can use something like a tile id linked to a sprite which is only instantiated once it’s inside the camera view, but what can I do with collisions ? Tilemap collisions are very simple and fast, you find the corresponding cell and you get a boolean if you can go there or not.
By using sprites for trees, they become a single entity and the shape is no more a square, nor a basic rectangle.

Just use your tile-map for collisions/logic like you are probably already doing and make the rendering a separate pass.
You first collect everything that needs to be rendered and then sort it and then render it, this does not need to be linked to anything else in any way.

int[][] terrainLayer;
int[][] objectLayer;
int[][] topLayer;

[...]

//logic pass
int tile = objectLayer[x][y];
if(tile == CHEST_TILE_ID) {
   // logic
}

[...]

//render pass
ArrayList<RenderJob> jobs;
for(x = x1 to x2) { //from left side of screen to right side
    for(y = y1 to y2){ //from upper side of screen to lower side
        jobs.add(new RenderJob(terrainLayer[x][y], x, y, 0));
        jobs.add(new RenderJob(objectLayer[x][y], x, y, 1));
        jobs.add(new RenderJob(topLayer[x][y], x, y, 2));
    }
}
sortForRendering(jobs); // sorting is done by taking into account Y AND Z values
renderJobs(jobs); // render the list in sorted order
                  // sprites are NOT stored in the RenderJob object

And yes this is bad for garbage collection, but good garbage collection behavior can be added later and won’t get your game done.

Thank you for your explanations, it’s more clear :slight_smile:
So I guess I should create an interface for that. Something like “Drawable” with a getY() method implemeted by Entities and a TileDrawable class.
For the GC, I can reuse TileDrawable objects by replacing the tile id and it’s position.

public interface Drawable {
	float getY();
	void draw();
}

public class Entity extends Sprite implements Drawable {
	
	public Vector2 position;
	public Vector2 velocity;

	public float getY() {
		return position.y;
	}

	public void draw() {
		[...]
	}

}

public class TileDrawable implements Drawable {
	
	public int tileId;
	public int x;
	public int y;

	public float getY() {
		return y;
	}

	public void draw() {
		[...]
	}
}



// render logic :
ArrayList<Drawable> drawables;

for(...) {
	for(...) {
		TileDrawable tileDrawable = getFreeTileDrawable();
		tileDrawable.tileId = objectLayer[x][y];
		tileDrawable.x = x;
		tileDrawable.y = y;
		drawables.add(tileRenderer);
	}
}

for(...) {
	drawables.add(entity);
}

// sort drawables
drawables.sort();

// render everything
[...]

What do you think ?

One problem though, Tiles share a single texture but not with entities which are on another one. How do I manage the batching with this ?

Hey sh10, here is how I implement batching.
http://pastebin.java-gaming.org/ecf0c14674d13

Note, doesn’t support java 7 because of default keyword in the interface.

The first class holds the model data. The model is anything else that is specific for each model - meaning each model drawn of this type will have it. The first class extends CoreEntity. This is an upper-level class aimed at holding data for the model, but only what each model utilize to the “Core”. It finally implements the interface Spacial2D. Since each model is virtually the same, the only thing that is variable are the positional elements. So each Entity you create just needs a new Spacial object added to it.

Whats good about this setup is that you can create a Spacial2D variable, add it to the entity, and be able to manipulate the Spacial object without having to .get() from some “holder” or “batch” class. Of course later, instead of taking in just a Spacial object, you could create a Core object for everything that is mutable between each object or something.

Thank you :slight_smile:
So the Entity class is a container that holds every instances (Spacial3D) of the model in scene ?
My problem is that now I can sort tiles and characters together on the Y axis, they don’t use the same texture. There’s one for the tiles and another for entities, I can’t group them to draw 2 batches because the rendering order would be broken and if I draw them in the order I want there might be many different draw calls. In a 16x16 map chunk, if I place a character at every grid cells then it should generate a maximum of 512 draw calls because the renderer would have to switch between tiles and entities for each cell position.
I can ofcourse use a single texture for everything but it’s not maintainable, the tile sheet is already a big texture and I plan to add lot’s of different entities in the other.
Each time I get a solution there’s another headache behind ;D

I have just tried to mimic the same behaviour in Unity and it doesn’t handle it very well :

http://image.noelshack.com/fichiers/2016/25/1466606970-no-order.png

http://image.noelshack.com/fichiers/2016/25/1466606978-order.png

It seems there’s no black magic that can batch efficiently a bunch of sprites with 2 textures and a rendering order applied to them.