# 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)