Quick answer: Make sure your terrain set’s mode matches your tile layout (use “Match Corners and Sides” for standard terrain tiles), verify that every peering bit on every tile is assigned to the correct terrain, and check that you haven’t left any peering bits unset — unset bits act as “don’t care” and cause unexpected matches.

You’ve painstakingly set up terrain tiles in Godot’s TileSet editor, configured what you think are the right peering bits, and started painting on your TileMap. But the autotiler keeps placing the wrong tiles — straight edges where there should be corners, grass tiles in the middle of water, or completely blank cells where a tile should appear. The terrain system in Godot 4.x is powerful, but its peering bit configuration is unforgiving when even one bit is wrong.

Understanding Terrain Modes

The first thing to check is your terrain set’s mode. This setting is in the TileSet editor under the Terrains tab, and it determines which peering bits the autotiler considers when matching tiles. There are three modes:

If your tileset was designed for 8-bit (corners and sides) autotiling but you’ve set the mode to “Match Sides,” the engine will ignore all corner peering bits. This means tiles with different corner configurations will be treated as identical, and the autotiler will pick randomly between them. The result looks like a jumbled mess of correct and incorrect corner pieces.

Check your tileset’s documentation or count the tiles: a full 8-bit terrain set has 47 unique tiles (or 48 with an empty center). A 4-bit side-only set has 16 tiles. If your tileset has around 47 tiles, use “Match Corners and Sides.”

Auditing Peering Bits

The most tedious but important step is verifying that every peering bit on every tile is correct. In the TileSet editor, select a tile, go to the Terrains section in the paint properties, and check each directional bit.

Common peering bit mistakes:

Unset bits: An unset peering bit means “this direction doesn’t matter.” If you forget to set the “top” peering bit on a tile that should only appear when the tile above is the same terrain, the autotiler will place that tile regardless of what’s above it. Always set every peering bit to either your terrain type or leave it explicitly empty (no terrain) — never leave bits in an ambiguous state.

Swapped corners: The corner peering bits in Godot refer to the corner of the cell, not the corner of the visual tile. For a tile in the top-left corner of a terrain patch, the top-left peering bit should be set to “no terrain” (the empty area), and the bottom-right peering bit should be set to your terrain. It’s easy to get these backwards.

Wrong terrain assignment: If you have multiple terrains (grass, dirt, water), make sure each tile’s peering bits reference the correct terrain. A grass-to-dirt transition tile should have some bits set to “grass” and others to “dirt,” not all set to “grass.”

A systematic approach: start with the center tile (all bits set to your terrain), verify it works, then work outward to edges, then corners. Test each tile individually before testing complex patterns.

Debugging with a Test TileMap

When terrain matching seems broken, isolate the problem by creating a fresh TileMap node in a test scene. Paint a simple 3×3 block of terrain. If the center tile, edge tiles, and corner tiles all appear correctly, your TileSet is configured properly and the issue is with your existing TileMap data.

Existing TileMaps can get into a bad state if you change the TileSet configuration after painting. When you modify peering bits on existing tiles, the painted TileMap data isn’t automatically updated. You may need to erase and repaint affected areas.

# Script to force a terrain update on an existing TileMap
# Attach to your TileMap node and run once
func _ready():
    var used_cells = get_used_cells(0)  # Layer 0
    for cell in used_cells:
        var data = get_cell_tile_data(0, cell)
        if data:
            # Force terrain reconnection by setting the cell again
            set_cells_terrain_connect(0, [cell], 0, 0)
    print("Refreshed ", used_cells.size(), " cells")

Note: set_cells_terrain_connect re-evaluates terrain matching for the specified cells. The third parameter is the terrain set index and the fourth is the terrain index within that set.

Probability and Alternative Tiles

If your terrain tiles have visual variations (e.g., three different grass center tiles for visual variety), you need to set them up as alternative tiles with the same peering bit configuration but different probability values.

In the TileSet editor:

  1. Select the base tile for the variation.
  2. Add an alternative tile (click the + icon in the tile’s alternatives).
  3. Set the alternative’s art to your variation.
  4. Copy the exact same peering bits from the base tile to the alternative.
  5. Set the probability for each alternative. Higher values mean that tile is chosen more often.

A common mistake is creating separate tiles for variations instead of using the alternative tile system. Separate tiles with the same peering bits confuse the autotiler — it has no way to know they’re variations and may cycle through them unpredictably. Alternatives with probability values give you controlled randomization.

# Verify terrain configuration in code
func _ready():
    var tileset = $TileMap.tile_set
    var source = tileset.get_source(0) as TileSetAtlasSource
    var terrain_set = 0

    for y in range(source.get_atlas_grid_size().y):
        for x in range(source.get_atlas_grid_size().x):
            var coords = Vector2i(x, y)
            if not source.has_tile(coords):
                continue
            var data = source.get_tile_data(coords, 0)
            var terrain = data.get_terrain(terrain_set)
            print("Tile ", coords, " terrain: ", terrain,
                  " bits: ", _get_peering_bits(data, terrain_set))

func _get_peering_bits(data: TileData, terrain_set: int) -> Dictionary:
    var bits = {}
    for bit in [
        TileSet.CELL_NEIGHBOR_TOP_SIDE,
        TileSet.CELL_NEIGHBOR_BOTTOM_SIDE,
        TileSet.CELL_NEIGHBOR_LEFT_SIDE,
        TileSet.CELL_NEIGHBOR_RIGHT_SIDE,
    ]:
        bits[bit] = data.get_terrain_peering_bit(bit)
    return bits

When the Editor Itself Is the Problem

Occasionally, the TileSet editor in Godot 4.x has display bugs where peering bits appear set in the UI but aren’t saved correctly to the resource file. If you’ve verified everything visually and tiles still don’t match, try these steps:

If your terrain autotiling works in a fresh test scene but not in your main scene, the problem is almost always stale TileMap data, not the TileSet itself.