Fixes room spawning and adds physical doors and indicator lights
This commit is contained in:
@@ -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="."]
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+43
-2
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user