extends Node3D # First-person demo. Generates a grid of chunks (each a 79×29 dungeon) times # level_count stacked layers. Default is 1×1 chunks × 3 levels. Bump # chunks_x / chunks_y to stress-test the renderer with larger worlds. const T_NOTHING := 0 const T_FLOOR := 1 const T_WALL := 2 const T_DOOR := 3 const T_CORRIDOR := 4 const T_LIQUID := 5 const T_BRIDGE := 6 const T_STAIRS_UP := 7 const T_STAIRS_DOWN := 8 const L_WATER := 1 const L_LAVA := 2 const L_CHASM := 3 const L_BRIMSTONE := 4 const TILE_FLOOR := 0 const TILE_WALL := 1 const TILE_DOOR := 2 const TILE_CORRIDOR := 3 const TILE_WATER := 4 const TILE_LAVA := 5 const TILE_BRIMSTONE := 6 const TILE_BRIDGE := 7 const TILE_STAIRS_UP := 8 const TILE_STAIRS_DOWN := 9 const CHUNK_W := 79 const CHUNK_H := 29 @export var base_seed: int = 2028 @export var depth_start: int = 20 @export var level_count: int = 3 @export var level_spacing: float = 6.0 @export var chunks_x: int = 1 @export var chunks_y: int = 1 @export var player_spawn_height: float = 1.1 @onready var levels_root: Node3D = $Levels @onready var player: CharacterBody3D = $Player @onready var fps_overlay: Node = $FPSOverlay if has_node("FPSOverlay") else null var _mesh_library: MeshLibrary func _ready() -> void: var t0 := Time.get_ticks_msec() _mesh_library = MeshLibraryBuilder.build(true) var total_cells := 0 var total_chunks := 0 var spawn_world := Vector3.ZERO var spawn_found := false for level_index in range(level_count): for cy in range(chunks_y): for cx in range(chunks_x): var seed := base_seed \ + level_index * 1000 \ + cy * chunks_x + cx var depth := depth_start + level_index var gen := BrogueGen.new() var grid: Dictionary = gen.generate(seed, depth) gen.free() var grid_map := GridMap.new() grid_map.name = "L%d_C%d_%d" % [level_index, cx, cy] grid_map.mesh_library = _mesh_library grid_map.cell_size = Vector3(1, 1, 1) grid_map.position = Vector3( cx * CHUNK_W, -level_index * level_spacing, cy * CHUNK_H ) levels_root.add_child(grid_map) var cells := _populate_level(grid_map, grid) total_cells += cells total_chunks += 1 # First up-stair on level 0, chunk (0,0) is the spawn point. if not spawn_found and level_index == 0 and cx == 0 and cy == 0: var up: Vector2i = grid["stairs_up"] as Vector2i if up.x >= 0: spawn_world = Vector3(up.x, player_spawn_height, up.y) spawn_found = true if not spawn_found: spawn_world = Vector3(CHUNK_W * 0.5, player_spawn_height, CHUNK_H * 0.5) player.position = spawn_world var build_ms := Time.get_ticks_msec() - t0 var info := "%d chunks (%dx%d x %d lvls) %d placed cells build=%d ms" % [ total_chunks, chunks_x, chunks_y, level_count, total_cells, build_ms, ] print(info) print("Player spawned at %s" % spawn_world) if fps_overlay and fps_overlay.has_method("set_subtitle"): fps_overlay.set_subtitle(info) # Place every non-chasm cell into the GridMap. Returns the number of cells # actually placed (excludes T_NOTHING and chasms). func _populate_level(grid_map: GridMap, grid: Dictionary) -> int: var w: int = grid["width"] var h: int = grid["height"] var terrain: PackedByteArray = grid["terrain"] var liquid: PackedByteArray = grid["liquid"] var placed := 0 for y in range(h): for x in range(w): var idx := y * w + x var t: int = terrain[idx] var liq: int = liquid[idx] if t == T_LIQUID and liq == L_CHASM: continue var tile_id := _tile_for(t, liq) if tile_id == -1: continue grid_map.set_cell_item(Vector3i(x, 0, y), tile_id) placed += 1 return placed func _tile_for(terrain: int, liquid: int) -> int: match terrain: T_FLOOR: return TILE_FLOOR T_CORRIDOR: return TILE_CORRIDOR T_DOOR: return TILE_DOOR T_WALL: return TILE_WALL T_BRIDGE: return TILE_BRIDGE T_STAIRS_UP: return TILE_STAIRS_UP T_STAIRS_DOWN: return TILE_STAIRS_DOWN T_LIQUID: match liquid: L_WATER: return TILE_WATER L_LAVA: return TILE_LAVA L_BRIMSTONE: return TILE_BRIMSTONE _: return TILE_WATER _: return -1