122 lines
4.5 KiB
GDScript
122 lines
4.5 KiB
GDScript
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||
# 实现 GDD:design/ux/battle.md(胜利/失败终局 overlay——金蜡封占位落于扫雷图区中央 + 判定行 +
|
||
# 明细回看入口 + 继续/返回;失败 = 暮蓝 #5A6C8C 氛围(明度不变)+ 旗化光点收回占位;
|
||
# pattern 6 模态 overlay 层级纪律——遮挡物隐藏/输入锁定断言归场景探针)。
|
||
# Date: 2026-09-12(扩展自 node_overlay 的战斗终局职责分离)
|
||
class_name BattleEndOverlay
|
||
extends Control
|
||
|
||
signal review_pressed
|
||
signal continue_pressed
|
||
|
||
const COL_GOLD := UiKit.GOLD
|
||
const COL_DUSK := UiKit.DUSK # 暮蓝(全作唯一暮蓝档)
|
||
const COL_WARM := UiKit.WARM
|
||
|
||
var _dim: ColorRect
|
||
var _seal: Panel
|
||
var _verdict: Label
|
||
var _review_btn: Button
|
||
var _btn: Button
|
||
var _board_rect := Rect2()
|
||
|
||
|
||
func _init() -> void:
|
||
_dim = ColorRect.new()
|
||
_dim.color = Color(COL_WARM, 0.0)
|
||
_dim.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
add_child(_dim)
|
||
var center := CenterContainer.new()
|
||
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
_dim.add_child(center)
|
||
var box := VBoxContainer.new()
|
||
box.add_theme_constant_override("separation", 12)
|
||
center.add_child(box)
|
||
_verdict = UiKit.label("", 26, true)
|
||
_verdict.add_theme_color_override("font_color", COL_WARM)
|
||
_verdict.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
box.add_child(_verdict)
|
||
_review_btn = UiKit.button("明细回看")
|
||
_review_btn.pressed.connect(func(): review_pressed.emit())
|
||
box.add_child(_review_btn)
|
||
_btn = UiKit.button("继续")
|
||
_btn.pressed.connect(func(): continue_pressed.emit())
|
||
box.add_child(_btn)
|
||
# 金蜡封占位(胜利):圆形色块落于扫雷图区中央——位置由 set_board_rect 注入
|
||
_seal = Panel.new()
|
||
_seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
var sb := UiKit.panel_flat(COL_GOLD, UiKit.GOLD_DEEP, 200, 4)
|
||
_seal.add_theme_stylebox_override("panel", sb)
|
||
_seal.size = Vector2(72, 72)
|
||
_seal.visible = false
|
||
_seal.top_level = true
|
||
add_child(_seal)
|
||
visible = false
|
||
|
||
|
||
# 终局画面数据锚 = 战斗结算 判定行(verdict)——判定行文案由组合根装配传入
|
||
func open_victory(verdict_line: String, continue_label: String, board_rect: Rect2) -> void:
|
||
_dim.color = Color(COL_WARM, 0.28)
|
||
_verdict.text = verdict_line
|
||
_verdict.add_theme_color_override("font_color", UiKit.INK_ON_GOLD)
|
||
_btn.text = continue_label
|
||
_board_rect = board_rect
|
||
visible = true
|
||
_play_seal_fall()
|
||
_play_flag_recall(0) # 胜利不放旗收回
|
||
|
||
|
||
func open_defeat(verdict_line: String, continue_label: String, board_rect: Rect2) -> void:
|
||
# 明度不变的暮蓝色相氛围(全屏唯一暮蓝档——§2.5 最静一拍)
|
||
_dim.color = Color(COL_DUSK, 0.45)
|
||
_verdict.text = verdict_line
|
||
_verdict.add_theme_color_override("font_color", COL_WARM)
|
||
_btn.text = continue_label
|
||
_board_rect = board_rect
|
||
visible = true
|
||
_seal.visible = false
|
||
_play_flag_recall(8)
|
||
|
||
|
||
func close() -> void:
|
||
visible = false
|
||
_seal.visible = false
|
||
|
||
|
||
func is_open() -> bool:
|
||
return visible
|
||
|
||
|
||
func verdict_text() -> String:
|
||
return _verdict.text
|
||
|
||
|
||
# 金蜡封自上落下弹跳定格于棋盘中央(§2.4 克制不狂欢——占位级)
|
||
func _play_seal_fall() -> void:
|
||
var target := _board_rect.get_center() - _seal.size * 0.5
|
||
if _board_rect.size == Vector2.ZERO:
|
||
target = get_viewport_rect().size * 0.5 - _seal.size * 0.5
|
||
_seal.position = Vector2(target.x, -100.0)
|
||
_seal.visible = true
|
||
var tw := _seal.create_tween()
|
||
tw.tween_property(_seal, "position:y", target.y - 26.0, UiKit.motion(0.42)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
|
||
tw.tween_property(_seal, "position:y", target.y, UiKit.motion(0.22)).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
|
||
|
||
|
||
# 旗化光点收回(失败——插过的旗逐面化光点收回占位,§2.5)
|
||
func _play_flag_recall(count: int) -> void:
|
||
for i in count:
|
||
var dot := ColorRect.new()
|
||
dot.color = COL_GOLD
|
||
dot.size = Vector2(6, 6)
|
||
var base := _board_rect.get_center() if _board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
|
||
dot.position = base + Vector2((float(i % 5) - 2.0) * _board_rect.size.x * 0.14 if _board_rect.size.x > 0 else 0.0,
|
||
(float(i % 3) - 1.0) * _board_rect.size.y * 0.18) # 确定性散布(S2 禁全局随机——占位演出同守)
|
||
dot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
add_child(dot)
|
||
var tw := dot.create_tween()
|
||
tw.tween_interval(UiKit.motion(0.1 * i))
|
||
tw.tween_property(dot, "position:y", dot.position.y - 120.0, UiKit.motion(0.8))
|
||
tw.parallel().tween_property(dot, "modulate:a", 0.0, UiKit.motion(0.8))
|
||
tw.tween_callback(dot.queue_free)
|