Embellish selected unit HUD

This commit is contained in:
2026-06-20 06:54:05 +09:00
parent b84cadc904
commit 65667b261b
2 changed files with 104 additions and 6 deletions

View File

@@ -173,6 +173,10 @@ const HUD_UNIT_SUMMARY_SIZE := Vector2(320, 42)
const HUD_UNIT_BADGE_ROW_SIZE := Vector2(320, 22) const HUD_UNIT_BADGE_ROW_SIZE := Vector2(320, 22)
const HUD_UNIT_BADGE_SIZE := Vector2(26, 22) const HUD_UNIT_BADGE_SIZE := Vector2(26, 22)
const HUD_UNIT_BAR_SIZE := Vector2(252, 12) const HUD_UNIT_BAR_SIZE := Vector2(252, 12)
const HUD_UNIT_PORTRAIT_SEAL_SIZE := Vector2(26, 26)
const HUD_UNIT_PORTRAIT_CLASS_PANEL_SIZE := Vector2(30, 30)
const HUD_UNIT_PORTRAIT_CLASS_ICON_SIZE := Vector2(24, 24)
const HUD_UNIT_RESOURCE_ICON_SIZE := Vector2(16, 16)
const TOP_HUD_CHIP_ICON_SIZE := Vector2(28, 28) const TOP_HUD_CHIP_ICON_SIZE := Vector2(28, 28)
const SIDE_INFO_CHIP_ICON_SIZE := Vector2(26, 26) const SIDE_INFO_CHIP_ICON_SIZE := Vector2(26, 26)
const HUD_COMMAND_GRID_SIZE := Vector2(420, 46) const HUD_COMMAND_GRID_SIZE := Vector2(420, 46)
@@ -408,6 +412,10 @@ var screen_backdrop: ColorRect
var hud_unit_portrait_panel: PanelContainer var hud_unit_portrait_panel: PanelContainer
var hud_unit_portrait_texture: TextureRect var hud_unit_portrait_texture: TextureRect
var hud_unit_portrait_label: Label var hud_unit_portrait_label: Label
var hud_unit_team_seal_panel: PanelContainer
var hud_unit_team_seal_label: Label
var hud_unit_portrait_class_panel: PanelContainer
var hud_unit_portrait_class_icon: TextureRect
var hud_unit_info_column: VBoxContainer var hud_unit_info_column: VBoxContainer
var hud_unit_badge_row: HBoxContainer var hud_unit_badge_row: HBoxContainer
var hud_unit_hp_bar: ProgressBar var hud_unit_hp_bar: ProgressBar
@@ -1164,15 +1172,26 @@ func _configure_local_command_button(button: Button, icon_kind: String, label: S
button.mouse_exited.connect(_on_local_command_button_mouse_exited) button.mouse_exited.connect(_on_local_command_button_mouse_exited)
func _make_hud_unit_resource_row(label_text: String, fill_color: Color) -> Dictionary: func _make_hud_unit_resource_row(label_text: String, fill_color: Color, icon_kind: String) -> Dictionary:
var row := HBoxContainer.new() var row := HBoxContainer.new()
row.custom_minimum_size = Vector2(HUD_UNIT_INFO_SIZE.x, 18.0) row.custom_minimum_size = Vector2(HUD_UNIT_INFO_SIZE.x, 18.0)
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_theme_constant_override("separation", 6) row.add_theme_constant_override("separation", 5)
var icon := TextureRect.new()
icon.name = "HudUnitResourceIcon"
icon.custom_minimum_size = HUD_UNIT_RESOURCE_ICON_SIZE
icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon.texture = _make_toolbar_icon(icon_kind)
icon.tooltip_text = label_text
row.add_child(icon)
var row_label := Label.new() var row_label := Label.new()
row_label.text = label_text row_label.text = label_text.substr(0, 1)
row_label.custom_minimum_size = Vector2(42, 16) row_label.tooltip_text = label_text
row_label.custom_minimum_size = Vector2(18, 16)
row_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER row_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
_apply_label_style(row_label, UI_OLD_BRONZE, 11) _apply_label_style(row_label, UI_OLD_BRONZE, 11)
row.add_child(row_label) row.add_child(row_label)
@@ -2901,6 +2920,42 @@ func _create_hud() -> void:
_apply_label_style(hud_unit_portrait_label, UI_PARCHMENT_TEXT) _apply_label_style(hud_unit_portrait_label, UI_PARCHMENT_TEXT)
hud_unit_portrait_stack.add_child(hud_unit_portrait_label) hud_unit_portrait_stack.add_child(hud_unit_portrait_label)
hud_unit_team_seal_panel = PanelContainer.new()
hud_unit_team_seal_panel.name = "HudUnitTeamSeal"
hud_unit_team_seal_panel.position = Vector2(1, 1)
hud_unit_team_seal_panel.size = HUD_UNIT_PORTRAIT_SEAL_SIZE
hud_unit_team_seal_panel.custom_minimum_size = HUD_UNIT_PORTRAIT_SEAL_SIZE
hud_unit_team_seal_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
_apply_panel_style(hud_unit_team_seal_panel, "command_seal")
hud_unit_portrait_stack.add_child(hud_unit_team_seal_panel)
hud_unit_team_seal_label = Label.new()
hud_unit_team_seal_label.set_anchors_preset(Control.PRESET_FULL_RECT)
hud_unit_team_seal_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
hud_unit_team_seal_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
hud_unit_team_seal_label.custom_minimum_size = Vector2(HUD_UNIT_PORTRAIT_SEAL_SIZE.x - 6.0, HUD_UNIT_PORTRAIT_SEAL_SIZE.y - 6.0)
_apply_label_style(hud_unit_team_seal_label, UI_PARCHMENT_TEXT, 12)
hud_unit_team_seal_panel.add_child(hud_unit_team_seal_label)
hud_unit_portrait_class_panel = PanelContainer.new()
hud_unit_portrait_class_panel.name = "HudUnitClassCrest"
hud_unit_portrait_class_panel.position = Vector2(
HUD_UNIT_PORTRAIT_STACK_SIZE.x - HUD_UNIT_PORTRAIT_CLASS_PANEL_SIZE.x + 2.0,
HUD_UNIT_PORTRAIT_STACK_SIZE.y - HUD_UNIT_PORTRAIT_CLASS_PANEL_SIZE.y + 2.0
)
hud_unit_portrait_class_panel.size = HUD_UNIT_PORTRAIT_CLASS_PANEL_SIZE
hud_unit_portrait_class_panel.custom_minimum_size = HUD_UNIT_PORTRAIT_CLASS_PANEL_SIZE
hud_unit_portrait_class_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
_apply_panel_style(hud_unit_portrait_class_panel, "caption")
hud_unit_portrait_stack.add_child(hud_unit_portrait_class_panel)
hud_unit_portrait_class_icon = TextureRect.new()
hud_unit_portrait_class_icon.name = "HudUnitClassIcon"
hud_unit_portrait_class_icon.custom_minimum_size = HUD_UNIT_PORTRAIT_CLASS_ICON_SIZE
hud_unit_portrait_class_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
hud_unit_portrait_class_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
hud_unit_portrait_class_panel.add_child(hud_unit_portrait_class_icon)
hud_unit_info_column = VBoxContainer.new() hud_unit_info_column = VBoxContainer.new()
hud_unit_info_column.custom_minimum_size = HUD_UNIT_INFO_SIZE hud_unit_info_column.custom_minimum_size = HUD_UNIT_INFO_SIZE
hud_unit_info_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL hud_unit_info_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@@ -2920,11 +2975,11 @@ func _create_hud() -> void:
hud_unit_badge_row.add_theme_constant_override("separation", 3) hud_unit_badge_row.add_theme_constant_override("separation", 3)
hud_unit_info_column.add_child(hud_unit_badge_row) hud_unit_info_column.add_child(hud_unit_badge_row)
var hp_row := _make_hud_unit_resource_row("병력", Color(0.66, 0.12, 0.075, 1.0)) var hp_row := _make_hud_unit_resource_row("병력", Color(0.66, 0.12, 0.075, 1.0), "status")
hud_unit_hp_bar = hp_row["bar"] as ProgressBar hud_unit_hp_bar = hp_row["bar"] as ProgressBar
hud_unit_info_column.add_child(hp_row["row"] as Control) hud_unit_info_column.add_child(hp_row["row"] as Control)
var mp_row := _make_hud_unit_resource_row("기력", Color(0.20, 0.42, 0.70, 1.0)) var mp_row := _make_hud_unit_resource_row("기력", Color(0.20, 0.42, 0.70, 1.0), "tactic")
hud_unit_mp_bar = mp_row["bar"] as ProgressBar hud_unit_mp_bar = mp_row["bar"] as ProgressBar
hud_unit_info_column.add_child(mp_row["row"] as Control) hud_unit_info_column.add_child(mp_row["row"] as Control)
@@ -9069,9 +9124,23 @@ func _update_hud_unit_portrait(unit: Dictionary) -> void:
hud_unit_portrait_label.text = "" hud_unit_portrait_label.text = ""
hud_unit_portrait_label.visible = false hud_unit_portrait_label.visible = false
hud_unit_portrait_label.tooltip_text = "" hud_unit_portrait_label.tooltip_text = ""
if hud_unit_team_seal_panel != null:
hud_unit_team_seal_panel.visible = false
hud_unit_team_seal_panel.tooltip_text = ""
if hud_unit_team_seal_label != null:
hud_unit_team_seal_label.text = ""
hud_unit_team_seal_label.tooltip_text = ""
if hud_unit_portrait_class_panel != null:
hud_unit_portrait_class_panel.visible = false
hud_unit_portrait_class_panel.tooltip_text = ""
if hud_unit_portrait_class_icon != null:
hud_unit_portrait_class_icon.texture = null
hud_unit_portrait_class_icon.tooltip_text = ""
return return
hud_unit_portrait_panel.visible = true hud_unit_portrait_panel.visible = true
var focus_detail := _format_unit_focus_text(unit, "Hover") var focus_detail := _format_unit_focus_text(unit, "Hover")
var team_tooltip := _hud_unit_badge_tooltip(_unit_team_text(str(unit.get("team", ""))), focus_detail)
var class_tooltip := _hud_unit_badge_tooltip("%s · %s" % [_unit_class_display_name(unit), _unit_role_text(unit)], focus_detail)
hud_unit_portrait_panel.tooltip_text = focus_detail hud_unit_portrait_panel.tooltip_text = focus_detail
var texture := _load_portrait_texture(str(unit.get("portrait", ""))) var texture := _load_portrait_texture(str(unit.get("portrait", "")))
if texture == null: if texture == null:
@@ -9083,6 +9152,18 @@ func _update_hud_unit_portrait(unit: Dictionary) -> void:
hud_unit_portrait_label.text = _dialogue_portrait_initials(str(unit.get("name", ""))) hud_unit_portrait_label.text = _dialogue_portrait_initials(str(unit.get("name", "")))
hud_unit_portrait_label.visible = not has_portrait hud_unit_portrait_label.visible = not has_portrait
hud_unit_portrait_label.tooltip_text = focus_detail hud_unit_portrait_label.tooltip_text = focus_detail
if hud_unit_team_seal_panel != null:
hud_unit_team_seal_panel.visible = true
hud_unit_team_seal_panel.tooltip_text = team_tooltip
if hud_unit_team_seal_label != null:
hud_unit_team_seal_label.text = _hud_unit_team_badge_text(unit)
hud_unit_team_seal_label.tooltip_text = team_tooltip
if hud_unit_portrait_class_panel != null:
hud_unit_portrait_class_panel.visible = true
hud_unit_portrait_class_panel.tooltip_text = class_tooltip
if hud_unit_portrait_class_icon != null:
hud_unit_portrait_class_icon.texture = _load_unit_class_icon_texture(unit)
hud_unit_portrait_class_icon.tooltip_text = class_tooltip
func _update_cell_info() -> void: func _update_cell_info() -> void:

View File

@@ -3268,6 +3268,23 @@ func _check_hud_focus_text(failures: Array[String]) -> void:
failures.append("selected HUD should expose Cao Cao MP through a resource bar") failures.append("selected HUD should expose Cao Cao MP through a resource bar")
if not scene.hud_unit_hp_bar.tooltip_text.contains("병력") or not scene.hud_unit_hp_bar.tooltip_text.contains("군기: 조조"): if not scene.hud_unit_hp_bar.tooltip_text.contains("병력") or not scene.hud_unit_hp_bar.tooltip_text.contains("군기: 조조"):
failures.append("selected HP bar tooltip should preserve unit detail: %s" % scene.hud_unit_hp_bar.tooltip_text) failures.append("selected HP bar tooltip should preserve unit detail: %s" % scene.hud_unit_hp_bar.tooltip_text)
var portrait_team_seal := _find_descendant_by_name(scene.hud_unit_portrait_panel, "HudUnitTeamSeal")
if portrait_team_seal == null:
failures.append("selected unit portrait should overlay a generated team seal")
else:
_check_panel_uses_generated_texture(failures, portrait_team_seal, "selected portrait team seal")
if not _collect_child_text(portrait_team_seal).contains(""):
failures.append("selected portrait team seal should show ally mark: %s" % _collect_child_text(portrait_team_seal))
var portrait_class_icon := _find_descendant_by_name(scene.hud_unit_portrait_panel, "HudUnitClassIcon")
if portrait_class_icon == null or not portrait_class_icon is TextureRect or (portrait_class_icon as TextureRect).texture == null:
failures.append("selected unit portrait should overlay generated class crest artwork")
var portrait_class_panel := _find_descendant_by_name(scene.hud_unit_portrait_panel, "HudUnitClassCrest")
if portrait_class_panel == null:
failures.append("selected unit portrait class crest frame missing")
else:
_check_panel_uses_generated_texture(failures, portrait_class_panel, "selected portrait class crest frame")
if _count_descendants_by_name(scene.hud_unit_info_column, "HudUnitResourceIcon") < 2:
failures.append("selected unit resource rows should use generated HP/MP icons")
if scene.selected_label.text.contains("병력") or scene.selected_label.text.contains("기력"): if scene.selected_label.text.contains("병력") or scene.selected_label.text.contains("기력"):
failures.append("selected label should not duplicate HP/MP bars: %s" % scene.selected_label.text) failures.append("selected label should not duplicate HP/MP bars: %s" % scene.selected_label.text)
if scene.selected_label.text.contains("군령:"): if scene.selected_label.text.contains("군령:"):