Getting Started With Godot Tile Maps: TileMapLayer, TileSet, Collisions, and Codex

A beginner-friendly Godot 4.x tile map guide covering TileSet, TileMapLayer, layered maps, tile collisions, Terrain auto-connection, and how to use Codex to write map interaction code.

A Godot tile map is a way to take a sprite sheet containing small images such as grass, roads, walls, and water, split it into regular grid cells, and then paint a level with those tiles.

In Godot 4.x, especially for new projects after 4.3, use TileMapLayer. The old TileMap node is deprecated. The current recommendation is to use one TileMapLayer for each map layer. This makes the node tree clearer and fits Godot’s node-based workflow better.

The official documentation also states that TileMapLayer is a node for 2D tile-based maps, and that it uses a TileSet to create grid maps. If you need multiple layers, use multiple TileMapLayer nodes.

Official docs:

https://docs.godotengine.org/en/stable/classes/class_tilemaplayer.html

https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html

Two Core Concepts

Tile maps revolve around two things:

  1. TileSet
  2. TileMapLayer

TileSet is the tile library. It stores:

  1. Grass, dirt, walls, water, roads, and other tiles.
  2. Collision shapes for individual tiles.
  3. Terrain auto-connection rules.
  4. Navigation, occlusion, and custom data.

TileMapLayer is the canvas. It uses tiles from the TileSet to draw the map.

Start with a structure like this:

1
2
3
4
5
6
World (Node2D)
├─ Ground (TileMapLayer)       # Grass, roads, floors
├─ Decoration (TileMapLayer)   # Flowers, cracks, shadows
├─ Walls (TileMapLayer)        # Walls and obstacles
├─ Objects (Node2D)            # Chests, doors, NPCs, coins
└─ Player (CharacterBody2D)

Layering has several advantages:

  1. Ground and walls do not get mixed together.
  2. Display order is easier to control.
  3. You can hide a single layer.
  4. Only the wall layer needs collision; the ground layer can stay simple.
  5. Codex gets a clearer node structure when writing scripts later.

Create Your First Tile Map

Prepare a tile image first, for example:

1
tileset.png

Every cell inside the image should use the same size. Common sizes are:

1
2
3
16 × 16
32 × 32
64 × 64

If each tile in the source art is 32 × 32, the Tile Size in your TileSet should also be 32 × 32.

Add a TileMapLayer

Add this to the scene:

1
2
Node2D
└─ TileMapLayer

Rename the TileMapLayer to:

1
Ground

Select Ground, then find this in the Inspector:

1
Tile Set

Click:

1
2
<empty>
→ New TileSet

Then open the new TileSet resource and set Tile Size to the source tile size, for example:

1
32 × 32

Add the Tile Image

After selecting Ground, the TileMap / TileSet editor panel appears at the bottom.

Drag tileset.png into the TileSet panel and choose automatic tile creation. Godot will split the image into tiles according to Tile Size.

After this step, the TileSet contains drawable tiles, and the Ground TileMapLayer can use them to paint the map.

Paint the Map

Switch to the TileMap panel at the bottom:

  1. Pick a grass tile.
  2. Paint with the pencil tool.
  3. Delete with the eraser.
  4. Use the rectangle tool to fill a region quickly.
  5. Use the fill tool to fill a connected area.

Do not start with a huge map. Draw a small 20 × 15 map first, with only grass, walls, and a player spawn point.

Add Collision to Walls

Do not add collision to every ground tile. Usually only non-walkable tiles need collision:

  1. Walls.
  2. Rocks.
  3. Fences.
  4. Water boundaries.
  5. Cliffs.

Select the TileSet resource and find:

1
Physics Layers

Click:

1
Add Element

A common setup is:

1
2
Collision Layer: 1
Collision Mask: 1

Then in the bottom TileSet panel:

  1. Switch to the collision or physics painting tools.
  2. Select a wall tile.
  3. Draw a rectangular or polygon collision shape over the wall area.

This lets different tiles in the same TileSet have different collision shapes.

Make the Player Collide With Tile Walls

A basic player scene can look like this:

1
2
3
Player (CharacterBody2D)
├─ Sprite2D
└─ CollisionShape2D

Start with a minimal movement script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
extends CharacterBody2D

@export var speed: float = 200.0


func _physics_process(_delta: float) -> void:
	var direction := Input.get_vector(
		"move_left",
		"move_right",
		"move_up",
		"move_down"
	)

	velocity = direction * speed
	move_and_slide()

As long as the Player collision layer and mask match the physics layer in the TileSet, the player will be blocked by wall tiles.

While running the game, enable:

1
2
Debug
→ Visible Collision Shapes

This shows the player and wall collision shapes directly, which makes debugging much easier.

Use Three Map Layers

For a first project, use three layers:

1
2
3
4
World
├─ Ground
├─ Walls
└─ Decoration

Each node is an independent TileMapLayer.

Put these in Ground:

  1. Grass.
  2. Dirt.
  3. Roads.
  4. Floors.

Usually there is no collision.

Put these in Walls:

  1. Walls.
  2. Cliffs.
  3. Water boundaries.
  4. Non-walkable rocks.

Usually this layer has collision.

Put these in Decoration:

  1. Flowers.
  2. Grass blades.
  3. Ground cracks.
  4. Shadows.

Usually there is no collision.

You can use z_index for a simple draw order:

1
2
3
4
Ground: 0
Walls: 1
Decoration: 2
Player: 3

If you have trees, roofs, or bridge openings that should cover the player, handle that later with Y Sort or by splitting objects into upper and lower parts. Your first map does not need a complex occlusion system.

