From b8e6b27538a4d939e9cace1406ade8df470efe79 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 19:58:25 +0800 Subject: [PATCH] =?UTF-8?q?iter8-T6=20=E5=8D=A1=E2=91=A6=20=E8=BD=AE?= =?UTF-8?q?=E9=97=B4=E7=BB=93=E7=AE=97=E8=8A=82=E5=A5=8F=E5=8C=96=EF=BC=9A?= =?UTF-8?q?=E6=BC=94=E5=87=BA=E5=B1=82=E6=8E=92=E6=92=AD=E9=98=9F=E5=88=97?= =?UTF-8?q?=EF=BC=88=5Fon=5Fstep=5Frow=20=E5=85=A5=E9=98=9F+=5Fprocess=20?= =?UTF-8?q?=E6=B3=B5+=E6=AE=B5=E9=97=B4=200.3s/=E6=AE=B5=E5=86=85=200.06s?= =?UTF-8?q?=20=E9=98=B6=E6=A2=AF=E2=80=94=E2=80=94=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=B1=82=E9=9B=B6=20await=20=E5=A5=91=E7=BA=A6=E9=9B=B6?= =?UTF-8?q?=E8=A7=A6=E7=A2=B0=EF=BC=8Cstep=5Frow=20=E6=B6=88=E8=B4=B9?= =?UTF-8?q?=E4=BD=93=E5=8E=9F=E6=A0=B7=E6=90=AC=E5=85=A5=20=5Fconsume=5Fro?= =?UTF-8?q?w=20=E6=8E=92=E6=92=AD=E5=90=8E=E9=80=90=E4=BD=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4=EF=BC=89+=E8=BD=AE=E5=88=87=E6=8D=A2=E3=80=8C?= =?UTF-8?q?=E7=AC=AC=20N=20=E8=BD=AE=E3=80=8D=E6=A8=AA=E5=B9=85=EF=BC=88se?= =?UTF-8?q?ttlement=5Ffx=5Fview.play=5Fround=5Fbanner=20=E9=A9=BB=E7=95=99?= =?UTF-8?q?=200.6s=20=E6=B7=A1=E5=85=A5=E6=B6=88=E9=9A=90=E2=80=94?= =?UTF-8?q?=E2=80=94=E7=99=BD=E5=90=8D=E5=8D=95=E5=86=85=E5=8F=96=E5=80=BC?= =?UTF-8?q?=EF=BC=89+=E8=BD=AE=E9=A6=96=E5=88=86=E9=9A=94=E8=A1=8C?= =?UTF-8?q?=E9=9A=8F=E9=98=9F=E6=8E=92=E9=98=9F=EF=BC=88=E5=B8=A6=E5=BA=8F?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=EF=BC=89+=E5=87=8F=E5=8A=A8=E6=95=88?= =?UTF-8?q?=E5=8F=8C=E6=80=81=EF=BC=88=E5=BC=80=3D=E5=90=8C=E5=B8=A7?= =?UTF-8?q?=E7=9B=B4=E8=90=BD=E5=BF=AB=E8=B7=AF+=E6=A8=AA=E5=B9=85?= =?UTF-8?q?=E9=9D=99=E6=80=81=E5=8C=96=20create=5Ftimer=20=E5=8D=B3?= =?UTF-8?q?=E9=9A=90=E2=80=94=E2=80=94=E8=A1=8C=E5=91=88=E7=8E=B0=E4=B8=8D?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=EF=BC=89+flush-on-modal=EF=BC=88=E4=BB=BB?= =?UTF-8?q?=E4=BD=95=E8=A6=86=E7=9B=96=E5=B1=82=E5=BC=80=E5=90=AF=E5=89=8D?= =?UTF-8?q?=E6=8E=92=E7=A9=BA=E9=98=9F=E5=88=97=3D=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=9B=9E=E7=9C=8B/=E5=81=9C=E7=82=B9=E9=9D=A2=E6=98=8E?= =?UTF-8?q?=E7=BB=86=E6=81=92=E5=AE=8C=E6=95=B4=EF=BC=89+fx=5Fprobe=20?= =?UTF-8?q?=E8=BD=AE=E6=A8=AA=E5=B9=85=E5=8F=8C=E6=80=81=E6=96=AD=E8=A8=80?= =?UTF-8?q?=E2=91=A3b=E2=80=94=E2=80=94=E9=97=B8=EF=BC=9A=E5=86=92?= =?UTF-8?q?=E7=83=9F=20593/0+fx/click/input=20=E5=85=A8=E7=BB=BF=EF=BC=88c?= =?UTF-8?q?lick=20=E4=B8=BB=E5=BE=AA=E7=8E=AF=E5=85=A8=E7=A8=8B=E6=8E=92?= =?UTF-8?q?=E6=92=AD=E6=80=81=E5=AE=9E=E8=B7=91=EF=BC=89=E2=80=94=E2=80=94?= =?UTF-8?q?MC=20=E9=9B=B6=E6=89=B0=E5=8A=A8=3D=E7=BB=93=E6=9E=84=E6=80=A7?= =?UTF-8?q?=EF=BC=88=E7=BA=AF=E5=91=88=E7=8E=B0=E5=B1=82=EF=BC=8C=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BF=A1=E5=8F=B7=E6=B6=88=E8=B4=B9=E9=9B=B6=E6=94=B9?= =?UTF-8?q?=EF=BC=89T10=20=E5=A4=8D=E6=8B=8D=E3=80=82=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E7=9B=92=E8=AF=84=E4=BC=B0=EF=BC=88T6=20=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E5=88=87=E7=82=B9=EF=BC=89=EF=BC=9AT0-T6=20=E5=8D=95=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E8=90=BD=E7=B1=8D=E8=BF=9C=E5=BF=AB=E4=BA=8E=E4=BC=B0?= =?UTF-8?q?=E6=97=B6=EF=BC=8CT7-T9=20=E4=BD=99=E9=87=8F=E5=85=85=E8=B6=B3?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E8=A7=A6=E5=8F=91=E5=88=87=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/presentation/main.gd | 65 ++++++++++++++++++- game/presentation/views/settlement_fx_view.gd | 39 +++++++++++ game/smoke/fx_probe.gd | 21 +++++- 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/game/presentation/main.gd b/game/presentation/main.gd index d8d7d584..764448b4 100644 --- a/game/presentation/main.gd +++ b/game/presentation/main.gd @@ -87,6 +87,16 @@ var _refresh_used_round := 0 # 本轮已受理刷新次数(遥测 round_r var _boss_active := false # Boss 遭遇变体(阶段指示附 Boss 名) var _was_settling := false # 结算相位上升沿检测(结算轮光带触发——演出链批) +# ---- 结算行排播队列(迭代 8 卡⑦——演出层排播:逻辑先行零回压,行按段分组阶梯延迟进明细带)---- +# 硬契约:核心层零 await 不破——本队列只做信号的"后置消费",结算顺序/结果/时序逻辑零改动(§3 契约 1); +# 减动效开=延迟归零走同帧直落快路(行呈现不跳过——§3 契约 5);模态开启前强制排空(明细回看/停点 +# 覆盖层所见明细带恒完整)。 +var _row_queue: Array = [] # 待排播行(step_row 载荷原样入队;__round_line 标记=轮首分隔行) +var _row_pace_wait := 0.0 # 距下一行排播的剩余秒(_process 消耗) +var _pace_prev_segment := "" # 上一排播行的段型(段间/段内延迟判据) +const PACE_SEGMENT_GAP := 0.3 # 段间阶梯延迟(代拍板:白名单 0.2–0.4s 内取值,追认清单呈报) +const PACE_ROW_GAP := 0.06 # 段内快排间隔(同行段连读性——非白名单约束面) + func _ready() -> void: db = get_node("/root/ConfigDB") @@ -224,6 +234,7 @@ func _register_modal(m: Control) -> void: func _open_modal(m: Control) -> void: # 打开时显式隐藏树序在其上方的可见层(遮挡物隐藏),关闭恢复——单一模态栈 + _flush_row_queue() # 卡⑦——任何覆盖层开启前排空排播队列(明细带恒完整,回看/停点面不缺行) _modals.open(m) @@ -600,6 +611,19 @@ func _wire_battle(settlement_ref) -> void: func _on_step_row(row: Dictionary) -> void: + # 卡⑦ 排播入口:减动效=延迟归零同帧直落(行呈现不跳过);常态入队按段阶梯播放 + if UiKit.motion_scale < 1.0: + _consume_row(row) + return + _row_queue.append(row) + + +# 行消费(排播队列的出队步 / 减动效快路共用):明细带入带+演出链+呈现刷新——与卡⑦前排位逐位一致 +func _consume_row(row: Dictionary) -> void: + if row.has("__round_line"): + log_view.finish_settlement_round() # 上轮摘要行(明细带 pattern 3)随轮首分隔行落带 + log_view.append_bb("[color=#e0b860]── 第 %d 轮 ──[/color]" % int(row["__round_line"])) + return log_view.append_row(row) stage.on_step_row_fx(row) _play_cross_zone_fx(row) # 跨区因果演出(结算演出链批):开格之因 → 站桩之果 @@ -611,6 +635,37 @@ func _on_step_row(row: Dictionary) -> void: _refresh_presentations() +func _process(delta: float) -> void: + # 排播泵(卡⑦——演出层帧驱动;队列空=零开销直返) + if _row_queue.is_empty(): + _row_pace_wait = 0.0 + _pace_prev_segment = "" + return + _row_pace_wait -= delta + if _row_pace_wait > 0.0: + return + var entry: Dictionary = _row_queue.pop_front() + _consume_row(entry) + var seg := String(entry.get("type", "")) + _row_pace_wait = 0.0 if UiKit.motion_scale < 1.0 else (PACE_SEGMENT_GAP if seg != _pace_prev_segment else PACE_ROW_GAP) + _pace_prev_segment = seg + + +# 段间延迟取数面(减动效双态断言用——开=0 归零,行不跳过;常态=段间/段内两档) +func pace_delay_for(prev_seg: String, next_seg: String) -> float: + if UiKit.motion_scale < 1.0: + return 0.0 + return PACE_SEGMENT_GAP if prev_seg != next_seg else PACE_ROW_GAP + + +# 强制排空(模态开启前调用——明细回看/停点覆盖层/终局面所见明细带恒完整) +func _flush_row_queue() -> void: + while not _row_queue.is_empty(): + _consume_row(_row_queue.pop_front()) + _row_pace_wait = 0.0 + _pace_prev_segment = "" + + # 跨区因果演出(§Transitions 结算逐行兑现——动画密度终稿归战斗表现样张批): # 伤害行 → ⚔ 弹道自棋盘飞向目标敌方站桩(crit 金档加重);治疗行 → ✚ 弹道飞向主角站桩; # 命中反馈(闪白/血条递减/灰化)由站桩侧 on_step_row_fx/set_data 承接 @@ -637,8 +692,14 @@ func _play_cross_zone_fx(row: Dictionary) -> void: func _on_round_started(ri: int) -> void: - log_view.finish_settlement_round() # 上轮摘要行(挖掘期 1 行——明细带 pattern 3) - log_view.append_bb("[color=#e0b860]── 第 %d 轮 ──[/color]" % ri) + # 卡⑦:轮首分隔行随排播队列走(落在前轮各行之后——带序正确);轮横幅即轮切换时刻发射 + #(view 内判减动效=静态化变体)。减动效快路=分隔行同帧直落(不跳过)。 + if UiKit.motion_scale < 1.0: + log_view.finish_settlement_round() + log_view.append_bb("[color=#e0b860]── 第 %d 轮 ──[/color]" % ri) + else: + _row_queue.append({"__round_line": ri}) + settlement_fx.play_round_banner(ri) _refresh_used_round = 0 _refresh_presentations() diff --git a/game/presentation/views/settlement_fx_view.gd b/game/presentation/views/settlement_fx_view.gd index 24e0c932..006d523f 100644 --- a/game/presentation/views/settlement_fx_view.gd +++ b/game/presentation/views/settlement_fx_view.gd @@ -65,3 +65,42 @@ func play_projectile(from: Vector2, to: Vector2, glyph: String, col: Color, crit tw.tween_property(shot, "position", to - shot.size * 0.5, UiKit.motion(0.19)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN) tw.parallel().tween_property(shot, "modulate:a", 0.0, UiKit.motion(0.12)).set_delay(UiKit.motion(0.23)) tw.tween_callback(shot.queue_free) + + +# ---- 轮切换横幅(迭代 8 卡⑦——「第 N 轮」驻留 0.6s 后消隐进下一轮;白名单 0.5–0.8s 内取值)---- +# 减动效=静态呈现(驻留后即隐,零位移/零透明度动画——行呈现不跳过同语义,卡⑦ AC③)。 +const BANNER_DWELL := 0.6 + +var _fx_banners := 0 # 演出探针计数(fx_probe 断言面) + + +# 演出探针出口(卡⑦——轮横幅发射计数) +func probe_banners() -> int: + return _fx_banners + + +func play_round_banner(ri: int) -> void: + _fx_banners += 1 + var banner := Panel.new() + banner.mouse_filter = Control.MOUSE_FILTER_IGNORE + banner.add_theme_stylebox_override("panel", UiKit.panel_flat(Color(UiKit.BG_OVERLAY, 0.88), UiKit.GOLD_DEEP, 8, 2)) + var lab := UiKit.label("第 %d 轮" % ri, 22, true) + lab.add_theme_color_override("font_color", UiKit.GOLD) + lab.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + lab.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + lab.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + banner.add_child(lab) + banner.size = Vector2(190, 46) + banner.position = Vector2((size.x - banner.size.x) * 0.5, size.y * 0.30) # 棋盘中带上缘——不压明细带 + banner.z_index = 4 + add_child(banner) + if UiKit.motion_scale < 1.0: + var st := get_tree().create_timer(BANNER_DWELL) + st.timeout.connect(banner.queue_free) + return + banner.modulate.a = 0.0 + var tw := banner.create_tween() + tw.tween_property(banner, "modulate:a", 1.0, UiKit.motion(0.15)) + tw.tween_interval(UiKit.motion(BANNER_DWELL)) + tw.tween_property(banner, "modulate:a", 0.0, UiKit.motion(0.25)) + tw.tween_callback(banner.queue_free) diff --git a/game/smoke/fx_probe.gd b/game/smoke/fx_probe.gd index f64a0102..59cf07c7 100644 --- a/game/smoke/fx_probe.gd +++ b/game/smoke/fx_probe.gd @@ -77,6 +77,25 @@ func _ready() -> void: if n_fx < 2: problems.append("结算光带应含带体+前导缘线 ≥2 节点,实得 %d" % n_fx) + # ---- ④b 轮切换横幅双态(迭代 8 卡⑦——常态=淡入驻留消隐动画链;减动效=静态呈现零动画)---- + sfx.play_round_banner(3) + await get_tree().process_frame + var banner_nodes := 0 + for ch in sfx.get_children(): + if ch is Panel: + banner_nodes += 1 + if banner_nodes != 1: + problems.append("轮横幅应落位 1 面(卡⑦),实得 %d" % banner_nodes) + if int(sfx.probe_banners()) != 1: + problems.append("轮横幅计数失守(probe_banners=%s)" % sfx.probe_banners()) + var saved_motion: float = UiKit.motion_scale + UiKit.motion_scale = 0.5 + sfx.play_round_banner(4) + await get_tree().process_frame + if int(sfx.probe_banners()) != 2: + problems.append("减动效轮横幅未发射(卡⑦ AC③——静态化仍呈现不跳过)") + UiKit.motion_scale = saved_motion + # ---- ⑤ 主角三态切换(迭代 6 T3——attack/hit 短驻自回 + 死亡复活态回 idle) ---- var hero_sb = sb_script.new("hero") hero_sb.box = Vector2(150, 176) @@ -129,7 +148,7 @@ func _ready() -> void: # ---- 汇总 ---- if problems.is_empty(): - print("[fx_probe] PASS — 死亡碎裂5块/命中火花6/意图三档+零表示/胜利纹章10/失败掸灰8+旗光8/结算光带+缘线/主角三态切换 全链路通过") + print("[fx_probe] PASS — 死亡碎裂5块/命中火花6/意图三档+零表示/胜利纹章10/失败掸灰8+旗光8/结算光带+缘线/轮横幅双态/主角三态切换 全链路通过") get_tree().quit(0) else: for p in problems: