Files
gplan-2/game/presentation/views/ap_bar_view.gd
T

184 lines
5.9 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 实现 GDD:design/ux/battle.md(D 区 AP 条 44px——点阵+数字〔pattern 5 点阵资源显示〕、
# 停手按钮居左、图例+弃图刷新按钮居右〔雷图右上角〕;弃图刷新确认微交互与常规确认不同位
# 〔pattern 7 破坏性确认异位:RAP 扣费 · 旧板旗作废显式代价〕)。
# Date: 2026-09-12
# 高内聚边界:纯视图——意图经信号外发(stop_pressed/refresh_confirmed/legend_toggled),
# 状态由组合根经 setter 注入;刷新可用性预判 = RAP≥8 读数(行动经济 无推送信号——每次调用返回后重查)。
class_name ApBarView
extends PanelContainer
signal stop_pressed
signal refresh_confirmed
signal legend_toggled
const COL_GOLD := UiKit.GOLD
const COL_DOT_OFF := UiKit.DOT_OFF
const COL_INK := UiKit.INK
var _dots: HBoxContainer
var _ap_label: Label
var _btn_stop: Button
var _btn_legend: Button
var _btn_refresh: Button
var _refresh_sub: Label
var _confirm_row: HBoxContainer
var _confirm_lab: Label
var refresh_cost: int = 0 # 表值驱动(装配经 set_refresh_cost 注入 ActionEconomyTable.rap_refresh_cost)
var _confirm_armed := false
var _arm_tween: Tween
func _init() -> void:
custom_minimum_size = Vector2(0, 44)
var sb := UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 0, 1, Vector4(8, 4, 8, 4))
add_theme_stylebox_override("panel", sb)
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 8)
add_child(row)
_dots = HBoxContainer.new()
_dots.add_theme_constant_override("separation", 3)
_dots.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(_dots)
_ap_label = UiKit.label("AP 0/0", 16, true)
_ap_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(_ap_label)
_btn_stop = UiKit.button("停手")
_btn_stop.custom_minimum_size = Vector2(64, 0)
_btn_stop.size_flags_vertical = Control.SIZE_SHRINK_CENTER
_btn_stop.pressed.connect(func(): stop_pressed.emit())
row.add_child(_btn_stop)
var spacer := Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(spacer)
# 破坏性确认异位(pattern 7):确认 chips 出现在刷新按钮左方——与常规"按钮自身确认"不同位
_confirm_row = HBoxContainer.new()
_confirm_row.add_theme_constant_override("separation", 4)
_confirm_row.visible = false
row.add_child(_confirm_row)
_confirm_lab = UiKit.label("RAP−%d · 旧板旗作废" % refresh_cost, 14, true)
_confirm_lab.add_theme_color_override("font_color", COL_INK)
_confirm_row.add_child(_confirm_lab)
var confirm_btn := UiKit.button("确认弃图")
confirm_btn.pressed.connect(_disarm_and_fire)
_confirm_row.add_child(confirm_btn)
_btn_legend = UiKit.button("图例")
_btn_legend.custom_minimum_size = Vector2(56, 0)
_btn_legend.size_flags_vertical = Control.SIZE_SHRINK_CENTER
_btn_legend.pressed.connect(func(): legend_toggled.emit())
row.add_child(_btn_legend)
var refresh_box := VBoxContainer.new()
refresh_box.add_theme_constant_override("separation", 0)
refresh_box.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(refresh_box)
_btn_refresh = UiKit.button("弃图刷新")
_btn_refresh.pressed.connect(_on_refresh_pressed)
refresh_box.add_child(_btn_refresh)
_refresh_sub = UiKit.label("RAP−%d · 剩 0 次" % refresh_cost, 14, false)
_refresh_sub.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
refresh_box.add_child(_refresh_sub)
# ---- setter 面(组合根每次核心调用返回后重查注入——行动经济 无推送信号) ----
func set_ap(ap: int, ap_max: int) -> void:
while _dots.get_child_count() < ap_max:
_dots.add_child(_make_dot())
while _dots.get_child_count() > ap_max:
var last: Control = _dots.get_child(_dots.get_child_count() - 1)
_dots.remove_child(last)
last.queue_free()
for i in _dots.get_child_count():
var d: ColorRect = _dots.get_child(i)
d.color = COL_GOLD if i < ap else COL_DOT_OFF
_ap_label.text = "AP %d/%d" % [ap, ap_max]
func set_refresh_cost(cost: int) -> void:
refresh_cost = cost
_confirm_lab.text = "RAP−%d · 旧板旗作废" % cost
func set_refresh_state(remaining: int, ready: bool) -> void:
_refresh_sub.text = "RAP−%d · 剩 %d 次" % [refresh_cost, remaining]
_btn_refresh.disabled = not ready
if not ready:
_disarm()
func set_stop_enabled(on: bool) -> void:
_btn_stop.disabled = not on
func set_legend_enabled(on: bool) -> void:
_btn_legend.disabled = not on
# 探针/装配复用:刷新按钮可用性(预判 = RAP 足额 + 上限未到)
func is_refresh_ready() -> bool:
return not _btn_refresh.disabled
# 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):刷新按钮点击 → 确认 chips 全链路
func press_refresh_for_probe() -> void:
_on_refresh_pressed()
func confirm_visible() -> bool:
return _confirm_row.visible
func press_confirm_for_probe() -> void:
if _confirm_armed:
_disarm_and_fire()
func refresh_remaining_text() -> String:
return _refresh_sub.text
# ---- 确认微交互(pattern 7 异位:常规确认 = 按钮自身;本确认 = 左侧独立 chips) ----
func _on_refresh_pressed() -> void:
if _btn_refresh.disabled:
return
_confirm_row.visible = true
_confirm_armed = true
if _arm_tween != null and _arm_tween.is_valid():
_arm_tween.kill()
_arm_tween = create_tween()
_arm_tween.tween_interval(4.0)
_arm_tween.tween_callback(_disarm)
func _disarm_and_fire() -> void:
_disarm()
refresh_confirmed.emit()
func _disarm() -> void:
_confirm_armed = false
_confirm_row.visible = false
# 资源面拒绝反馈(pattern 1 resource_face 腿):AP 数字脉冲
func pulse_ap() -> void:
var tw := create_tween()
tw.tween_property(_ap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1))
tw.tween_property(_ap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25))
func _make_dot() -> ColorRect:
var d := ColorRect.new()
d.custom_minimum_size = Vector2(10, 10)
d.color = COL_DOT_OFF
d.mouse_filter = Control.MOUSE_FILTER_IGNORE
return d