Use Terrain to Auto-Connect Roads and Walls

If you want the editor to automatically create edges and corners, such as:

  1. Grass connecting to dirt edges.
  2. Roads generating corners automatically.
  3. Walls choosing the correct tile based on neighbors.
  4. Water generating shorelines.

Use Godot’s Terrain Set.

The basic process is:

  1. Add a Terrain Set in the TileSet.
  2. Choose a matching mode, such as matching by sides and corners.
  3. Create terrains, such as Grass, Dirt, and Water.
  4. Mark the terrain connection positions for each tile.
  5. Switch the TileMapLayer to Terrains painting mode.
  6. Paint the map with the Connect or Path tool.

Godot will choose straight, corner, and edge tiles based on nearby cells. The official docs also mention two Terrain painting modes: Connect, which is easier to start with, and Path, which gives more manual control for roads and paths.

You do not need Terrain immediately. First draw a small map manually and understand TileSet, TileMapLayer, and collisions. Then learn auto-connection.

Edit Tiles From Code

Assume this scene structure:

1
2
World
└─ Ground

You can reference Ground from the World script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
extends Node2D

@onready var ground: TileMapLayer = $Ground

const SOURCE_ID: int = 0
const GRASS_TILE: Vector2i = Vector2i(0, 0)


func place_grass(cell: Vector2i) -> void:
	ground.set_cell(
		cell,
		SOURCE_ID,
		GRASS_TILE
	)

Here, cell is a tile map cell coordinate. For example:

1
place_grass(Vector2i(5, 3))

This places a grass tile at column 5, row 3.

Important: SOURCE_ID and the atlas coordinates in GRASS_TILE must match your actual TileSet. Do not copy the sample values blindly.

Convert Between World Coordinates and Cell Coordinates

Mouse positions are world coordinates, while tile maps use cell coordinates. Usually you first convert to the layer’s local coordinates, then convert to a map cell.

World position to cell coordinate:

1
2
var local_position := ground.to_local(get_global_mouse_position())
var cell := ground.local_to_map(local_position)

Cell coordinate back to map position:

1
var position_in_layer := ground.map_to_local(cell)

To place a tile with a mouse click:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
extends Node2D

@onready var ground: TileMapLayer = $Ground

const SOURCE_ID: int = 0
const GRASS_TILE: Vector2i = Vector2i(0, 0)


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
			var local_position := ground.to_local(
				get_global_mouse_position()
			)
			var cell := ground.local_to_map(local_position)

			ground.set_cell(
				cell,
				SOURCE_ID,
				GRASS_TILE
			)

To support right-click deletion, use:

1
ground.erase_cell(cell)

set_cell(), erase_cell(), local_to_map(), and map_to_local() are common TileMapLayer APIs.

Do Not Make Every Chest, Door, or Coin a Plain Tile

These objects are usually not good as plain image tiles:

  1. Coins.
  2. Chests.
  3. Doors that can open.
  4. NPCs.
  5. Enemies.
  6. Teleport points.
  7. Traps.
  8. Breakable boxes.

They have scripts, animations, collisions, and signals, so they are usually better as separate scenes.

For example, a coin:

1
2
3
Coin (Area2D)
├─ Sprite2D
└─ CollisionShape2D

Place it under:

1
2
World
└─ Objects

Plain tiles are best for static maps. Objects with behavior are better as independent Scene files. Godot also supports Scene Collection tiles, but for beginners, manually placing independent scenes is easier to understand and debug.

What Codex Can Help With

Codex is good at:

  1. Writing player movement scripts.
  2. Reading map cells.
  3. Procedurally generating maps.
  4. Randomly painting ground tiles.
  5. Placing and deleting tiles with the mouse.
  6. Finding spawn points.
  7. Reading custom tile data.
  8. Checking TileMapLayer API usage.
  9. Implementing coins, doors, and chests.

You can prompt Codex like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
This is a Godot 4.x project.

Scene structure:

World: Node2D
├─ Ground: TileMapLayer
├─ Walls: TileMapLayer
├─ Objects: Node2D
└─ Player: CharacterBody2D

Please write a script for World:

1. Convert the mouse world position to Ground cell coordinates;
2. Left-click places a grass tile;
3. Right-click clears a tile;
4. SOURCE_ID and atlas coordinates should use @export configuration;
5. Use Godot 4.x TileMapLayer API;
6. Use static types;
7. Do not modify the TileSet or scene node names.

Codex is less suitable for:

  1. Determining the tile size of the source art.
  2. Visually painting an entire map.
  3. Fine-tuning Terrain bitmasks.
  4. Guessing source_id.
  5. Guessing atlas coordinates.
  6. Hand-writing large .tscn map data.

A better workflow is: you create the TileSet, configure collisions, and paint the map in the Godot editor; Codex writes the map interaction, generation logic, and gameplay scripts around the real node structure.

First Practice Project

For the first exercise, make only a 20 × 15 map:

  1. Paint grass on Ground.
  2. Draw a wall border on Walls.
  3. Add collision to wall tiles.
  4. Place a Player.
  5. Make the player collide with the walls.
  6. Add a Coin scene afterward.

After finishing this exercise, you will understand the basic Godot tile map workflow:

1
2
3
4
5
TileSet stores tile art and rules
TileMapLayer draws one map layer
Collision is configured on tiles inside the TileSet
Objects with behavior should be independent scenes
Codex writes scripts around the real node structure

Get this minimal map working first. Then move on to Terrain, Y Sort, procedural generation, and large map loading.

记录并分享
Built with Hugo
Theme Stack designed by Jimmy