222 lines
7.4 KiB
GDScript
222 lines
7.4 KiB
GDScript
extends CanvasLayer
|
||
|
||
const MiniMapScript = preload("res://scripts/ui/mini_map.gd")
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Heart geometry — two polygons per slot: background (dark) + fill (red)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
# Full heart, centered at origin, ~40 wide x 36 tall
|
||
var HEART_FULL := PackedVector2Array([
|
||
Vector2( 0, 18), Vector2(-15, 3), Vector2(-20, -6),
|
||
Vector2(-15, -15), Vector2(-6, -18), Vector2(-2, -14),
|
||
Vector2( 0, -11),
|
||
Vector2( 2, -14), Vector2( 6, -18), Vector2(15, -15),
|
||
Vector2( 20, -6), Vector2(15, 3),
|
||
])
|
||
|
||
# Left half only — used for the half-heart fill
|
||
var HEART_HALF := PackedVector2Array([
|
||
Vector2( 0, 18), Vector2(-15, 3), Vector2(-20, -6),
|
||
Vector2(-15, -15), Vector2(-6, -18), Vector2(-2, -14),
|
||
Vector2( 0, -11),
|
||
])
|
||
|
||
const FULL_COLOR := Color(0.90, 0.10, 0.10) # bright red
|
||
const EMPTY_COLOR := Color(0.18, 0.04, 0.04) # dark maroon (background)
|
||
|
||
const HEART_SPACING := 52 # px between heart centers
|
||
const ORIGIN := Vector2(32, 32) # center of first heart (screen px)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# DEPRECATED — Boss bar (commented out)
|
||
# ---------------------------------------------------------------------------
|
||
#const BOSS_BAR_W := 400.0
|
||
#const BOSS_BAR_H := 18.0
|
||
#const BOSS_BAR_POS := Vector2(760.0, 1040.0) # bottom center (1920×1080 viewport)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# State
|
||
# ---------------------------------------------------------------------------
|
||
# Each entry: { "bg": Polygon2D, "fill": Polygon2D }
|
||
var _slots: Array = []
|
||
var _credits_label: Label
|
||
var _mini_map: Control
|
||
|
||
# DEPRECATED — Boss bar nodes (commented out)
|
||
#var _boss_bar_root: Node2D = null
|
||
#var _boss_bar_fill: Polygon2D = null
|
||
#var _boss_bar_label: Label = null
|
||
#var _boss_max_hp: float = 1.0
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Boot
|
||
# ---------------------------------------------------------------------------
|
||
func _ready() -> void:
|
||
EventBus.player_health_changed.connect(_on_health_changed)
|
||
EventBus.credits_changed.connect(_on_credits_changed)
|
||
EventBus.save_loaded.connect(_on_save_loaded)
|
||
# DEPRECATED — Boss bar signal connections (commented out)
|
||
#EventBus.boss_health_changed.connect(_on_boss_health_changed)
|
||
#EventBus.boss_died.connect(_on_boss_died)
|
||
_build_credits_label()
|
||
_build_mini_map()
|
||
# Initialise once the scene is fully set up
|
||
call_deferred("_init_from_player")
|
||
|
||
|
||
func _init_from_player() -> void:
|
||
var p = get_tree().get_first_node_in_group("player")
|
||
if p:
|
||
_rebuild(p.stats.max_health, p.stats.current_health)
|
||
else:
|
||
_rebuild(6.0, 6.0)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Build / rebuild all heart slots
|
||
# ---------------------------------------------------------------------------
|
||
func _rebuild(max_hp: float, current_hp: float) -> void:
|
||
for slot in _slots:
|
||
slot["bg"].queue_free()
|
||
slot["fill"].queue_free()
|
||
_slots.clear()
|
||
|
||
var num_hearts := int(max_hp / 2.0)
|
||
|
||
for i in num_hearts:
|
||
var center := ORIGIN + Vector2(i * HEART_SPACING, 0)
|
||
|
||
# Background — always visible, shows the "empty" container
|
||
var bg := Polygon2D.new()
|
||
bg.polygon = HEART_FULL
|
||
bg.color = EMPTY_COLOR
|
||
bg.position = center
|
||
add_child(bg)
|
||
|
||
# Fill — overlaid on top; polygon shape changes per fill level
|
||
var fill := Polygon2D.new()
|
||
fill.polygon = HEART_FULL
|
||
fill.color = FULL_COLOR
|
||
fill.position = center
|
||
add_child(fill)
|
||
|
||
_slots.append({"bg": bg, "fill": fill})
|
||
|
||
_update_display(current_hp)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Update fill polygons to reflect current health
|
||
# ---------------------------------------------------------------------------
|
||
func _update_display(current_hp: float) -> void:
|
||
for i in _slots.size():
|
||
var fill: Polygon2D = _slots[i]["fill"]
|
||
var hp_in_slot := current_hp - i * 2.0
|
||
|
||
if hp_in_slot >= 2.0:
|
||
fill.polygon = HEART_FULL
|
||
fill.visible = true
|
||
elif hp_in_slot >= 1.0:
|
||
fill.polygon = HEART_HALF
|
||
fill.visible = true
|
||
else:
|
||
fill.visible = false
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Credits label
|
||
# ---------------------------------------------------------------------------
|
||
func _build_credits_label() -> void:
|
||
_credits_label = Label.new()
|
||
_credits_label.position = Vector2(16, 72)
|
||
var amount := RunManager.run_credits if RunManager.run_active else UpgradeManager.wallet_credits
|
||
_credits_label.text = "SCRAP: %d" % amount
|
||
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:
|
||
_credits_label.text = "SCRAP: %d" % new_total
|
||
|
||
func _on_save_loaded() -> void:
|
||
var amount := RunManager.run_credits if RunManager.run_active else UpgradeManager.wallet_credits
|
||
_credits_label.text = "SCRAP: %d" % amount
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Signal handler
|
||
# ---------------------------------------------------------------------------
|
||
func _on_health_changed(current_hp: float, max_hp: float) -> void:
|
||
var num_hearts := int(max_hp / 2.0)
|
||
if num_hearts != _slots.size():
|
||
_rebuild(max_hp, current_hp)
|
||
else:
|
||
_update_display(current_hp)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# DEPRECATED — Boss health bar (commented out)
|
||
# ---------------------------------------------------------------------------
|
||
#var _boss_name: String = ""
|
||
#
|
||
#func _on_boss_health_changed(current_hp: float, max_hp: float, boss_name: String) -> void:
|
||
# if _boss_bar_root == null:
|
||
# _build_boss_bar(max_hp, boss_name)
|
||
# elif _boss_name != boss_name:
|
||
# # Different boss, update label
|
||
# _boss_name = boss_name
|
||
# if _boss_bar_label != null:
|
||
# _boss_bar_label.text = boss_name
|
||
# _boss_max_hp = max_hp
|
||
# _update_boss_bar(current_hp)
|
||
#
|
||
#func _on_boss_died() -> void:
|
||
# if _boss_bar_root != null:
|
||
# _boss_bar_root.queue_free()
|
||
# _boss_bar_root = null
|
||
# _boss_bar_fill = null
|
||
# _boss_bar_label = null
|
||
# _boss_name = ""
|
||
#
|
||
#func _build_boss_bar(max_hp: float, boss_name: String) -> void:
|
||
# _boss_max_hp = max_hp
|
||
# _boss_name = boss_name
|
||
#
|
||
# _boss_bar_root = Node2D.new()
|
||
# _boss_bar_root.position = BOSS_BAR_POS
|
||
# add_child(_boss_bar_root)
|
||
#
|
||
# # Name label
|
||
# _boss_bar_label = Label.new()
|
||
# _boss_bar_label.text = boss_name
|
||
# _boss_bar_label.position = Vector2(0, -22)
|
||
# _boss_bar_root.add_child(_boss_bar_label)
|
||
#
|
||
# # Background
|
||
# var bg := Polygon2D.new()
|
||
# bg.polygon = PackedVector2Array([
|
||
# Vector2(0, 0), Vector2(BOSS_BAR_W, 0),
|
||
# Vector2(BOSS_BAR_W, BOSS_BAR_H), Vector2(0, BOSS_BAR_H),
|
||
# ])
|
||
# bg.color = Color(0.15, 0.05, 0.05)
|
||
# _boss_bar_root.add_child(bg)
|
||
#
|
||
# # Fill
|
||
# _boss_bar_fill = Polygon2D.new()
|
||
# _boss_bar_fill.polygon = PackedVector2Array([
|
||
# Vector2(0, 0), Vector2(BOSS_BAR_W, 0),
|
||
# Vector2(BOSS_BAR_W, BOSS_BAR_H), Vector2(0, BOSS_BAR_H),
|
||
# ])
|
||
# _boss_bar_fill.color = Color(0.85, 0.1, 0.1)
|
||
# _boss_bar_root.add_child(_boss_bar_fill)
|
||
#
|
||
#func _update_boss_bar(current_hp: float) -> void:
|
||
# if _boss_bar_fill == null:
|
||
# return
|
||
# var pct := clampf(current_hp / _boss_max_hp, 0.0, 1.0)
|
||
# var w := BOSS_BAR_W * pct
|
||
# _boss_bar_fill.polygon = PackedVector2Array([
|
||
# Vector2(0, 0), Vector2(w, 0),
|
||
# Vector2(w, BOSS_BAR_H), Vector2(0, BOSS_BAR_H),
|
||
# ])
|