Agent skill
godot-migrate-tilemap
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+.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/godot-migrate-tilemap
SKILL.md
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)
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)
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
# 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:
# 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:
[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:
[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:
-
Parse legacy TileMap
- Extract layer names
- Extract layer data
- Extract TileSet reference
- Extract position/z-index
-
Generate TileMapLayer nodes
- One node per layer
- Name from layer name
- Convert tile_data format
- Preserve TileSet reference
-
Update scene hierarchy
- Remove TileMap node
- Add TileMapLayer children
- Update parent references
2.2 Tile Data Conversion
Legacy Format:
layer_0/tile_data = PackedInt32Array(0, 1, 0, 65536, 1, 0, ...)
New Format:
tile_map_data = PackedByteArray(0, 0, 0, 0, 1, 0, 0, 0, ...)
Note: Direct byte conversion requires Godot's internal format knowledge. Alternative approach:
# 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:
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:
# 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:
# 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:
var source_id = tilemap.get_cell_source_id(0, coords)
var atlas_coords = tilemap.get_cell_atlas_coords(0, coords)
After:
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:
tilemap.set_cell(0, coords, 1)
tilemap.update_bitmask_region(Rect2i(0, 0, 20, 20))
After:
# 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
# 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
# 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
# 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
# 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:
-
Backup scene file
bashcp scene.tscn scene.tscn.backup -
Parse TileMap data
- Extract layers
- Extract tile data
- Note TileSet reference
-
Generate TileMapLayer nodes
- Create node entries
- Convert data format
- Set properties
-
Update scripts
- Replace TileMap references
- Update method calls
- Fix signal connections
-
Commit changes
bashgit 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
# 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
# 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
# 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
# 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):
# 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):
# 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:
# 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:
# 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_bitmaskcalls 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
# 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()
# 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
# 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:
# 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:
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 migrationgodot-refactor- Clean up code after migrationgodot-setup-navigation- Configure navigation on new TileMapLayer
Best practice workflow:
- Run godot-modernize-gdscript (update syntax)
- Run godot-migrate-tilemap (this skill)
- Run godot-refactor (clean architecture)
- 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.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?