Skip to content
Back to skills

Godot Migrate Tilemap

ASecurity

Migrates legacy TileMap (Godot 4.0-4.2) to new TileMapLayer system (Godot 4.3+). Handles TileMap node conversion, API migration (set_cell to set_cells_terrain_connect), TileSet resource updates, physics layer mapping, navigation layer conversion, and custom data preservation. Essential for upgrading Godot 4.2 projects to 4.3+.

  • 666 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added February 8, 2026
developmentgobashnodetestinggitapi

Works with

  • api

Security analysis

A100/100

Scanned February 10, 2026

npx -y skills add majiayu000/claude-skill-registry --skill godot-migrate-tilemap --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Godot Migrate Tilemap?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Godot Migrate Tilemap
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-godot-migrate-tilemap/badge)](https://www.skillsdirectory.com/skills/majiayu000-godot-migrate-tilemap)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: godot-migrate-tilemap
version: 1.0.0
displayName: "Godot TileMap V2 Migration"
description: >
  Migrates legacy TileMap (Godot 4.0-4.2) to new TileMapLayer system (Godot 4.3+).
  Handles TileMap node conversion, API migration (set_cell to set_cells_terrain_connect),
  TileSet resource updates, physics layer mapping, navigation layer conversion, and
  custom data preservation. Essential for upgrading Godot 4.2 projects to 4.3+.
author: "Asreonn"
license: MIT
category: game-development
type: tool
difficulty: advanced
audience: [developers, migrators]
keywords:
  - godot
  - tilemap
  - tilemaplayer
  - migration
  - godot43
  - tileset
  - terrain
  - navigation
  - physics
platforms: [macos, linux, windows]
repository: https://github.com/asreonn/godot-superpowers
homepage: https://github.com/asreonn/godot-superpowers#readme
filesystem:
  read:
    - "${PROJECT_ROOT}/**/*.gd"
    - "${PROJECT_ROOT}/**/*.tscn"
    - "${PROJECT_ROOT}/**/*.tres"
    - "${PROJECT_ROOT}/project.godot"
  write:
    - "${PROJECT_ROOT}/**/*.gd"
    - "${PROJECT_ROOT}/**/*.tscn"
    - "${PROJECT_ROOT}/**/*.tres"
  deny:
    - "**/.env*"
    - "**/secrets*"
    - "**/*.key"
behavior:
  timeout: 600
  retry: 2
  cache: true
  interactive: true
---

# Godot TileMap V2 Migration

**Migrates legacy TileMap system to Godot 4.3+ TileMapLayer architecture.**

## Breaking Changes

Godot 4.3 introduced a new TileMap system with breaking changes:

| Legacy (4.0-4.2) | New (4.3+) |
|------------------|------------|
| Single `TileMap` node | Multiple `TileMapLayer` nodes |
| `set_cell()` method | `set_cells_terrain_connect()` |
| Cell-based coordinates | Layer-based organization |
| Single TileSet resource | Enhanced TileSet with layers |
| `update_bitmask_region()` | Terrain system |
| Manual physics setup | Physics layers per tile |

---

## UPON INVOCATION - START HERE

When this skill is invoked, IMMEDIATELY execute:

### 1. Verify Godot Project (5 seconds)

```bash
ls project.godot 2>/dev/null && echo "✓ Godot project detected" || echo "✗ Not a Godot project"
```

**If NOT a Godot project:**
- Inform user this skill only works on Godot projects
- STOP here

### 2. Detect TileMap Usage (10 seconds)

```bash
echo "=== Detecting TileMap Usage ==="

echo "TileMap nodes in scenes:"
grep -rn "type=\"TileMap\"" --include="*.tscn" . | wc -l

echo "TileMap references in scripts:"
grep -rn "TileMap" --include="*.gd" . | wc -l

echo "set_cell calls:"
grep -rn "set_cell\|get_cell" --include="*.gd" . | wc -l

echo "update_bitmask calls:"
grep -rn "update_bitmask" --include="*.gd" . | wc -l

echo "tile_set property access:"
grep -rn "\.tile_set" --include="*.gd" . | wc -l
```

### 3. Present Findings

Show the user:
```
=== TileMap V2 Migration Analysis ===

Project: [project name]
Current: Legacy TileMap (Godot 4.0-4.2 style)

TileMap usage detected:
- TileMap nodes: X
- TileMap references: X
- set_cell/get_cell calls: X
- update_bitmask calls: X
- tile_set access: X

Migration includes:
✓ TileMap → TileMapLayer node conversion
✓ set_cell() → set_cells_terrain_connect()
✓ TileSet resource upgrade
✓ Physics layer mapping
✓ Navigation layer conversion
✓ Custom data preservation
✓ Terrain system setup
✓ Git commit per layer
✓ Backup before changes

⚠️  WARNING: Godot 4.3+ required for new TileMapLayer system

Would you like me to:
1. Proceed with migration (recommended)
2. Show detailed breakdown first
3. Migrate specific TileMaps only
4. Cancel
```

### 4. Wait for User Choice

- **If 1 (Proceed):** Start Phase 2 immediately
- **If 2 (Details):** Show file-by-file breakdown
- **If 3 (Selective):** Ask which TileMaps to migrate
- **If 4 (Cancel):** Exit skill

---

## Phase 1: Analysis & Inventory

### 1.1 Create TileMap Inventory

```bash
# Find all TileMap nodes in .tscn files
grep -rn "type=\"TileMap\"" --include="*.tscn" . | while read line; do
    file=$(echo "$line" | cut -d: -f1)
    echo "Found TileMap in: $file"
done > /tmp/tilemap_scenes.txt

# Find all TileMap references in scripts
grep -rn "extends TileMap\|var.*TileMap\|: TileMap" --include="*.gd" . | while read line; do
    file=$(echo "$line" | cut -d: -f1)
    echo "TileMap usage in: $file"
done > /tmp/tilemap_scripts.txt
```

### 1.2 Analyze TileMap Structure

For each TileMap node:

```bash
# Extract TileMap configuration from .tscn
grep -A20 "type=\"TileMap\"" scene.tscn | grep -E "tile_set|format|cell|layer"
```

### 1.3 Create Migration Plan

```
TileMap V2 Migration Plan:
=========================

1. Node Structure Changes (X TileMaps)
   - Convert TileMap → TileMapLayer nodes
   - Preserve layer order and names
   - Update scene hierarchy

2. API Migration (X scripts)
   - set_cell() → set_cells_terrain_connect()
   - get_cell() → get_cell_alternative_tile()
   - update_bitmask() → terrain system

3. TileSet Updates (X resources)
   - Upgrade TileSet format
   - Map physics layers
   - Configure navigation layers
   - Preserve custom data

4. Script Updates (X files)
   - Update TileMap references
   - Fix method calls
   - Update signal connections

Total operations: X
Estimated time: Auto
Godot version required: 4.3+
Backup created: YES
Rollback available: YES
```

---

## Phase 2: TileMap Node Migration

### 2.1 Convert TileMap to TileMapLayer

**Legacy Structure:**
```ini
[node name="TileMap" type="TileMap"]
tile_set = ExtResource("1_qwerty")
format = 2

layer_0/name = "Ground"
layer_0/tile_data = PackedInt32Array(...)

layer_1/name = "Walls"  
layer_1/tile_data = PackedInt32Array(...)
```

**New Structure:**
```ini
[node name="Ground" type="TileMapLayer" parent="."]
tile_map_data = PackedByteArray(...)
tile_set = ExtResource("1_qwerty")

[node name="Walls" type="TileMapLayer" parent="."]
tile_map_data = PackedByteArray(...)
tile_set = ExtResource("1_qwerty")
```

**Transformation Process:**

1. **Parse legacy TileMap**
   - Extract layer names
   - Extract layer data
   - Extract TileSet reference
   - Extract position/z-index

2. **Generate TileMapLayer nodes**
   - One node per layer
   - Name from layer name
   - Convert tile_data format
   - Preserve TileSet reference

3. **Update scene hierarchy**
   - Remove TileMap node
   - Add TileMapLayer children
   - Update parent references

---

### 2.2 Tile Data Conversion

**Legacy Format:**
```ini
layer_0/tile_data = PackedInt32Array(0, 1, 0, 65536, 1, 0, ...)
```

**New Format:**
```ini
tile_map_data = PackedByteArray(0, 0, 0, 0, 1, 0, 0, 0, ...)
```

**Note:** Direct byte conversion requires Godot's internal format knowledge. Alternative approach:

```gdscript
# Migration script approach
# 1. Load scene with legacy TileMap in Godot 4.3
# 2. Run migration tool script
# 3. Save with new TileMapLayer format
```

---

## Phase 3: API Migration

### 3.1 Method Call Updates

**Detection:**
```bash
grep -rn "set_cell\|get_cell\|update_bitmask" --include="*.gd" .
```

**Common Mappings:**

| Legacy API | New API |
|------------|---------|
| `set_cell(layer, coords, source_id)` | `set_cells_terrain_connect(coords_array, terrain_set, terrain)` |
| `get_cell(layer, coords)` | `get_cell_alternative_tile(coords)` |
| `get_cell_source_id(layer, coords)` | `get_cell_source_id(coords)` |
| `update_bitmask_region(start, end)` | Terrain system (set terrain bits) |
| `clear_layer(layer)` | `clear()` on TileMapLayer |
| `erase_cell(layer, coords)` | `erase_cell(coords)` |

### 3.2 Script Transformations

**Example 1: Setting a cell**

Before:
```gdscript
# Legacy TileMap API
tilemap.set_cell(0, Vector2i(5, 3), 1)
tilemap.set_cell(0, Vector2i(5, 4), 1)
tilemap.set_cell(0, Vector2i(6, 3), 1)
```

After:
```gdscript
# New TileMapLayer API - Using terrain for multiple cells
ground_layer.set_cells_terrain_connect(
    [Vector2i(5, 3), Vector2i(5, 4), Vector2i(6, 3)],
    0,  # terrain_set
    1   # terrain_id
)
```

**Example 2: Getting cell data**

Before:
```gdscript
var source_id = tilemap.get_cell_source_id(0, coords)
var atlas_coords = tilemap.get_cell_atlas_coords(0, coords)
```

After:
```gdscript
var source_id = ground_layer.get_cell_source_id(coords)
var atlas_coords = ground_layer.get_cell_atlas_coords(coords)
```

**Example 3: Autotile/Bitmask**

Before:
```gdscript
tilemap.set_cell(0, coords, 1)
tilemap.update_bitmask_region(Rect2i(0, 0, 20, 20))
```

After:
```gdscript
# Using terrain system
ground_layer.set_cells_terrain_connect([coords], 0, 1)
# Terrain automatically connects - no update_bitmask needed!
```

---

## Phase 4: TileSet Resource Migration

### 4.1 Physics Layers

**Legacy:** Physics setup per tile in TileSet

**New:** Dedicated physics layers

```gdscript
# New TileSet setup in Godot 4.3
tileset.set_physics_layer_collision_layer(0, 1)
tileset.set_physics_layer_collision_mask(0, 1)
tileset.set_physics_layer_physics_material_override(0, physics_material)
```

### 4.2 Navigation Layers

**Legacy:** Navigation polygons per tile

**New:** Navigation layers system

```gdscript
# Enable navigation layer
tileset.set_navigation_layer_enabled(0, true)

# Set navigation polygon for specific tile
var source_id = 1
var atlas_coords = Vector2i(0, 0)
tileset.set_navigation_polygon(0, source_id, atlas_coords, navigation_polygon)
```

### 4.3 Custom Data Layers

**New in 4.3:** Custom data per tile

```gdscript
# Define custom data layer
tileset.add_custom_data_layer()
tileset.set_custom_data_layer_name(0, "tile_health")
tileset.set_custom_data_layer_type(0, TYPE_INT)

# Set data on specific tile
tileset.set_custom_data(0, source_id, atlas_coords, 100)
```

---

## Phase 5: Execution & Safety

### 5.1 Create Git Baseline

```bash
# Create backup tag
git tag tilemap-v1-baseline-$(date +%Y%m%d-%H%M%S)

# Commit any current changes
git add .
git commit -m "Baseline: Pre-TileMap V2 migration" || echo "No changes to commit"
```

### 5.2 Migration Execution

For each TileMap:

1. **Backup scene file**
   ```bash
   cp scene.tscn scene.tscn.backup
   ```

2. **Parse TileMap data**
   - Extract layers
   - Extract tile data
   - Note TileSet reference

3. **Generate TileMapLayer nodes**
   - Create node entries
   - Convert data format
   - Set properties

4. **Update scripts**
   - Replace TileMap references
   - Update method calls
   - Fix signal connections

5. **Commit changes**
   ```bash
   git add scene.tscn modified_scripts.gd
   git commit -m "Migrate: TileMap to TileMapLayer in scene.tscn
   
   - Converted TileMap node to TileMapLayer nodes
   - Updated script references
   - Migrated set_cell() calls
   - Preserved layer data"
   ```

### 5.3 Validation After Each Migration

```bash
# Check scene loads in Godot
godot --headless --quit-after 5 project.godot 2>&1 | tee test.log

# Check for errors
if grep -q "ERROR\|SCRIPT ERROR" test.log; then
    echo "⚠️  Migration error detected!"
    git reset --hard HEAD~1
    echo "✓ Reverted to pre-migration state"
    exit 1
fi

rm test.log
```

---

## Phase 6: Post-Migration Setup

### 6.1 Terrain System Configuration

```gdscript
# Setup terrain for autotiling
tileset.add_terrain_set()
tileset.set_terrain_set_mode(0, TileSet.TerrainMode.CONNECT)

# Add terrain
tileset.add_terrain(0, 0)
tileset.set_terrain_name(0, 0, "Ground")

# Assign terrain to tiles
# (Configure in Godot editor for best results)
```

### 6.2 Physics Layer Setup

```gdscript
# Configure physics layers per tile type
tileset.set_physics_layer_collision_layer(0, 1)  # Layer 1
tileset.set_physics_layer_collision_mask(0, 1)   # Detect layer 1
```

### 6.3 Navigation Setup

```gdscript
# Enable navigation on specific tiles
navigation_layer.enabled = true
tileset.set_navigation_layer_enabled(0, true)
```

---

## Examples

### Example 1: Complete TileMap Migration

**Before (Godot 4.2):**
```gdscript
# level.tscn
[node name="TileMap" type="TileMap"]
tile_set = ExtResource("1_tileset")
format = 2
layer_0/name = "Ground"
layer_0/tile_data = PackedInt32Array(...)
layer_1/name = "Obstacles"
layer_1/tile_data = PackedInt32Array(...)

# level.gd
extends Node2D

@onready var tilemap: TileMap = $TileMap

func _ready():
    # Set some cells
    tilemap.set_cell(0, Vector2i(10, 5), 1)
    tilemap.set_cell(0, Vector2i(11, 5), 1)
    tilemap.update_bitmask_region(Rect2i(10, 5, 2, 1))
    
    # Get cell info
    var source_id = tilemap.get_cell_source_id(0, Vector2i(10, 5))
    print("Cell source: ", source_id)

func generate_level():
    for x in range(20):
        for y in range(15):
            tilemap.set_cell(0, Vector2i(x, y), randi() % 3)
    tilemap.update_bitmask_region(Rect2i(0, 0, 20, 15))
```

**After (Godot 4.3):**
```gdscript
# level.tscn
[node name="Ground" type="TileMapLayer" parent="."]
tile_set = ExtResource("1_tileset")
tile_map_data = PackedByteArray(...)

[node name="Obstacles" type="TileMapLayer" parent="."]
tile_set = ExtResource("1_tileset")
tile_map_data = PackedByteArray(...)

# level.gd
extends Node2D

@onready var ground_layer: TileMapLayer = $Ground
@onready var obstacles_layer: TileMapLayer = $Obstacles

func _ready():
    # Set cells using terrain
    ground_layer.set_cells_terrain_connect(
        [Vector2i(10, 5), Vector2i(11, 5)],
        0,  # terrain_set
        1   # terrain_id
    )
    
    # Get cell info
    var source_id = ground_layer.get_cell_source_id(Vector2i(10, 5))
    print("Cell source: ", source_id)

func generate_level():
    var coords_array = []
    for x in range(20):
        for y in range(15):
            coords_array.append(Vector2i(x, y))
    
    # Use terrain for efficient bulk placement
    ground_layer.set_cells_terrain_connect(coords_array, 0, randi() % 3)
```

### Example 2: Multiple Layer Management

**Before:**
```gdscript
# Access different layers
func set_ground_cell(coords: Vector2i, tile: int):
    tilemap.set_cell(0, coords, tile)

func set_wall_cell(coords: Vector2i, tile: int):
    tilemap.set_cell(1, coords, tile)

func clear_all():
    tilemap.clear_layer(0)
    tilemap.clear_layer(1)
```

**After:**
```gdscript
# Access different layers
func set_ground_cell(coords: Vector2i, tile: int):
    ground_layer.set_cells_terrain_connect([coords], 0, tile)

func set_wall_cell(coords: Vector2i, tile: int):
    obstacles_layer.set_cell(coords, tile)

func clear_all():
    ground_layer.clear()
    obstacles_layer.clear()
```

---

## Success Criteria

Migration complete when:

- ✓ Zero TileMap nodes remain (converted to TileMapLayer)
- ✓ Zero `set_cell(layer, ...)` calls remain
- ✓ Zero `update_bitmask` calls remain
- ✓ All scripts use TileMapLayer references
- ✓ TileSet resources upgraded to new format
- ✓ Physics layers configured (if used)
- ✓ Navigation layers configured (if used)
- ✓ Custom data preserved (if any)
- ✓ All scenes load without errors
- ✓ Runtime behavior identical

---

## Common Issues & Solutions

### Issue 1: Layer index confusion

**Problem:** Old code used layer indices (0, 1, 2)

**Solution:** Replace with explicit layer references
```gdscript
# Before
tilemap.set_cell(0, coords, tile)  # Layer 0

# After
ground_layer.set_cell(coords, tile)  # Named layer
```

### Issue 2: Bulk cell updates

**Problem:** `update_bitmask_region()` no longer exists

**Solution:** Use terrain system or set_cells_terrain_connect()
```gdscript
# Before
for x in range(width):
    for y in range(height):
        tilemap.set_cell(0, Vector2i(x, y), source_id)
tilemap.update_bitmask_region(Rect2i(0, 0, width, height))

# After
var coords_array = []
for x in range(width):
    for y in range(height):
        coords_array.append(Vector2i(x, y))
ground_layer.set_cells_terrain_connect(coords_array, 0, source_id)
```

### Issue 3: Cell coordinate systems

**Problem:** Coordinate system differences between TileMap and TileMapLayer

**Solution:** Both use Vector2i, but ensure local vs global coordinates
```gdscript
# Both work similarly
var local_coords = tilemap.local_to_map(position)  # Legacy
var local_coords = layer.local_to_map(position)    # New
```

---

## Rollback Procedure

If migration causes issues:

```bash
# Find baseline tag
git tag | grep "tilemap-v1-baseline"

# Reset to pre-migration
git reset --hard <baseline-tag>

# Or restore individual scene from backup
cp scene.tscn.backup scene.tscn
```

---

## Godot Version Requirements

**Minimum:** Godot 4.3+

**Check version:**
```bash
godot --version
# Should show 4.3 or higher
```

**Upgrade notes:**
- Open project in Godot 4.3 first (converts project.godot)
- Then run this migration skill
- Test thoroughly before committing

---

## Integration with Other Skills

**Use with:**
- `godot-modernize-gdscript` - Update syntax before TileMap migration
- `godot-refactor` - Clean up code after migration
- `godot-setup-navigation` - Configure navigation on new TileMapLayer

**Best practice workflow:**
1. Run godot-modernize-gdscript (update syntax)
2. Run godot-migrate-tilemap (this skill)
3. Run godot-refactor (clean architecture)
4. Manual testing in Godot 4.3+

---

**This skill handles the complex TileMap API changes in Godot 4.3, preserving your level data while upgrading to the modern TileMapLayer system.**

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.