~4 min read

TileMap (2D) — modular 2D levels

TileMapLayer, TileSet, terrains, autotile, navigation for 2D projects in Godot 4.x.

This encyclopedia is about 3D, but Godot has a first-class 2D pipeline, and TileMap is the main tool for modular levels (platformers, top-down RPGs, dungeon crawlers, city builders).

TileMap architecture in Godot 4.x

With Godot 4.3 an important change happened: the classic TileMap node is deprecated in favor of TileMapLayer nodes.

TileMap (legacy)TileMapLayer (current)
Yearbefore 4.3since 4.3, recommended
LayersInside a single node as an arrayEach layer is a separate node
PerformanceWorse on scenes with layer modulationBetter — each layer is processed in parallel
Editor UXComplex UI for multi-layerSimple: drag-and-drop nodes to reorder

In a new project, use TileMapLayer. One node = one layer (for example, background → details → objects).

Key concepts

  • TileSet — a Resource with a list of all available tiles (sprite + collision + nav data).
  • TileMapLayer — a Node2D that draws tiles from a TileSet on a coordinate grid.
  • Tile — a cell of the TileSet: sprite source + collision shape + custom data layers.
  • TileSetAtlasSource — a tile source from a single image (atlas-style).
  • TileSetScenesCollectionSource — a tile source from PackedScenes (animated / complex).
Web

A CSS sprite sheet with background-position + Pixi.js tilemap libraries.

Unity

Creating a TileSet

  1. In FileSystem → New Resource → TileSet.
  2. Double-click — the TileSet editor opens (bottom panel).
  3. Click + → New Atlas Source → choose a texture (a sprite atlas with tiles).
  4. The editor automatically slices the atlas into cells (16×16 by default). Each cell is a separate tile.
  5. For each tile you configure:
    • Physics layer — a collision shape (select Physics Layer 0, draw a polygon).
    • Navigation layer — for NavigationAgent2D.
    • Custom data layers — arbitrary properties (for example, “damage_per_tick” for lava).

TileMapLayer in action

World
├── TileMapLayer_Background
│   tile_set: floor.tres
│   y_sort_enabled: false
├── TileMapLayer_Walls
│   tile_set: floor.tres  # the same TileSet
│   y_sort_enabled: false
└── TileMapLayer_Objects
    tile_set: objects.tres
    y_sort_enabled: true   # for top-down with depth

In the Scene View select the layer → TileMap Editor (bottom panel) → choose a tile from the palette → draw.

Programmatic control

extends TileMapLayer

func _ready() -> void:
    # Coordinates in TileMap are Vector2i (integers)
    set_cell(Vector2i(0, 0), 0, Vector2i(0, 0))  # source_id, atlas_coords
    # source_id — the source index in the TileSet
    # atlas_coords — the tile position in the atlas

    # Erase a tile
    erase_cell(Vector2i(0, 0))

    # Get tile data
    var tile_data := get_cell_tile_data(Vector2i(0, 0))
    if tile_data:
        var dmg = tile_data.get_custom_data("damage_per_tick")
        print(dmg)

    # Convert between world ↔ map coordinates
    var map_pos := local_to_map(Vector2(64, 32))
    var world_pos := map_to_local(Vector2i(2, 1))

Terrains — auto-connecting tiles

The key feature for beautiful levels. You paint a zone (grass, water, road), and the engine itself picks the correct tile for each cell based on its neighbors.

  1. In the TileSet editor → choose the Terrains tab.
  2. Add a Terrain Set → a new Terrain (“Grass”).
  3. On each tile in the Atlas, mark which of its corners belong to the “Grass” terrain.
  4. In the TileMap editor switch the mode to Terrains → choose Grass → “paint” a large area.
  5. For each cell Godot automatically picks the tile from the set whose corners match its neighbors.

This is terrain matching by corners and/or sides — the classic “auto-tile”. You can draw a curved grass border across the map, and the seam with the road / water will be perfect.

Wang tiles vs corner-based

Godot Terrains uses corner-based matching (the 4 corners of a tile have a bitmask). This enables smooth transitions and diagonal-correct uneven borders. The old Wang-tile scheme (with side-based matching) also exists in the API, but corner is the modern way.

If you want a NavigationAgent2D to walk across your map:

  1. In TileSet → Physics Layers is NOT enough — that’s collision, not nav.
  2. In TileSet → Navigation Layers → add a layer.
  3. On each walkable tile → draw a navigation polygon (usually matching the tile’s border).
  4. On the TileMapLayer node → Navigation Layers → check the one being used.
  5. Godot automatically builds a navmesh from all walkable tiles.

Animated tiles

In the TileSet Atlas Source → select a tile → in the Inspector → Animation Frames Count > 1. Specify the duration of each frame. Movement / texture animation works without scripts — TileMapLayer updates automatically.

Use cases: flowing water, torches, flickering crystals.

Pitfalls

  1. Tile size in TileSet vs TileMapLayer — they must match. If you changed it in the TileSet → repaint the layers.
  2. Physics doesn’t work by default — the Physics Layer must be enabled and the tile must have a collision polygon. Often forgotten.
  3. Y-sort on a single layer does not play well with tile collision — for top-down with proper sorting of a character behind a tree, use an Object Layer (Y-sort) separate from the ground layers.
  4. Custom data layers — powerful, but remember the names. A typo "damage_per_tick" vs "damagePerTick" — silent fail.

When TileMap is NOT the choice

  • A 3D scene — these are 2D nodes; in 3D use GridMap (see chapter 21).
  • Hex grid — TileMap supports hex layout (Inspector → tile_shape = HALF_OFFSET_*), but the editor is more convenient for orthogonal. For a serious hex project, look at community plugins.
  • Voxel-style 3D — that’s a completely different task; TileMap is not suitable.