iter8-T6 卡⑦ 轮间结算节奏化:演出层排播队列(_on_step_row 入队+_process 泵+段间 0.3s/段内 0.06s 阶梯——核心层零 await 契约零触碰,step_row 消费体原样搬入 _consume_row 排播后逐位一致)+轮切换「第 N 轮」横幅(settlement_fx_view.play_round_banner 驻留 0.6s 淡入消隐——白名单内取值)+轮首分隔行随队排队(带序正确)+减动效双态(开=同帧直落快路+横幅静态化 create_timer 即隐——行呈现不跳过)+flush-on-modal(任何覆盖层开启前排空队列=明细回看/停点面明细恒完整)+fx_probe 轮横幅双态断言④b——闸:冒烟 593/0+fx/click/input 全绿(click 主循环全程排播态实跑)——MC 零扰动=结构性(纯呈现层,逻辑信号消费零改)T10 复拍。时间盒评估(T6 收口切点):T0-T6 单会话落籍远快于估时,T7-T9 余量充足,不触发切迭代

This commit is contained in:
DKChan committed 2026-09-29 19:58:25 +08:00
1 parent 3f46edbfa3
commit b8e6b27538
3 files changed
+122 -3

No files matched your search

+63 -2
View File
@@ -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()
@@ -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)
+20 -1
View File
@@ -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: