Files
gplan-2/game/presentation/views/battle_end_overlay.gd
T
DKChan d458e393de feat(art): T3 演出密度终稿批——演出四项落码+fx_probe 新探针
死亡碎裂(standee mark_dead 增五碎块抛物线弹飞 0.45s——§4.6.4 灰化+碎裂禁瞬间消失+§8.4 冻结值);意图三档动画终稿(§4.6.4:档①普通攻击零表示不变/档②特殊准备=弹入+二次弹跳高举/档③重击蓄力=缓推 1.22+定格微顿+回落——三档运动签名互异灰度可辨);胜利纹章(battle_end open_victory 蜡封落定后十碎砖自四周拼纹章环,驻留至 close——§2.4);失败掸灰(open_defeat 八尘絮飘落——§2.5)+既有旗光收回挂探针;结算轮光带终稿(加 2px 亮金前导缘线——§2.2 逐行横扫方向可读)。全部程序化 tween 零新帧资产,确定性散布禁全局随机,时长全走 UiKit.motion 减动效包装。
新探针 smoke/fx_probe.tscn+gd:死亡碎裂5/意图三档+零表示/纹章10/掸灰8+旗光8/光带+缘线 五断言全 PASS。
连带:图例旗条目名回退『旗』(click_probe 图例基线精确匹配;T1 曾改旗(封印印记)——封印语义移描述列,色 #000000 保留)。轻闸=冒烟 557/0+五探针(ui_input/ui_probe/click/tune/fx)全 PASS。
2026-09-28 04:34:51 +08:00

185 lines
7.2 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(胜利/失败终局 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_crest_assemble() # 碎砖拼纹章(§2.4——样张 v2 冻结批 T3 终稿)
_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_dust_sadle() # 坐砖掸灰(§2.5——终稿)
_play_flag_recall(8)
func close() -> void:
visible = false
_seal.visible = false
_clear_crest_bricks()
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:
_fx_flag_dots = count
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)
# ---- 演出密度终稿(样张 v2 冻结批 T3——程序化 tween,确定性散布,零新帧资产) ----
var _crest_bricks: Array = [] # 纹章碎砖驻留面(close 时回收)
var _fx_crest_shards := 0
var _fx_dust_motes := 0
var _fx_flag_dots := 0
# 碎砖拼纹章(胜利 §2.4——蜡封落定后十枚碎砖自四周向蜡封外环收拢拼成纹章环,驻留至 close)
func _play_crest_assemble() -> void:
_clear_crest_bricks()
_fx_crest_shards = 10
var c := _board_rect.get_center() if _board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
for i in 10:
var brick := ColorRect.new()
brick.color = UiKit.BRICK if i % 2 == 0 else UiKit.FLOOR # 碎砖=砖面族色(掩尘/裸土——图底同源)
brick.size = Vector2(12, 7)
brick.mouse_filter = Control.MOUSE_FILTER_IGNORE
var ang := TAU * float(i) / 10.0
var ring := c + Vector2(cos(ang), sin(ang)) * 64.0
brick.position = c + Vector2(cos(ang), sin(ang)) * 200.0 # 自四周场外入场
add_child(brick)
_crest_bricks.append(brick)
var btw := brick.create_tween()
btw.tween_interval(UiKit.motion(0.52)) # 待蜡封落定(seal 0.42+0.22 弹跳中段)
btw.tween_property(brick, "position", ring - brick.size * 0.5, UiKit.motion(0.4)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
btw.parallel().tween_property(brick, "rotation", sin(ang) * 0.35, UiKit.motion(0.4))
# 坐砖掸灰(失败 §2.5——暖灰尘絮自棋盘中带缓缓飘落,最静一拍的运动承载)
func _play_dust_sadle() -> void:
_fx_dust_motes = 8
var base := _board_rect.get_center() if _board_rect.size != Vector2.ZERO else get_viewport_rect().size * 0.5
for i in 8:
var mote := ColorRect.new()
mote.color = Color(UiKit.WARM_FAINT, 0.85)
mote.size = Vector2(4, 4)
mote.mouse_filter = Control.MOUSE_FILTER_IGNORE
mote.position = base + Vector2((float(i % 4) - 1.5) * 30.0, -24.0 - 8.0 * float(i / 4))
add_child(mote)
var mtw := mote.create_tween()
mtw.tween_interval(UiKit.motion(0.08 * i))
mtw.tween_property(mote, "position:y", mote.position.y + 64.0, UiKit.motion(0.9))
mtw.parallel().tween_property(mote, "modulate:a", 0.0, UiKit.motion(0.9))
mtw.tween_callback(mote.queue_free)
func _clear_crest_bricks() -> void:
for b in _crest_bricks:
if is_instance_valid(b):
b.queue_free()
_crest_bricks.clear()
# 演出探针出口(fx_probe——胜利纹章/失败掸灰/旗光收回三断言面)
func fx_probe() -> Dictionary:
return {"crest_shards": _fx_crest_shards, "dust_motes": _fx_dust_motes, "flag_dots": _fx_flag_dots}