Loading...
Loading...
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.
npx skill4agent add thedivergentai/gd-agentic-skills godot-procedural-generationrandi()seed(hash(Time.get_ticks_msec()))randf()_ready()_ready()_ready()min_size_ready()awaitfunc 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 gridvar 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 terrainclass_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 roomsfunc 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 gridgodot-tilemap-masterygodot-resource-data-patterns