177 lines
6.6 KiB
GDScript
177 lines
6.6 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# 实现 GDD:design/ux/battle.md(C 区角色信息 240×548〔底行 520→548——停点前移批 2026-09-23,
|
||
# 原 A 区顶栏空间并入〕——HP/攻击(+修正)/RAP 直角细线数据框
|
||
# 〔修正来源角标〕、状态效果槽 ×4、小人立绘占位;RAP 清零可见反馈〔行动经济 义务〕;
|
||
# 状态槽空态 = 槽隐藏上移补位〔EC12〕)。
|
||
# Date: 2026-09-12
|
||
# 高内聚边界:纯视图 setter 面——装配(含修正文案)归 hud_presenter.gd;定长槽 + clip_contents
|
||
# (缺陷①回归约束)。
|
||
class_name HeroInfoPanelView
|
||
extends PanelContainer
|
||
|
||
const COL_INK := UiKit.INK
|
||
const COL_GOLD := UiKit.GOLD
|
||
const COL_DOT_OFF := UiKit.DOT_OFF
|
||
|
||
var _hp_bar: ProgressBar
|
||
var _hp_label: Label
|
||
var _atk_label: Label
|
||
var _rap_dots: HBoxContainer
|
||
var _rap_label: Label
|
||
var _rap_feedback: Label
|
||
var _status_feedback: Label
|
||
var slot_row: StatusSlotRow
|
||
var gp_label: Label # 冒险钱包余额常驻位(停点前移批 2026-09-23——原 A 区顶栏迁入 C 区底行)
|
||
var keystone_label: Label # 钥石余额常驻位(同上——文案装配归 HudPresenter)
|
||
var _last_rap := 0 # 上次投影值(清零反馈判据——禁解析自身 label 文本当状态)
|
||
|
||
|
||
func _init() -> void:
|
||
custom_minimum_size = Vector2(240, 0)
|
||
clip_contents = true
|
||
var sb := UiKit.panel_flat(UiKit.PANEL_HERO, UiKit.PANEL_BORDER, 0, 1, Vector4(8, 6, 8, 6))
|
||
add_theme_stylebox_override("panel", sb)
|
||
var col := VBoxContainer.new()
|
||
col.add_theme_constant_override("separation", 6)
|
||
add_child(col)
|
||
|
||
col.add_child(UiKit.label("探险者", 16, true))
|
||
_hp_bar = ProgressBar.new()
|
||
_hp_bar.custom_minimum_size = Vector2(0, 12)
|
||
_hp_bar.show_percentage = false
|
||
col.add_child(_hp_bar)
|
||
_hp_label = _data_line()
|
||
col.add_child(_hp_label)
|
||
_atk_label = _data_line()
|
||
col.add_child(_atk_label)
|
||
|
||
# RAP 框(pattern 5 点阵资源显示——点阵图形 + 数字精确值双承载)
|
||
var rap_head := HBoxContainer.new()
|
||
rap_head.add_theme_constant_override("separation", 6)
|
||
col.add_child(rap_head)
|
||
_rap_dots = HBoxContainer.new()
|
||
_rap_dots.add_theme_constant_override("separation", 2)
|
||
rap_head.add_child(_rap_dots)
|
||
_rap_label = UiKit.label("RAP 0", 13, true)
|
||
rap_head.add_child(_rap_label)
|
||
_rap_feedback = UiKit.label("", 12, false)
|
||
_rap_feedback.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||
col.add_child(_rap_feedback)
|
||
|
||
col.add_child(UiKit.label("状态效果", 14, true))
|
||
slot_row = StatusSlotRow.new()
|
||
col.add_child(slot_row)
|
||
_status_feedback = UiKit.label("", 12, false)
|
||
_status_feedback.add_theme_color_override("font_color", UiKit.STONE_FAINT)
|
||
col.add_child(_status_feedback)
|
||
|
||
# 小人立绘占位(程序化色块——真实立绘归 战斗表现)
|
||
var portrait := ColorRect.new()
|
||
portrait.color = Color(UiKit.HERO_BLUE, 56.0 / 255.0) # 原 Color8(46, 110, 142, 56)
|
||
portrait.custom_minimum_size = Vector2(0, 120)
|
||
portrait.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||
col.add_child(portrait)
|
||
var portrait_glyph := UiKit.label("小人立绘占位", 13, false)
|
||
portrait_glyph.add_theme_color_override("font_color", COL_INK)
|
||
portrait_glyph.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
portrait_glyph.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||
portrait_glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
portrait_glyph.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
portrait.add_child(portrait_glyph)
|
||
|
||
# 钱包行(停点前移批 2026-09-23:A 区 28px 顶栏退役——GP/钥石余额常驻位迁本面板底行,
|
||
# 建节点归视图、文案装配归 HudPresenter,句柄经 ui_assembler 透传组合根)
|
||
var wallet_row := HBoxContainer.new()
|
||
wallet_row.add_theme_constant_override("separation", 10)
|
||
col.add_child(wallet_row)
|
||
gp_label = UiKit.label("金币 0", 15, true)
|
||
gp_label.add_theme_color_override("font_color", UiKit.GOLD_DEEP)
|
||
wallet_row.add_child(gp_label)
|
||
keystone_label = UiKit.label("钥石 0", 15, true)
|
||
keystone_label.add_theme_color_override("font_color", UiKit.GOLD)
|
||
keystone_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||
keystone_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||
wallet_row.add_child(keystone_label)
|
||
|
||
|
||
func set_hero(hp: int, max_hp: int) -> void:
|
||
_hp_bar.max_value = maxi(1, max_hp)
|
||
_hp_bar.value = hp
|
||
_hp_label.text = "HP %d / %d" % [hp, max_hp]
|
||
|
||
|
||
func set_attack(atk: int, mod_text: String) -> void:
|
||
# 修正来源角标:mod_text 形如「(+50% 增伤)」——来源 = 效果 display_name(增益状态 投影)
|
||
_atk_label.text = "攻击 %d %s" % [atk, mod_text]
|
||
|
||
|
||
func set_rap(rap: int, cap_hint: int) -> void:
|
||
var prev := _last_rap
|
||
_last_rap = rap
|
||
_rap_label.text = "RAP %d(攒 %d 刷图)" % [rap, cap_hint]
|
||
_render_rap_dots(rap)
|
||
if prev > 0 and rap == 0:
|
||
# battle_over RAP 清零可见反馈(行动经济 D1 义务):数字滚动归零 + 微文案占位
|
||
_rap_feedback.text = "随战斗结束消散"
|
||
var tw := create_tween()
|
||
tw.tween_property(_rap_label, "modulate", Color(1.4, 1.2, 0.7), UiKit.motion(0.12))
|
||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.3))
|
||
elif rap > 0:
|
||
_rap_feedback.text = ""
|
||
|
||
|
||
func set_status_effects(effects: Array) -> void:
|
||
slot_row.set_effects(effects)
|
||
_status_feedback.text = ""
|
||
|
||
|
||
# battle_over:状态槽全清可见反馈(逐槽化光 + 微文案——增益状态×4④)
|
||
func set_status_cleared_feedback() -> void:
|
||
slot_row.set_cleared_feedback()
|
||
_status_feedback.text = "状态随战斗结束消散"
|
||
|
||
|
||
func set_idle() -> void:
|
||
_hp_bar.value = 0
|
||
_hp_label.text = "HP —"
|
||
_atk_label.text = "攻击 —"
|
||
_last_rap = 0
|
||
_render_rap_dots(0)
|
||
_rap_label.text = "RAP —"
|
||
slot_row.set_effects([])
|
||
|
||
|
||
func hp_text() -> String:
|
||
return _hp_label.text
|
||
|
||
|
||
func rap_text() -> String:
|
||
return _rap_label.text
|
||
|
||
|
||
# 资源面拒绝反馈(pattern 1 resource_face 腿):RAP 数字脉冲
|
||
func pulse_rap() -> void:
|
||
var tw := create_tween()
|
||
tw.tween_property(_rap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1))
|
||
tw.tween_property(_rap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25))
|
||
|
||
|
||
func _render_rap_dots(rap: int) -> void:
|
||
var shown := mini(rap, 16)
|
||
while _rap_dots.get_child_count() < shown:
|
||
var d := ColorRect.new()
|
||
d.custom_minimum_size = Vector2(8, 8)
|
||
d.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||
d.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
_rap_dots.add_child(d)
|
||
for i in _rap_dots.get_child_count():
|
||
var d: ColorRect = _rap_dots.get_child(i)
|
||
d.color = COL_GOLD if i < shown else COL_DOT_OFF
|
||
|
||
|
||
func _data_line() -> Label:
|
||
var l := UiKit.label("", 14, false)
|
||
l.clip_text = true
|
||
l.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||
return l
|