Files
settled-reach/client/ui/stance_indicator.gd
T
jpmschweitzerandClaude Opus 4.6 a14828e02a refactor(ui): add stance icons to implant badge (#787)
Replace text-only stance labels with SVG icons + tint shader per D-086.
Alpha-mask shader swaps color at runtime via ShaderMaterial parameter.
Icons: walk, crouch, careful, sprint at 18px inside ImplantPanel row.
Also fix stale UILayer/HUD test path in test_ui_framework_sprint15.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 16:30:22 +02:00

89 lines
2.6 KiB
GDScript

extends Control
## D-053: Stance indicator — implant-styled badge (D-169).
## Sprint/Walk/Careful/Crouch. Icon (D-086) + color-coded label.
const STANCE_COLORS := {
"Sprint": Color("#d45d5d"), # Red — fast, loud, dangerous
"Walk": Color("#c8d0e0"), # Default — neutral white-blue
"Careful": Color("#6bc9a6"), # Green — quiet, observant
"Crouch": Color("#e8c547"), # Amber — very quiet, slow
}
const STANCE_ICONS := {
"Sprint": "res://assets/icons/icon_stance_sprint.svg",
"Walk": "res://assets/icons/icon_stance_walk.svg",
"Careful": "res://assets/icons/icon_stance_careful.svg",
"Crouch": "res://assets/icons/icon_stance_crouch.svg",
}
var _current_stance: String = "Walk"
var _panel: ImplantPanel
var _icon: TextureRect
var _label: Label
var _icon_mat: ShaderMaterial
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
var theme_res := load("res://ui/implant/default_implant.tres") as ImplantTheme
var icon_shader := load("res://shaders/icon_tint.gdshader") as Shader
_panel = ImplantPanel.new()
_panel.name = "StancePanel"
_panel.theme_resource = theme_res
_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(_panel)
var hbox := HBoxContainer.new()
hbox.add_theme_constant_override("separation", 4)
hbox.mouse_filter = Control.MOUSE_FILTER_IGNORE
_icon = TextureRect.new()
_icon.expand_mode = TextureRect.EXPAND_KEEP_SIZE
_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
_icon.custom_minimum_size = Vector2(18.0, 18.0)
_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
_icon_mat = ShaderMaterial.new()
_icon_mat.shader = icon_shader
_icon_mat.set_shader_parameter("tint_color", STANCE_COLORS["Walk"])
_icon.material = _icon_mat
hbox.add_child(_icon)
_label = Label.new()
_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
if theme_res:
_label.add_theme_font_size_override("font_size", theme_res.font_body)
hbox.add_child(_label)
_panel.add_component(hbox)
_apply_stance("Walk")
func _apply_stance(stance: String) -> void:
_current_stance = stance
var color: Color = STANCE_COLORS.get(stance, Color("#c8d0e0"))
var icon_path: String = STANCE_ICONS.get(stance, "")
if _icon and not icon_path.is_empty():
var tex := load(icon_path) as Texture2D
if tex:
_icon.texture = tex
_icon_mat.set_shader_parameter("tint_color", color)
if _label:
_label.text = stance
_label.add_theme_color_override("font_color", color)
func update_from_state() -> void:
var stance: String = GameState.player_stance
if stance == _current_stance:
return
_apply_stance(stance)
func get_current_stance() -> String:
return _current_stance