← Back to blog

Building a custom tilemap system

Sprint 2 is in the books! The second sprint of this project was focused on developing a custom tilemap system.
Every 2D engine needs a way to render tile-based artwork. For my engine (Zixel) I not only wanted to support tilemaps and
tilesets, but also have a custom in-game editor. This post will detail some of the design decisions and implementation details
of the tilemap system.

What are tilemaps?

Rendering a giant texture is not usually an option for large open-world games. You can’t have a 35,000x35,000 texture!
Instead, you can break the texture into smaller tiles. Tilemaps are a way to store a 2D grid of tiles.

Tilesets

Each tile is a subset of a 2D texture. The source texture is referred to as a tileset. Placing all the tile data into
a single texture is ideal because it allows for a single texture to be loaded into memory during the draw calls.

Here is a texture example of a tileset from the amazing Kenney asset pack.
Please note—All of Kenney’s assets are completely free to use. Head on over to kenney.nl to learn more.

image

More on tilesets later.

Why build an editor?

…but…but…but.... Tiled is awesome!

Yes, Tiled is a fantastic project and Thorbjørn Lindeijer should be saluted for his work.

Let’s take a quick step back and look at the high-level goals of the project. I’m developing Zixel as a platform to
make The Vendor…and other games. This is my game engine. Having full control of the entire development process is
important to me.

Could I have used Tiled and supported its file format? Absolutely!

With agentic coding practices and a clear vision for what I’m trying to achieve, developing a built-in tilemap and tileset editor
is trivial. In 2 weeks (3, but I was AFK for one of them) of 1-hour coding sessions in the morning, I’ve got a fully functional
tilemap editor—albeit a very basic one.

So what does it look like?

image

Here is the tilemap editor in action! The tilemap editor is accessed by pressing “F1” within the game engine (will need to disable this for a shipped game).
On the left side is the current tileset. At the top is the toolbar. From left to right, you can:
- Save the current tilemap
- Resize the tilemap (with anchoring)
- Create a new tileset
- Edit current tileset
- Paint tool
- Erase tool
- Fill tool
- Eye dropper selection tool
- Rectangle drawing tool
- Layer selection dropdown
- Toggle layer visibility
- Layer settings (currently just the name)
- Add layer
- Delete layer
- Move layer up and down (z-ordering)

At the bottom of the screen is an info panel which lists the current tool, layer, and coordinate information where the mouse is located.

Tileset editor

image

The tileset editor allows you to set the size of the tiles within a tileset texture. In addition, custom properties
can be set for each tile. This will be useful for things like “is solid” or “is walkable” later on.

Other features

Layers

The tilemap system supports multiple layers of tiles within the map. This is useful for things like “background” and “foreground”
layers. In the image above, the bottom-most layer is the “grass” layer. On top of it is the “Rock” layer, where the plateu is drawn.

Undo/redo system

Misclicks happen! There is a simple stack-based undo/redo system that allows you to undo and redo your changes. Each tool
supports an undo/redo operation so that actions are atomic, rather than tile manipulation. For example, if I click and drag the
painting tool, I expect all tiles pained in that operation to be undone (if I click “undo”). The same would be true for a fill
operation.

Storage & Loading

There will be an entirely separate post on how I’m handling assets within Zixel. For now, it’s worth noting that
I have a custom asset packaging step during build that will bundle all the assets into a single binary. There is a
tilemap and tileset format (JSON).

Example:

{
  "width": 25,
  "height": 25,
  "tileWidth": 32,
  "tileHeight": 32,
  "tileset": "tilemap-test.png",
  "saved_on": "2025-11-07T12:29:09",
  "layers": [
    {
      "name": "Layer 0",
      "visible": true,
      "opacity": 1,
      "tiles": [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,15,3,3,3,3,3,15,15,15,15,15,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,15,15,15,15,15,3,3,3,3,3,3,3,3,3,3,3,13,13,13,3,3,3,3,3,3,15,15,15,15,15,3,3,3,3,3,3,
        3,3,3,3,3,3,13,3,3,3,3,3,3,3,15,15,15,15,15,3,3,3,3,3,3,3,3,3,3,1,3,13,3,1,3,3,3,3,3,15,15,15,15,15,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
    }
  ]
}

What’s left for the tilemap system?

There are still some items that need to be tackled for the system. Notably:

  • [ ] Animated tiles
  • [ ] Custom brushes
  • [ ] Tile collision masking
  • [ ] Tile rotation / flipping
  • [ ] Use icons for buttons
  • [ ] “infinite” tilemap (remove a need for world sizing)
  • [ ] Keyboard shortcuts
  • [ ] Auto-tiling

Next up: Sprint 3

Continuing with foundational engine work, sprit 3 will focus on animation, audio, and visual FX.

  1. Animation System - Sprite animations + animated tile support
  2. Audio System - Sound effects and music playback
  3. Particle System - Visual effects (dust, sparkles, impact effects)