Metroidvania Generation

Celeste-Like Tilesets

Celeste’s tilesets have a number of interesting and useful properties.

Generally, each terrain tileset (rock, stone, dirt, etc.) has…

  • 8px square tiles

  • 3 unique, indexed colors (light, medium, dark)

  • 1 background color (which is often shared with neighboring tilesets)

  • 4 exterior edge variants for each direction (used for straight edges)

  • ~10 interior edge variants (used to separate exterior edges from the background)

  • 4 interior corners and 4 exterior corners

  • 4 horizontal and 4 vertical variants for single-tile-wide walls, along with endcaps for each

Each level will use a number of different individual tilesets, selected such that they can be used simultaneously in the same screen without looking strange. It’ll also have some doodad tilesets (snow, plants, crystals, etc.) which can be overlaid on top of the base tilesets to add more visual interest.

The brilliance of this system is that not only can the tilesets be auto-tiled (which vastly simplifies level design, since), the variants can be randomized such that the tiles feel more like a 16px square tileset while being much easier to design and maintain. (You know the system works because I was able to do it!)

celeste_tilesets_breakdown.gif

 

This debug tileset shows how the tile variants are automatically randomized along both exterior and interior edges. Numbers 0-9 represent internal edge variants, and tiles with 1-4 dots represent external edge variants.

(Sorry, they’re backwards here by mistake!)

Using a debug shader, we can visualize the vertex color of each sprite in the tilemap. When the tilemap is rendered, the tileset replacement shader uses these vertex colors to determine which tileset atlas to sample from.

Magenta tiles are drawn by sampling the “base” tilemap, red tiles sample the “alt” tilemap (ex. another neighboring zone), and teal tiles use a doodad overlay texture (snow piles, vines, etc.)

With the tileset replacement shader active, the two tilesets blend together nicely. Note how the blue and gray tilesets both use the same “background” or “clear” color — choosing a color that fits well into both palettes helps join the two tilesets together.

We can even blend between alternate tilesets at runtime! This is super useful when instantiating rooms, since it lets us apply any tileset to any room, without having to regenerate or modify the underlying Tilemap. Since tilemap modifications are one of the most expensive parts of room instantiation, this saves us a ton of computation time!

Previous
Previous

Non-Euclidean Trickery

Next
Next

Modular Rooms