Implements mini map and updates door lights
This commit is contained in:
@@ -15,6 +15,8 @@ signal floor_cleared(floor_number: int)
|
|||||||
signal room_entered(room_id: String)
|
signal room_entered(room_id: String)
|
||||||
signal room_cleared(room_id: String)
|
signal room_cleared(room_id: String)
|
||||||
signal room_revealed
|
signal room_revealed
|
||||||
|
signal room_entered_at(grid_pos: Vector2i)
|
||||||
|
signal floor_map_ready(rooms_data: Dictionary)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Items & Loot
|
# Items & Loot
|
||||||
|
|||||||
+16
-7
@@ -8,15 +8,20 @@ const DOOR_THICKNESS := 12.0
|
|||||||
const INDICATOR_SIZE := 10.0
|
const INDICATOR_SIZE := 10.0
|
||||||
const INDICATOR_OFFSET := 20.0 # distance above door
|
const INDICATOR_OFFSET := 20.0 # distance above door
|
||||||
|
|
||||||
# Indicator light colors (brighter versions of room floor colors)
|
# Indicator light colors - only for special rooms, matching floor colors but brighter
|
||||||
const INDICATOR_COLORS := {
|
const INDICATOR_COLORS := {
|
||||||
RoomData.RoomType.START: Color(0.3, 0.3, 0.5), # blue-gray
|
RoomData.RoomType.ITEM: Color(0.2, 0.45, 0.2), # green (brighter version of 0.10, 0.16, 0.10)
|
||||||
RoomData.RoomType.COMBAT: Color(0.35, 0.35, 0.55), # blue-gray
|
RoomData.RoomType.SHOP: Color(0.9, 0.75, 0.1), # yellow
|
||||||
RoomData.RoomType.ITEM: Color(0.2, 0.5, 0.2), # green
|
RoomData.RoomType.BOSS: Color(0.7, 0.15, 0.15), # red (brighter version of 0.20, 0.08, 0.08)
|
||||||
RoomData.RoomType.SHOP: Color(0.6, 0.45, 0.2), # gold/amber
|
|
||||||
RoomData.RoomType.BOSS: Color(0.7, 0.15, 0.15), # red
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Room types that should show indicator lights
|
||||||
|
const SPECIAL_ROOM_TYPES := [
|
||||||
|
RoomData.RoomType.ITEM,
|
||||||
|
RoomData.RoomType.SHOP,
|
||||||
|
RoomData.RoomType.BOSS,
|
||||||
|
]
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# State
|
# State
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -71,6 +76,10 @@ func _build_barrier() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _build_indicator() -> void:
|
func _build_indicator() -> void:
|
||||||
|
# Only show indicators for special rooms (ITEM, SHOP, BOSS)
|
||||||
|
if adjacent_room_type not in SPECIAL_ROOM_TYPES:
|
||||||
|
return
|
||||||
|
|
||||||
_indicator = Polygon2D.new()
|
_indicator = Polygon2D.new()
|
||||||
|
|
||||||
# Small diamond shape for indicator
|
# Small diamond shape for indicator
|
||||||
@@ -89,7 +98,7 @@ func _build_indicator() -> void:
|
|||||||
"right": 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.position = offset
|
||||||
_indicator.color = INDICATOR_COLORS.get(adjacent_room_type, INDICATOR_COLORS[RoomData.RoomType.COMBAT])
|
_indicator.color = INDICATOR_COLORS[adjacent_room_type]
|
||||||
|
|
||||||
add_child(_indicator)
|
add_child(_indicator)
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const ENTRY_INSET := 60.0 # how far from wall edge the player appears
|
|||||||
# State
|
# State
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
var _rooms: Dictionary = {} # Vector2i -> Room
|
var _rooms: Dictionary = {} # Vector2i -> Room
|
||||||
|
var _rooms_data: Dictionary = {} # Vector2i -> RoomData (for mini map)
|
||||||
var _current_grid: Vector2i
|
var _current_grid: Vector2i
|
||||||
var _transitioning: bool = false
|
var _transitioning: bool = false
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ func _build_floor(floor_data: Array) -> void:
|
|||||||
rooms_container.add_child(room_node)
|
rooms_container.add_child(room_node)
|
||||||
room_node.setup(room_data, self)
|
room_node.setup(room_data, self)
|
||||||
_rooms[room_data.grid_pos] = room_node
|
_rooms[room_data.grid_pos] = room_node
|
||||||
|
_rooms_data[room_data.grid_pos] = room_data
|
||||||
|
|
||||||
if room_data.type == RoomData.RoomType.START:
|
if room_data.type == RoomData.RoomType.START:
|
||||||
start_pos = room_data.grid_pos
|
start_pos = room_data.grid_pos
|
||||||
@@ -51,6 +53,10 @@ func _build_floor(floor_data: Array) -> void:
|
|||||||
_current_grid = start_pos
|
_current_grid = start_pos
|
||||||
_rooms[start_pos].activate()
|
_rooms[start_pos].activate()
|
||||||
|
|
||||||
|
# Emit signals for mini map
|
||||||
|
EventBus.floor_map_ready.emit(_rooms_data)
|
||||||
|
EventBus.room_entered_at.emit(start_pos)
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Transitions
|
# Transitions
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -59,6 +65,7 @@ func transition_to(target_grid: Vector2i, from_direction: String) -> void:
|
|||||||
return
|
return
|
||||||
_transitioning = true
|
_transitioning = true
|
||||||
_current_grid = target_grid
|
_current_grid = target_grid
|
||||||
|
EventBus.room_entered_at.emit(target_grid)
|
||||||
|
|
||||||
var new_world := _grid_to_world(target_grid)
|
var new_world := _grid_to_world(target_grid)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
extends CanvasLayer
|
extends CanvasLayer
|
||||||
|
|
||||||
|
const MiniMapScript = preload("res://scripts/ui/mini_map.gd")
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Heart geometry — two polygons per slot: background (dark) + fill (red)
|
# Heart geometry — two polygons per slot: background (dark) + fill (red)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -39,6 +41,7 @@ const ORIGIN := Vector2(32, 32) # center of first heart (screen px)
|
|||||||
# Each entry: { "bg": Polygon2D, "fill": Polygon2D }
|
# Each entry: { "bg": Polygon2D, "fill": Polygon2D }
|
||||||
var _slots: Array = []
|
var _slots: Array = []
|
||||||
var _credits_label: Label
|
var _credits_label: Label
|
||||||
|
var _mini_map: Control
|
||||||
|
|
||||||
# DEPRECATED — Boss bar nodes (commented out)
|
# DEPRECATED — Boss bar nodes (commented out)
|
||||||
#var _boss_bar_root: Node2D = null
|
#var _boss_bar_root: Node2D = null
|
||||||
@@ -56,6 +59,7 @@ func _ready() -> void:
|
|||||||
#EventBus.boss_health_changed.connect(_on_boss_health_changed)
|
#EventBus.boss_health_changed.connect(_on_boss_health_changed)
|
||||||
#EventBus.boss_died.connect(_on_boss_died)
|
#EventBus.boss_died.connect(_on_boss_died)
|
||||||
_build_credits_label()
|
_build_credits_label()
|
||||||
|
_build_mini_map()
|
||||||
# Initialise once the scene is fully set up
|
# Initialise once the scene is fully set up
|
||||||
call_deferred("_init_from_player")
|
call_deferred("_init_from_player")
|
||||||
|
|
||||||
@@ -126,6 +130,12 @@ func _build_credits_label() -> void:
|
|||||||
_credits_label.text = "SCRAP: %d" % amount
|
_credits_label.text = "SCRAP: %d" % amount
|
||||||
add_child(_credits_label)
|
add_child(_credits_label)
|
||||||
|
|
||||||
|
|
||||||
|
func _build_mini_map() -> void:
|
||||||
|
_mini_map = Control.new()
|
||||||
|
_mini_map.set_script(MiniMapScript)
|
||||||
|
add_child(_mini_map)
|
||||||
|
|
||||||
func _on_credits_changed(new_total: int) -> void:
|
func _on_credits_changed(new_total: int) -> void:
|
||||||
_credits_label.text = "SCRAP: %d" % new_total
|
_credits_label.text = "SCRAP: %d" % new_total
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Layout constants
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
const MAP_SIZE := Vector2(150, 150)
|
||||||
|
const ROOM_SIZE := Vector2(18, 10) # 16:9 aspect ratio like actual rooms
|
||||||
|
const ROOM_GAP := 4.0
|
||||||
|
const PADDING := 10.0
|
||||||
|
const CONNECTION_WIDTH := 2.0
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Colors (brightened versions of room.gd floor colors)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
const ROOM_COLORS := {
|
||||||
|
RoomData.RoomType.START: Color(0.24, 0.24, 0.36), # blue-grey
|
||||||
|
RoomData.RoomType.COMBAT: Color(0.24, 0.24, 0.36), # blue-grey
|
||||||
|
RoomData.RoomType.ITEM: Color(0.20, 0.32, 0.20), # green
|
||||||
|
RoomData.RoomType.SHOP: Color(0.32, 0.24, 0.16), # brown
|
||||||
|
RoomData.RoomType.BOSS: Color(0.40, 0.16, 0.16), # red
|
||||||
|
}
|
||||||
|
const CURRENT_OUTLINE := Color(1.0, 1.0, 0.4) # bright yellow
|
||||||
|
const CONNECTION_COLOR := Color(0.5, 0.5, 0.6)
|
||||||
|
const UNVISITED_ALPHA := 0.35
|
||||||
|
const BACKGROUND_COLOR := Color(0.08, 0.08, 0.10, 0.85)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# State
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
var _rooms_data: Dictionary = {} # Vector2i -> RoomData
|
||||||
|
var _current_pos: Vector2i = Vector2i.ZERO
|
||||||
|
var _grid_min: Vector2i = Vector2i.ZERO
|
||||||
|
var _grid_max: Vector2i = Vector2i.ZERO
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Setup
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
func _ready() -> void:
|
||||||
|
# Position in top-right corner
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
offset_left = -MAP_SIZE.x - PADDING
|
||||||
|
offset_right = -PADDING
|
||||||
|
offset_top = PADDING
|
||||||
|
offset_bottom = MAP_SIZE.y + PADDING
|
||||||
|
custom_minimum_size = MAP_SIZE
|
||||||
|
|
||||||
|
# Connect signals
|
||||||
|
EventBus.floor_map_ready.connect(_on_floor_map_ready)
|
||||||
|
EventBus.room_entered_at.connect(_on_room_entered)
|
||||||
|
EventBus.run_ended.connect(_on_run_ended)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Signal handlers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
func _on_floor_map_ready(rooms_data: Dictionary) -> void:
|
||||||
|
_rooms_data = rooms_data
|
||||||
|
_compute_grid_bounds()
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_room_entered(grid_pos: Vector2i) -> void:
|
||||||
|
_current_pos = grid_pos
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_run_ended(_reached_hub: bool) -> void:
|
||||||
|
_rooms_data.clear()
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
func _compute_grid_bounds() -> void:
|
||||||
|
if _rooms_data.is_empty():
|
||||||
|
_grid_min = Vector2i.ZERO
|
||||||
|
_grid_max = Vector2i.ZERO
|
||||||
|
return
|
||||||
|
|
||||||
|
var first := true
|
||||||
|
for pos in _rooms_data.keys():
|
||||||
|
if first:
|
||||||
|
_grid_min = pos
|
||||||
|
_grid_max = pos
|
||||||
|
first = false
|
||||||
|
else:
|
||||||
|
_grid_min.x = mini(_grid_min.x, pos.x)
|
||||||
|
_grid_min.y = mini(_grid_min.y, pos.y)
|
||||||
|
_grid_max.x = maxi(_grid_max.x, pos.x)
|
||||||
|
_grid_max.y = maxi(_grid_max.y, pos.y)
|
||||||
|
|
||||||
|
|
||||||
|
func _get_visible_rooms() -> Dictionary:
|
||||||
|
# Returns {Vector2i -> {"data": RoomData, "visited": bool}}
|
||||||
|
var visible := {}
|
||||||
|
var known_positions: Array[Vector2i] = []
|
||||||
|
|
||||||
|
# First pass: collect visited rooms and their adjacent positions
|
||||||
|
for pos in _rooms_data.keys():
|
||||||
|
var room: RoomData = _rooms_data[pos]
|
||||||
|
if room.visited:
|
||||||
|
visible[pos] = {"data": room, "visited": true}
|
||||||
|
for conn_pos in room.connections.values():
|
||||||
|
if conn_pos not in known_positions:
|
||||||
|
known_positions.append(conn_pos)
|
||||||
|
|
||||||
|
# Second pass: add adjacent (known but unvisited) rooms
|
||||||
|
for pos in known_positions:
|
||||||
|
if pos not in visible and _rooms_data.has(pos):
|
||||||
|
visible[pos] = {"data": _rooms_data[pos], "visited": false}
|
||||||
|
|
||||||
|
return visible
|
||||||
|
|
||||||
|
|
||||||
|
func _grid_to_map_pos(grid_pos: Vector2i) -> Vector2:
|
||||||
|
# Convert grid position to local drawing coordinates
|
||||||
|
var cell_size := ROOM_SIZE + Vector2(ROOM_GAP, ROOM_GAP)
|
||||||
|
var grid_size := Vector2i(_grid_max.x - _grid_min.x + 1, _grid_max.y - _grid_min.y + 1)
|
||||||
|
var total_size := Vector2(grid_size.x, grid_size.y) * cell_size - Vector2(ROOM_GAP, ROOM_GAP)
|
||||||
|
|
||||||
|
# Center the map within the control
|
||||||
|
var centering := (MAP_SIZE - total_size) / 2.0
|
||||||
|
var offset := Vector2(
|
||||||
|
(grid_pos.x - _grid_min.x) * cell_size.x,
|
||||||
|
(grid_pos.y - _grid_min.y) * cell_size.y
|
||||||
|
)
|
||||||
|
return centering + offset
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Drawing
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
func _draw() -> void:
|
||||||
|
if _rooms_data.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
# Background panel
|
||||||
|
draw_rect(Rect2(Vector2.ZERO, MAP_SIZE), BACKGROUND_COLOR)
|
||||||
|
|
||||||
|
var visible := _get_visible_rooms()
|
||||||
|
|
||||||
|
# Draw connections first (under rooms)
|
||||||
|
for pos in visible.keys():
|
||||||
|
var room: RoomData = visible[pos]["data"]
|
||||||
|
var room_center := _grid_to_map_pos(pos) + ROOM_SIZE / 2.0
|
||||||
|
for dir in room.connections.keys():
|
||||||
|
var conn_pos: Vector2i = room.connections[dir]
|
||||||
|
if visible.has(conn_pos):
|
||||||
|
var conn_center := _grid_to_map_pos(conn_pos) + ROOM_SIZE / 2.0
|
||||||
|
# Only draw each connection once (from lower to higher grid pos)
|
||||||
|
if pos.x < conn_pos.x or (pos.x == conn_pos.x and pos.y < conn_pos.y):
|
||||||
|
draw_line(room_center, conn_center, CONNECTION_COLOR, CONNECTION_WIDTH)
|
||||||
|
|
||||||
|
# Draw rooms
|
||||||
|
for pos in visible.keys():
|
||||||
|
var info: Dictionary = visible[pos]
|
||||||
|
var room: RoomData = info["data"]
|
||||||
|
var is_visited: bool = info["visited"]
|
||||||
|
var map_pos := _grid_to_map_pos(pos)
|
||||||
|
var rect := Rect2(map_pos, ROOM_SIZE)
|
||||||
|
|
||||||
|
# Room color with alpha based on visited state
|
||||||
|
var color: Color = ROOM_COLORS.get(room.type, ROOM_COLORS[RoomData.RoomType.COMBAT])
|
||||||
|
if not is_visited:
|
||||||
|
color.a = UNVISITED_ALPHA
|
||||||
|
draw_rect(rect, color)
|
||||||
|
|
||||||
|
# Current room indicator - bright outline
|
||||||
|
if pos == _current_pos:
|
||||||
|
draw_rect(rect, CURRENT_OUTLINE, false, 2.0)
|
||||||
Reference in New Issue
Block a user