Quick answer: Godot terrain auto-painting fails when tiles have missing or incorrect peering bit assignments in the TileSet editor. Every tile in your terrain set must have its neighbour bits explicitly assigned — importing a tileset image does not configure bits automatically. Match your terrain mode (Corners and Sides / Sides Only / Corners Only) to the number of tile variants in your set.
You import a beautiful tileset, set up a terrain, select the Terrain Paint tool, drag across your TileMapLayer — and get a scattered mess of wrong tiles, blank cells, or the same tile repeated everywhere. Godot’s terrain system is powerful but uniquely unintuitive to set up: it requires manual configuration of a peering bit mask for every single tile in the terrain, and the editor gives you no warning when those bits are missing. Understanding what peering bits are and how to assign them correctly unlocks the auto-tiling system and makes procedural level painting trivial.
What Are Peering Bits?
A peering bit is a single flag on a terrain tile that describes which of its neighbours it expects to share the same terrain. Godot uses a bit mask with up to 8 positions — one for each side (top, bottom, left, right) and one for each corner (top-left, top-right, bottom-left, bottom-right). When the terrain solver places a tile at a cell, it reads the terrain IDs of all 8 neighbouring cells and finds the tile whose peering bit pattern best matches that neighbourhood.
If a tile has no peering bits assigned at all, the solver treats it as having no neighbour requirements — which means it matches everything and nothing at the same time. The result is random-looking tile selection or empty cells where no match is found.
The fundamental principle: peering bits must be set manually in the TileSet editor for every tile that participates in a terrain. Importing a PNG, slicing it into tiles, and assigning tiles to a terrain is not enough — you must also open each tile and set its bit mask.
Understanding the Three Terrain Modes
Each terrain set in the TileSet resource has a terrain mode that determines which bits are used for matching. Choosing the wrong mode for your tileset is one of the most common causes of incorrect auto-painting:
- Match Corners and Sides: Uses all 8 bits. Best for full 47-tile or 16-tile autotile sets where you have distinct tile graphics for each combination of corner and side neighbours. This is the correct mode for most ground/grass/water tilesets where the corners visually blend between adjacent terrain types.
- Match Sides Only: Uses only the 4 cardinal bits (top, right, bottom, left). Ignores corners. Use this for tilesets with only 16 or fewer variations that don’t have corner blending. If you use this mode with a tileset that has corner tiles, those corner tiles will never be selected.
- Match Corners Only: Uses only the 4 diagonal bits. Rarely needed; used for overlay tilesets like decorative detail layers.
“If your terrain mode uses 8 bits but your tileset only has 16 tile variants, most neighbourhood configurations will have no valid match and the solver will leave those cells empty or fall back to the closest available tile.”
Assigning Peering Bits in the TileSet Editor
To assign peering bits, open the TileSet resource (select the TileMapLayer node, then click the TileSet property to open the editor at the bottom of the screen). Navigate to the Select tab, click on a tile, and look at the Terrain section in the Inspector on the right side.
Each tile shows the terrain set it belongs to and an 8-bit grid representing its neighbours. Click each bit to toggle whether that direction expects a same-terrain neighbour. For a standard ground tile that connects to other ground tiles on all sides and corners, all 8 bits should be set to the same terrain. For an edge tile (top edge of a ground area), the bottom and bottom-corner bits connect to terrain, and the top bits do not.
# Terrain bit constants in Godot 4 (TileSet class)
# These correspond to positions in the peering bit mask:
TileSet.CELL_NEIGHBOR_RIGHT_SIDE # bit 0
TileSet.CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER # bit 1
TileSet.CELL_NEIGHBOR_BOTTOM_SIDE # bit 2
TileSet.CELL_NEIGHBOR_BOTTOM_LEFT_CORNER # bit 3
TileSet.CELL_NEIGHBOR_LEFT_SIDE # bit 4
TileSet.CELL_NEIGHBOR_TOP_LEFT_CORNER # bit 5
TileSet.CELL_NEIGHBOR_TOP_SIDE # bit 6
TileSet.CELL_NEIGHBOR_TOP_RIGHT_CORNER # bit 7
The visual editor shows these as a ring of clickable arrows and dots around the tile preview. Blue means “this side connects to my terrain”; empty means “this side does not connect.” For a 47-tile RPG-style ground set, you need to set the bits for all 47 tiles individually — there is no auto-assign feature.
Using the Select Tool to Diagnose Bad Tiles
When terrain painting goes wrong, the fastest diagnostic is to use the Select tool (not the Terrain Paint tool) to click on individual cells in the TileMapLayer. The inspector shows which exact tile was placed, which terrain set it belongs to, and which peering bits are set. Compare the selected tile’s bits against the actual neighbourhood pattern of that cell.
Common patterns to look for:
- A tile with no bits set at all was placed: the terrain solver chose it because it has no requirements, meaning it appears to match every neighbourhood by default. Fix: assign the correct bits to that tile.
- A tile with only side bits set is placed at a corner: the terrain mode is “Match Sides Only” but the tileset was designed for “Match Corners and Sides”. Fix: change the terrain mode.
- A cell is empty after painting: no tile in the set matches the exact neighbourhood configuration. Fix: either add the missing tile variant or relax the peering bits on nearby tiles so the solver has a fallback.
Importing a Tileset Does Not Configure Terrain Automatically
This is the single most common misconception about Godot’s terrain system. When you drag a tileset PNG into the TileSet editor and use Setup Atlas to slice it, Godot creates tile entries and assigns atlas coordinates, but leaves all terrain data completely blank. Even if you then go to Terrains and add a terrain set and assign each tile’s terrain colour, the peering bits on every tile remain unset.
There is no import option, no auto-detect from tile image contents, and no bulk assignment tool built into the editor (as of Godot 4.3). You must click into each tile in the Select mode and set the bits. For a 47-tile full autotile set, plan for roughly 15–30 minutes of manual bit assignment the first time you set up a terrain from a new image.
Some community tools and addons (such as “Terrainy” or terrain JSON importers) can automate bit assignment if your tileset follows a known layout convention. These are worth investigating for projects with many terrain sets.
To verify at runtime that peering bits are stored correctly on a tile, you can inspect them from GDScript before painting:
# Inspect peering bits on a specific tile to confirm configuration
func debug_tile_peering(source_id: int, atlas_coord: Vector2i) -> void:
var tile_set: TileSet = tile_map_layer.tile_set
var tile_data: TileData = tile_set.get_source(source_id).get_tile_data(
atlas_coord, 0
)
var terrain_set_index := tile_data.terrain_set
print("Terrain set: %d, Terrain: %d" % [
terrain_set_index,
tile_data.terrain
])
# Check each neighbour direction
for bit in TileSet.CELL_NEIGHBOR_RIGHT_SIDE:
var peering := tile_data.get_terrain_peering_bit(bit)
print(" bit %d => terrain %d" % [bit, peering])
Scripted Terrain Painting with TileMapLayer
Once peering bits are correctly configured, you can paint terrain from GDScript using the same solver the editor paint tool uses. This is the API for procedural level generation, dungeon generation, and runtime map editing:
extends TileMapLayer
func paint_terrain_area(
top_left: Vector2i,
size: Vector2i,
terrain_set: int,
terrain: int
) -> void:
var cells: Array[Vector2i] = []
for y in range(size.y):
for x in range(size.x):
cells.append(top_left + Vector2i(x, y))
# set_cells_terrain_connect selects and places tiles using the terrain solver
set_cells_terrain_connect(
cells,
terrain_set, # index of the terrain set in the TileSet
terrain, # terrain index within that set (0, 1, 2 ...)
false # ignore_empty_terrains: false = also update borders
)
The set_cells_terrain_connect method handles border updating automatically — it also re-evaluates the cells adjacent to your painted area so edge tiles update correctly. Pass true for ignore_empty_terrains only if you want to paint terrain into a region that already has terrain and don’t want the empty cells adjacent to it to be changed. For procedural generation, false is almost always what you want.
If terrain painting still looks wrong after correct bit assignment, add the following to your debug flow: call get_cell_tile_data(coord) on a mispainted cell and inspect its terrain and terrain_peering_bits properties at runtime. This confirms whether the solver selected the right tile or fell back to a default, and gives you the exact bit mismatch to fix in the TileSet editor. Reporting these mismatches systematically — with a screenshot and cell coordinates — through a bug tracker like Bugnet is the fastest way to communicate tileset problems to a collaborating level designer.
The terrain solver is only as smart as the bits you give it — every unset bit is a question it can’t answer.