From b709b64a523e6a4f4d9ab1c441c242321deee737 Mon Sep 17 00:00:00 2001 From: Mike McGhen Date: Tue, 10 Mar 2026 11:16:48 -0400 Subject: [PATCH] Fixes room spawning and adds physical doors and indicator lights --- scenes/run/rooms/room_base.tscn | 2 + scripts/rooms/door.gd | 113 +++++++++++++++++++++++++++++++ scripts/rooms/floor.gd | 8 +++ scripts/rooms/floor_generator.gd | 8 ++- scripts/rooms/room.gd | 45 +++++++++++- scripts/rooms/room_data.gd | 1 + 6 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 scripts/rooms/door.gd diff --git a/scenes/run/rooms/room_base.tscn b/scenes/run/rooms/room_base.tscn index 6bdcd18..57a77a3 100644 --- a/scenes/run/rooms/room_base.tscn +++ b/scenes/run/rooms/room_base.tscn @@ -13,4 +13,6 @@ color = Color(0.12, 0.12, 0.18, 1) [node name="DoorTriggers" type="Node2D" parent="."] +[node name="Doors" type="Node2D" parent="."] + [node name="Contents" type="Node2D" parent="."] diff --git a/scripts/rooms/door.gd b/scripts/rooms/door.gd new file mode 100644 index 0000000..e81ee76 --- /dev/null +++ b/scripts/rooms/door.gd @@ -0,0 +1,113 @@ +extends Node2D +class_name RoomDoor + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- +const DOOR_THICKNESS := 12.0 +const INDICATOR_SIZE := 10.0 +const INDICATOR_OFFSET := 20.0 # distance above door + +# Indicator light colors (brighter versions of room floor colors) +const INDICATOR_COLORS := { + RoomData.RoomType.START: Color(0.3, 0.3, 0.5), # blue-gray + RoomData.RoomType.COMBAT: Color(0.35, 0.35, 0.55), # blue-gray + RoomData.RoomType.ITEM: Color(0.2, 0.5, 0.2), # green + RoomData.RoomType.SHOP: Color(0.6, 0.45, 0.2), # gold/amber + RoomData.RoomType.BOSS: Color(0.7, 0.15, 0.15), # red +} + +# --------------------------------------------------------------------------- +# State +# --------------------------------------------------------------------------- +var direction: String = "" # "up", "down", "left", "right" +var door_size: Vector2 = Vector2.ZERO +var adjacent_room_type: RoomData.RoomType = RoomData.RoomType.COMBAT + +var _barrier: StaticBody2D = null +var _barrier_collision: CollisionShape2D = null +var _barrier_visual: Polygon2D = null +var _indicator: Polygon2D = null +var _is_locked: bool = false + +# --------------------------------------------------------------------------- +# Setup +# --------------------------------------------------------------------------- +func setup(dir: String, size: Vector2, adj_type: RoomData.RoomType) -> void: + direction = dir + door_size = size + adjacent_room_type = adj_type + + _build_barrier() + _build_indicator() + + # Start unlocked (open) + unlock() + + +func _build_barrier() -> void: + _barrier = StaticBody2D.new() + _barrier.collision_layer = 1 # world layer - blocks player + _barrier.collision_mask = 0 + + _barrier_collision = CollisionShape2D.new() + var shape := RectangleShape2D.new() + shape.size = door_size + _barrier_collision.shape = shape + _barrier.add_child(_barrier_collision) + + # Visual - solid rectangle + _barrier_visual = Polygon2D.new() + var hx := door_size.x / 2.0 + var hy := door_size.y / 2.0 + _barrier_visual.polygon = PackedVector2Array([ + Vector2(-hx, -hy), Vector2(hx, -hy), + Vector2(hx, hy), Vector2(-hx, hy), + ]) + _barrier_visual.color = Color(0.4, 0.35, 0.3) # metallic brown + _barrier.add_child(_barrier_visual) + + add_child(_barrier) + + +func _build_indicator() -> void: + _indicator = Polygon2D.new() + + # Small diamond shape for indicator + var s := INDICATOR_SIZE + _indicator.polygon = PackedVector2Array([ + Vector2(0, -s), Vector2(s, 0), + Vector2(0, s), Vector2(-s, 0), + ]) + + # Position based on door direction + var offset := Vector2.ZERO + match direction: + "up": offset = Vector2(0, -door_size.y / 2.0 - INDICATOR_OFFSET) + "down": offset = Vector2(0, door_size.y / 2.0 + INDICATOR_OFFSET) + "left": offset = Vector2(-door_size.x / 2.0 - INDICATOR_OFFSET, 0) + "right": offset = Vector2(door_size.x / 2.0 + INDICATOR_OFFSET, 0) + + _indicator.position = offset + _indicator.color = INDICATOR_COLORS.get(adjacent_room_type, INDICATOR_COLORS[RoomData.RoomType.COMBAT]) + + add_child(_indicator) + + +# --------------------------------------------------------------------------- +# Lock/Unlock +# --------------------------------------------------------------------------- +func lock() -> void: + _is_locked = true + _barrier_collision.disabled = false + _barrier_visual.visible = true + + +func unlock() -> void: + _is_locked = false + _barrier_collision.disabled = true + _barrier_visual.visible = false + + +func is_locked() -> bool: + return _is_locked diff --git a/scripts/rooms/floor.gd b/scripts/rooms/floor.gd index d495e01..4c19d56 100644 --- a/scripts/rooms/floor.gd +++ b/scripts/rooms/floor.gd @@ -90,3 +90,11 @@ func _entry_offset(from_direction: String) -> Vector2: # --------------------------------------------------------------------------- func _grid_to_world(grid_pos: Vector2i) -> Vector2: return Vector2(grid_pos.x * ROOM_W, grid_pos.y * ROOM_H) + + +# Returns the RoomData.RoomType for the room at the given grid position. +# Returns -1 if no room exists at that position. +func get_room_type_at(grid_pos: Vector2i) -> int: + if _rooms.has(grid_pos): + return _rooms[grid_pos].data.type + return -1 diff --git a/scripts/rooms/floor_generator.gd b/scripts/rooms/floor_generator.gd index a81b05b..c45b2a0 100644 --- a/scripts/rooms/floor_generator.gd +++ b/scripts/rooms/floor_generator.gd @@ -3,9 +3,9 @@ class_name FloorGenerator const GRID_START := Vector2i(5, 5) const FLOOR_ROOM_COUNTS := { - 1: {"min": 5, "max": 6}, # 4-5 combat + start + boss - 2: {"min": 6, "max": 7}, # 5-6 combat + start + boss - 3: {"min": 3, "max": 4}, # 2-3 combat + start + boss + 1: {"min": 8, "max": 9}, # 4-5 combat + start + boss + item + shop + 2: {"min": 9, "max": 10}, # 5-6 combat + start + boss + item + shop + 3: {"min": 6, "max": 7}, # 2-3 combat + start + boss + item + shop } const DIRS := { @@ -29,6 +29,7 @@ static func generate(floor_number: int) -> Array: var start := RoomData.new() start.type = RoomData.RoomType.START start.grid_pos = GRID_START + start.id = "%d_%d" % [GRID_START.x, GRID_START.y] rooms[GRID_START] = start var queue: Array = [GRID_START] @@ -59,6 +60,7 @@ static func generate(floor_number: int) -> Array: var r := RoomData.new() r.type = RoomData.RoomType.COMBAT r.grid_pos = next + r.id = "%d_%d" % [next.x, next.y] rooms[next] = r queue.append(next) diff --git a/scripts/rooms/room.gd b/scripts/rooms/room.gd index e94d617..dd2c4a4 100644 --- a/scripts/rooms/room.gd +++ b/scripts/rooms/room.gd @@ -55,6 +55,7 @@ var data: RoomData = null var _floor: Node = null # reference to floor.gd node var _enemy_count: int = 0 var _doors: Dictionary = {} # direction -> Area2D trigger +var _physical_doors: Dictionary = {} # direction -> RoomDoor # --------------------------------------------------------------------------- # Node refs (set by room_base.tscn) @@ -62,6 +63,7 @@ var _doors: Dictionary = {} # direction -> Area2D trigger @onready var floor_poly: Polygon2D = $Floor @onready var walls_node: Node2D = $Walls @onready var door_triggers: Node2D = $DoorTriggers +@onready var doors_node: Node2D = $Doors @onready var contents: Node2D = $Contents # --------------------------------------------------------------------------- @@ -73,12 +75,13 @@ func setup(room_data: RoomData, floor_ref: Node) -> void: _apply_floor_color() _build_walls() _build_door_triggers() + _build_physical_doors() # --------------------------------------------------------------------------- # Activate — called on first (and repeat) entry # --------------------------------------------------------------------------- func activate() -> void: - EventBus.room_entered.emit(data.id if "id" in data else "") + EventBus.room_entered.emit(data.id) if data.visited: _update_door_locks() return @@ -227,6 +230,35 @@ func _on_door_entered(body: Node, direction: String) -> void: "transition_to", data.connections[direction], direction ) +# --------------------------------------------------------------------------- +# Physical doors with lock barriers and indicator lights +# --------------------------------------------------------------------------- +func _build_physical_doors() -> void: + const DOOR_THICKNESS := 12.0 + var hw := ROOM_W / 2.0 + var hh := ROOM_H / 2.0 + + # Door positions and sizes per direction + var configs := { + "up": {"pos": Vector2(0, -hh + WALL_T / 2.0), "size": Vector2(DOOR_W, DOOR_THICKNESS)}, + "down": {"pos": Vector2(0, hh - WALL_T / 2.0), "size": Vector2(DOOR_W, DOOR_THICKNESS)}, + "left": {"pos": Vector2(-hw + WALL_T / 2.0, 0), "size": Vector2(DOOR_THICKNESS, DOOR_H)}, + "right": {"pos": Vector2(hw - WALL_T / 2.0, 0), "size": Vector2(DOOR_THICKNESS, DOOR_H)}, + } + + for dir in data.connections.keys(): + var cfg = configs[dir] + var adj_grid: Vector2i = data.connections[dir] + var adj_type: int = _floor.get_room_type_at(adj_grid) + if adj_type < 0: + adj_type = RoomData.RoomType.COMBAT # fallback + + var door := RoomDoor.new() + door.position = cfg["pos"] + door.setup(dir, cfg["size"], adj_type as RoomData.RoomType) + doors_node.add_child(door) + _physical_doors[dir] = door + # --------------------------------------------------------------------------- # Enemy spawning # --------------------------------------------------------------------------- @@ -284,7 +316,7 @@ func _on_enemy_died() -> void: _spawn_body_part_drop() _spawn_floor_exit() room_cleared.emit() - EventBus.room_cleared.emit(data.id if "id" in data else "") + EventBus.room_cleared.emit(data.id) _update_door_locks() @@ -512,5 +544,14 @@ func _update_door_locks() -> void: var is_combat := data.type == RoomData.RoomType.COMBAT \ or data.type == RoomData.RoomType.BOSS var locked := data.visited and not data.cleared and is_combat + + # Update door triggers (for transitions) for area in _doors.values(): (area as Area2D).monitoring = not locked + + # Update physical door barriers + for door in _physical_doors.values(): + if locked: + door.lock() + else: + door.unlock() diff --git a/scripts/rooms/room_data.gd b/scripts/rooms/room_data.gd index 13840a6..7075870 100644 --- a/scripts/rooms/room_data.gd +++ b/scripts/rooms/room_data.gd @@ -2,6 +2,7 @@ class_name RoomData enum RoomType { START, COMBAT, ITEM, SHOP, BOSS } +var id: String = "" # unique identifier (e.g., "5_5" from grid pos) var type: RoomType = RoomType.COMBAT var grid_pos: Vector2i = Vector2i.ZERO var connections: Dictionary = {} # "up"/"down"/"left"/"right" -> Vector2i