Skip to content
godot-migrate-tilemap logo

Godot TileMap V2 Migration

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 upgrad...

SKILL.md

Full skill instructions

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 nodeMultiple TileMapLayer nodes
set_cell() methodset_cells_terrain_connect()
Cell-based coordinatesLayer-based organization
Single TileSet resourceEnhanced TileSet with layers
update_bitmask_region()Terrain system
Manual physics setupPhysics 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:

  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:

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 APINew 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:

  1. Backup scene file

    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

    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

# 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_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

# 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 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.

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View