I have the basis of a tiled map with multiple layers implemented, and I’m looking for advice on my approach, given my somewhat unique intended application.
I’m building a simulation game that only requires a fairly minimal graphical interface. It is a tiled map where all of the tiles have the same size (something similar to Dwarf Fortress). There are going to be 3 or 4 layers of tiles, each layer pulling its tiles from a large texture with an array of tiles. There won’t even be a need to animate sprites moving across the tile map. The characters are simply tiles of the same size as the map tiles, and they move discretely one tile at a time.
The primary focus is performance, because I am building fairly complex game logic. The only exception to the tile map will be a simple menu system.
Here is my basic approach so far:
I have one array buffer object holding four vertices to create a single tile. These four vertices are then drawn multiple times using glDrawArraysInstanced to create the skeleton of the tile map.
Then I have a second VBO that holds the per instance data for each tile. It has the world position for each tile (three floats) and the texture coordinates for each tile (four floats) interleaved like this:
{
0.0f, 0.0f, -2.0f,
0.0f / TILESET_WIDTH, 13.0f / TILESET_HEIGHT,
0.0f / TILESET_WIDTH, 14.0f / TILESET_HEIGHT,
...
This is sent to the shaders as vertex attributes like this:
glVertexAttribPointer(
1, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GL_FLOAT), 0
);
glVertexAttribPointer(
2, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT))
);
This allows me to get all the per instance data for each tile into the shaders, but I’m a bit concerned because my current approach relies on some conditional logic in the shaders.
In the vertex shader, I use the gl_VertexID value to correctly set up the texture coordinates for each vertex. I only pass in the bottom-left and the top-right coordinates, and then use this to derive all four corners. But that logic is in the shader, and I’ve read some negative things about branching like this. I’ve looked into the non-branching functional versions of this logic, but I’m not sure if that’s the right approach.
if (gl_VertexID == 0) {
tex_coord.x = aTexCoord[0];
tex_coord.y = aTexCoord[1];
} else if (gl_VertexID == 1) {
...
In the fragment shader, the correct texture is chosen with another conditional based on the z-value of the tile, because each layer takes from its own unique texture atlas.
if (tileset_id == 0.0) {
FragColor = texture(character_tileset, tex_coord);
} else if (tileset_id == -1.0) {
FragColor = texture(object_tileset, tex_coord);
} else if (tileset_id == -2.0) {
FragColor = texture(map_tileset, tex_coord);
}
I’ll link to the repo with the full codebase to help clarify any confusion: https://github.com/ecssiah/last-ditch
I haven’t started on the UI system at all yet, and I would also really appreciate any suggestions on how to do this in a simple, efficient way. I have ruled out the Dwarf Fortress approach of simply building it within the tiled system. I think this is the one exception I’ll make for aesthetic reasons. I want a very a simple windowed menu system.
Thanks!!!