feat(ui): convert HUD status, stance, interaction prompt to implant theme (D-169)
- HUD: programmatically builds ImplantPanel with health/mode/time rows, replaces raw MarginContainer/VBoxContainer/Labels - Stance indicator: ImplantPanel with color-coded ImplantDataRow, replaces custom _draw() with hardcoded bg/text - Interaction prompt: applies implant theme StyleBox + colors to existing PanelContainer layout Minimap left as-is — its circular frame is a distinct diegetic element, not rectangular panel chrome. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+37
-13
@@ -1,35 +1,59 @@
|
||||
extends Control
|
||||
|
||||
# HUD — displays player health, perception mode, time, etc.
|
||||
## HUD — implant-styled status panel (D-169, D-170).
|
||||
## Displays health, perception mode, time in an ImplantPanel.
|
||||
|
||||
@onready var health_label: Label = $MarginContainer/VBoxContainer/HealthLabel
|
||||
@onready var perception_label: Label = $MarginContainer/VBoxContainer/PerceptionLabel
|
||||
@onready var time_label: Label = $MarginContainer/VBoxContainer/TimeLabel
|
||||
var _panel: ImplantPanel
|
||||
var _health_row: ImplantDataRow
|
||||
var _perception_row: ImplantDataRow
|
||||
var _time_row: ImplantDataRow
|
||||
var _theme: ImplantTheme
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# Remove the old raw MarginContainer/labels if present
|
||||
var old := get_node_or_null("MarginContainer")
|
||||
if old:
|
||||
old.queue_free()
|
||||
|
||||
_theme = load("res://ui/implant/default_implant.tres") as ImplantTheme
|
||||
|
||||
_panel = ImplantPanel.new()
|
||||
_panel.name = "StatusPanel"
|
||||
_panel.theme_resource = _theme
|
||||
_panel.custom_minimum_size.x = 200.0
|
||||
_panel.size.x = 200.0
|
||||
_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_panel.position = Vector2(16, 16)
|
||||
add_child(_panel)
|
||||
_panel.move_child(_panel.get_node("Content"), 0) # ensure content is first
|
||||
|
||||
_health_row = ImplantDataRow.new("Health: 100")
|
||||
_perception_row = ImplantDataRow.new("Mode: Baseline")
|
||||
_time_row = ImplantDataRow.new("Time: 08:00")
|
||||
|
||||
_panel.add_component(_health_row)
|
||||
_panel.add_component(_perception_row)
|
||||
_panel.add_component(_time_row)
|
||||
|
||||
print("HUD: Initialized")
|
||||
|
||||
|
||||
# Update HUD from snapshot data
|
||||
func update_from_hud_data(data: Dictionary) -> void:
|
||||
# Update perception mode display
|
||||
if data.has("perception_mode"):
|
||||
var prefix := UIStrings.get_text("hud.perception_mode_prefix")
|
||||
if prefix.is_empty():
|
||||
perception_label.text = data.perception_mode.capitalize()
|
||||
_perception_row.text = data.perception_mode.capitalize()
|
||||
else:
|
||||
perception_label.text = prefix + ": " + data.perception_mode.capitalize()
|
||||
_perception_row.text = prefix + ": " + data.perception_mode.capitalize()
|
||||
|
||||
# Update time display (per D-031)
|
||||
if data.has("time"):
|
||||
var prefix := UIStrings.get_text("hud.time_prefix")
|
||||
if prefix.is_empty():
|
||||
time_label.text = data.time
|
||||
_time_row.text = data.time
|
||||
else:
|
||||
time_label.text = prefix + ": " + data.time
|
||||
_time_row.text = prefix + ": " + data.time
|
||||
|
||||
|
||||
# Update player health (from player data, not hud_data)
|
||||
func update_health(health: int) -> void:
|
||||
health_label.text = UIStrings.get_text("hud.health") + ": " + str(health)
|
||||
_health_row.text = UIStrings.get_text("hud.health") + ": " + str(health)
|
||||
|
||||
@@ -24,6 +24,17 @@ func _ready() -> void:
|
||||
modulate.a = 0.0
|
||||
visible = false
|
||||
_is_showing = false
|
||||
# D-169: Apply implant theme
|
||||
var t := load("res://ui/implant/default_implant.tres") as ImplantTheme
|
||||
if t:
|
||||
var style := StyleBoxFlat.new()
|
||||
style.bg_color = t.panel_bg
|
||||
style.border_color = t.separator
|
||||
style.set_border_width_all(int(t.border_width))
|
||||
style.set_content_margin_all(t.padding)
|
||||
add_theme_stylebox_override("panel", style)
|
||||
prompt_label.add_theme_color_override("font_color", t.text_primary)
|
||||
prompt_label.add_theme_font_size_override("font_size", t.font_body)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
extends Control
|
||||
|
||||
## D-053: Stance indicator — shows current movement stance on HUD.
|
||||
## D-053: Stance indicator — implant-styled badge (D-169).
|
||||
## Sprint/Walk/Careful/Crouch. Color-coded for quick read.
|
||||
## Lives on UILayer (z-layer 7).
|
||||
|
||||
const STANCE_COLORS := {
|
||||
"Sprint": Color("#d45d5d"), # Red — fast, loud, dangerous
|
||||
@@ -11,16 +10,23 @@ const STANCE_COLORS := {
|
||||
"Crouch": Color("#e8c547"), # Amber — very quiet, slow
|
||||
}
|
||||
|
||||
const STANCE_DEFAULT_COLOR := Color("#c8d0e0")
|
||||
const BG_COLOR := Color(0.05, 0.05, 0.08, 0.5)
|
||||
const FONT_SIZE := 13
|
||||
const PADDING := Vector2(10, 6)
|
||||
|
||||
var _current_stance: String = "Walk"
|
||||
var _panel: ImplantPanel
|
||||
var _row: ImplantDataRow
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
var theme_res := load("res://ui/implant/default_implant.tres") as ImplantTheme
|
||||
|
||||
_panel = ImplantPanel.new()
|
||||
_panel.name = "StancePanel"
|
||||
_panel.theme_resource = theme_res
|
||||
_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(_panel)
|
||||
|
||||
_row = ImplantDataRow.new("Walk", STANCE_COLORS["Walk"])
|
||||
_panel.add_component(_row)
|
||||
|
||||
|
||||
func update_from_state() -> void:
|
||||
@@ -28,32 +34,8 @@ func update_from_state() -> void:
|
||||
if stance == _current_stance:
|
||||
return
|
||||
_current_stance = stance
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var font := ThemeDB.fallback_font
|
||||
var text := _current_stance
|
||||
var text_size := font.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, FONT_SIZE)
|
||||
var box_size := text_size + PADDING * 2
|
||||
|
||||
# Background
|
||||
draw_rect(Rect2(Vector2.ZERO, box_size), BG_COLOR)
|
||||
|
||||
# Stance text
|
||||
var color: Color = STANCE_COLORS.get(_current_stance, STANCE_DEFAULT_COLOR)
|
||||
draw_string(
|
||||
font,
|
||||
PADDING + Vector2(0, text_size.y),
|
||||
text,
|
||||
HORIZONTAL_ALIGNMENT_LEFT,
|
||||
-1,
|
||||
FONT_SIZE,
|
||||
color
|
||||
)
|
||||
|
||||
|
||||
# -- Public API ---------------------------------------------------------------
|
||||
var color: Color = STANCE_COLORS.get(stance, Color("#c8d0e0"))
|
||||
_row.set_content(stance, color)
|
||||
|
||||
|
||||
func get_current_stance() -> String:
|
||||
|
||||
Reference in New Issue
Block a user