Expert blueprint for procedural content generation (dungeons, terrain, loot, levels) using FastNoiseLite, random walks, BSP trees, Wave Function Collapse, and seeded randomization. Use when creating roguelikes, sandbox games, or dynamic content. Keywords procedural, generation, FastNoiseLite, Perlin noise, BSP, drunkard walk, Wave Function Collapse, seeding.
Seeded algorithms, noise functions, and constraint propagation define replayable content generation.
Advanced usage of FastNoiseLite with image-based sampling for maximum performance.
The classic 4-5 rule implementation for organic cave and terrain generation.
Blue-noise distribution algorithm for non-clumping object and enemy placement.
Expert pattern for offloading procedural generation to the WorkerThreadPool.
Lightweight algorithm for generating winding paths, tunnels, and rivers.
Implementing the Marching Squares algorithm for smooth contouring and influential maps.
Binary Space Partitioning for generating structured, non-overlapping floor plans.
Foundation for Wave Function Collapse (WFC) using entropy-based adjacency rules.
Runtime 3D terrain generation using ArrayMesh and SurfaceTool with LOD potential.
L-System string grammar for procedural plant and tree growth in 3D.
Expert Wave Function Collapse implementation with tile adjacency rules.
WorkerThreadPool or a background Thread to keep the UI responsive.FastNoiseLite every frame — Sampling noise per frame (especially in _process) is a massive waste. Generate your map into an Image or Array once and sample from memory [NoiseSampling].randi() for reproducible seeds — Always store and reuse a specific seed within your random number generator (RandomNumberGenerator.new()) to ensure consistent world generation.max_iterations safety break.add_child().TileMap.set_cell() for large-scale updates — Updating 10,000 cells individually is slow. Prepare a TileMapPattern and use set_pattern() or set_cells_terrain_connect() for batch updates.func generate_dungeon(width: int, height: int, fill_percent: float = 0.4) -> Array:
var grid := []
for y in height:
var row := []
for x in width:
row.append(1) # 1 = wall
grid.append(row)
# Start in center
var x := width / 2
var y := height / 2
var floor_tiles := 0
var target_floor := int(width * height * fill_percent)
while floor_tiles < target_floor:
if grid[y][x] == 1:
grid[y][x] = 0 # Create floor
floor_tiles += 1
# Random walk
var dir := randi() % 4
match dir:
0: x = clampi(x + 1, 0, width - 1)
1: x = clampi(x - 1, 0, width - 1)
2: y = clampi(y + 1, 0, height - 1)
3: y = clampi(y - 1, 0, height - 1)
return grid
var noise := FastNoiseLite.new()
func generate_terrain(width: int, height: int) -> Array:
noise.seed = randi()
noise.frequency = 0.05
var terrain := []
for y in height:
var row := []
for x in width:
var value := noise.get_noise_2d(x, y)
# Map noise to tile types
var tile: int
if value < -0.2:
tile = 0 # Water
elif value < 0.2:
tile = 1 # Grass
else:
tile = 2 # Mountain
row.append(tile)
terrain.append(row)
return terrain
class_name BSPRoom
var x: int
var y: int
var width: int
var height: int
var left: BSPRoom = null
var right: BSPRoom = null
func split(min_size: int = 6) -> bool:
if left or right:
return false # Already split
# Choose split direction
var split_horizontal := randf() > 0.5
if width > height and float(width) / float(height) >= 1.25:
split_horizontal = false
elif height > width and float(height) / float(width) >= 1.25:
split_horizontal = true
var max := (height if split_horizontal else width) - min_size
if max <= min_size:
return false # Too small
var split_pos := randi_range(min_size, max)
if split_horizontal:
left = BSPRoom.new()
left.x = x
left.y = y
left.width = width
left.height = split_pos
right = BSPRoom.new()
right.x = x
right.y = y + split_pos
right.width = width
right.height = height - split_pos
else:
left = BSPRoom.new()
left.x = x
left.y = y
left.width = split_pos
left.height = height
right = BSPRoom.new()
right.x = x + split_pos
right.y = y
right.width = width - split_pos
right.height = height
return true
func generate_bsp_dungeon(width: int, height: int, iterations: int = 4) -> Array[BSPRoom]:
var root := BSPRoom.new()
root.x = 0
root.y = 0
root.width = width
root.height = height
var rooms: Array[BSPRoom] = [root]
for i in iterations:
var new_rooms: Array[BSPRoom] = []
for room in rooms:
if room.split():
new_rooms.append(room.left)
new_rooms.append(room.right)
else:
new_rooms.append(room)
rooms = new_rooms
return rooms
func generate_loot(loot_level: int) -> Array[Item]:
var items: Array[Item] = []
var roll_count := randi_range(1, 3)
for i in roll_count:
var rarity := roll_rarity()
var item := get_random_item(rarity, loot_level)
items.append(item)
return items
func roll_rarity() -> String:
var roll := randf()
if roll < 0.6:
return "common"
elif roll < 0.85:
return "uncommon"
elif roll < 0.95:
return "rare"
else:
return "legendary"
# Simplified WFC for tile patterns
# Load compatible tile adjacency rules
var tile_rules := {
"grass": ["grass", "path", "water_edge"],
"water": ["water", "water_edge"],
"path": ["grass", "path"]
}
func wfc_generate(width: int, height: int) -> Array:
var grid := []
for y in height:
var row := []
for x in width:
row.append(null) # Uncollapsed
grid.append(row)
# Collapse cells until complete
while has_uncollapsed(grid):
var pos := find_lowest_entropy(grid)
collapse_cell(grid, pos)
propagate_constraints(grid, pos)
return grid
godot-tilemap-mastery, godot-resource-data-patterns