按 code-conventions §1.4.1 第三轮定稿执行:core 22+schemas 18+presentation 根 14+views 28,全部头注 #→##、删日期/变更叙事/GDD 与架构反向链接/字段与域清单/机制描述,保留职责摘要+真实使用约束(防事故禁令/单一入口/信号契约每信号一行)。main.gd 31→5 行、save_manager 45→5 行、adventure_runner 37→5 行为最大单件。子代理分模块执行(波一 core+schemas、波二 presentation+views,并发≤2)。验收=tools/verify_comment_only_change.py 逐字节校验(82 文件头注区外逐行一致=零行为变更)+audit_file_headers 全绿;纯注释批免冒烟(先例 5843270)
173 lines
8.6 KiB
GDScript
173 lines
8.6 KiB
GDScript
## VERTICAL SLICE - NOT FOR PRODUCTION
|
||
## 结算演出层:跨区弹道/光带等结算兑现演出载体(A–D 区之上、模态之下);棋盘区内演出归 BoardFxView。
|
||
## 组合根按结算信号调 play_* 传全局坐标;mouse_filter 全忽略不劫持输入。
|
||
class_name SettlementFxView
|
||
extends Control
|
||
|
||
|
||
func _init() -> void:
|
||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
set_anchors_preset(Control.PRESET_FULL_RECT)
|
||
|
||
|
||
# 结算轮光带:金橙半透明横带自棋盘上缘扫至下缘(一次 0.5s,自动回收)——
|
||
# "棋盘能量向战斗画面汇聚"的开轮语义(§2.2 色彩转金橙主导;区分于 board_fx 的完美排雷金光带)。
|
||
# 终稿(样张 v2 冻结批 T3):加 2px 亮金前导缘线——扫带运动方向可读(兑现光带逐行横扫 §2.2)
|
||
func play_round_sweep(board_rect: Rect2) -> void:
|
||
if board_rect.size == Vector2.ZERO:
|
||
return
|
||
var band := ColorRect.new()
|
||
band.color = Color(UiKit.GOLD, 0.22)
|
||
band.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
band.position = Vector2(board_rect.position.x, board_rect.position.y)
|
||
band.size = Vector2(board_rect.size.x, 34.0)
|
||
add_child(band)
|
||
var edge := ColorRect.new()
|
||
edge.color = Color(UiKit.GOLD_LIT, 0.7)
|
||
edge.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
edge.size = Vector2(board_rect.size.x, 2.0)
|
||
edge.position = band.position
|
||
add_child(edge)
|
||
var tw := band.create_tween()
|
||
tw.tween_property(band, "position:y", board_rect.end.y - 34.0, UiKit.motion(0.5)).set_trans(Tween.TRANS_SINE)
|
||
tw.parallel().tween_property(band, "modulate:a", 0.0, UiKit.motion(0.5)).set_delay(UiKit.motion(0.15))
|
||
tw.tween_callback(band.queue_free)
|
||
var etw := edge.create_tween()
|
||
etw.tween_property(edge, "position:y", board_rect.end.y - 2.0, UiKit.motion(0.5)).set_trans(Tween.TRANS_SINE)
|
||
etw.parallel().tween_property(edge, "modulate:a", 0.0, UiKit.motion(0.2)).set_delay(UiKit.motion(0.3))
|
||
etw.tween_callback(edge.queue_free)
|
||
|
||
|
||
# 跨区弹道:glyph 字形自 from 飞向 to(0.35s + 轻微上抛弧线 + 终点淡出,自动回收)——
|
||
# 开格之因 → 站桩之果的因果可视承载(P2);crit 弹道由调用方传加重标记
|
||
func play_projectile(from: Vector2, to: Vector2, glyph: String, col: Color, crit: bool = false) -> void:
|
||
var shot := UiKit.label(glyph, UiKit.FS_TITLE if crit else UiKit.FS_BODY, true, col)
|
||
shot.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
shot.size = Vector2(24, 24)
|
||
shot.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
shot.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||
shot.position = from - shot.size * 0.5
|
||
shot.pivot_offset = shot.size * 0.5
|
||
shot.z_index = 5
|
||
add_child(shot)
|
||
var mid := (from + to) * 0.5 + Vector2(0, -36.0) # 轻微上抛弧线
|
||
var tw := shot.create_tween()
|
||
if crit:
|
||
tw.tween_property(shot, "scale", Vector2(1.5, 1.5), UiKit.motion(0.08))
|
||
tw.tween_property(shot, "position", mid, UiKit.motion(0.16)).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
|
||
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 断言面)
|
||
var _fx_damage_marks := 0 # 三轮 #3——伤害/治疗数字浮现计数
|
||
var _fx_status_pulses := 0 # 三轮 #3——增益/减益状态脉冲计数
|
||
|
||
|
||
# 演出探针出口(卡⑦——轮横幅发射计数)
|
||
func probe_banners() -> int:
|
||
return _fx_banners
|
||
|
||
|
||
# 演出探针出口(三轮 #3——逐条结算演出计数)
|
||
func probe_settlement_marks() -> int:
|
||
return _fx_damage_marks + _fx_status_pulses
|
||
|
||
|
||
# 伤害/治疗数字浮现(三轮 #3——用户裁决「打中谁就标出多少伤害/主角被打标出多少」):
|
||
# 站桩头顶浮现数字,上飘 34px 渐隐 0.7s(减动效=时长折半同演不跳过);crit 加大加重。
|
||
func play_damage_number(pos: Vector2, text: String, col: Color, crit: bool = false) -> void:
|
||
_fx_damage_marks += 1
|
||
# T17 修复(用户实机「完全没看到伤害数字」):26/32px 大字+1.1s 驻留——旧 20px/0.7s 在
|
||
# 结算排播节奏下视觉存在感不足;描边 4→6 同步加重(亮舞台底上保读数)。
|
||
var lab := UiKit.label(text, UiKit.FS_H1 if crit else UiKit.FS_TITLE, true, col)
|
||
lab.add_theme_color_override("font_outline_color", Color(0.1, 0.08, 0.06, 0.9))
|
||
lab.add_theme_constant_override("outline_size", 6)
|
||
lab.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
lab.z_index = 6
|
||
add_child(lab)
|
||
await get_tree().process_frame # 等一帧取实际尺寸(文本度量)
|
||
lab.position = pos - lab.size * 0.5
|
||
var tw := lab.create_tween()
|
||
tw.tween_property(lab, "position:y", lab.position.y - 40.0, UiKit.motion(1.1)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||
tw.parallel().tween_property(lab, "modulate:a", 0.0, UiKit.motion(0.45)).set_delay(UiKit.motion(0.65))
|
||
tw.tween_callback(lab.queue_free)
|
||
|
||
|
||
# 增益/减益状态脉冲(三轮 #3——用户裁决「先上 Buff/Debuff 特效,再显基础伤害」):
|
||
# 目标站桩处色环扩散淡出 0.5s(增益绿/减益红由调用方传色)。
|
||
func play_status_pulse(pos: Vector2, col: Color) -> void:
|
||
_fx_status_pulses += 1
|
||
var ring := Panel.new()
|
||
ring.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||
var sb := UiKit.panel_flat(Color(col, 0.0), col, 100, 3)
|
||
ring.add_theme_stylebox_override("panel", sb)
|
||
ring.size = Vector2(22, 22)
|
||
ring.position = pos - ring.size * 0.5
|
||
ring.z_index = 5
|
||
add_child(ring)
|
||
var tw := ring.create_tween()
|
||
tw.tween_property(ring, "scale", Vector2(2.4, 2.4), UiKit.motion(0.5)).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||
tw.parallel().tween_property(ring, "modulate:a", 0.0, UiKit.motion(0.5))
|
||
tw.tween_callback(ring.queue_free)
|
||
|
||
|
||
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, UiKit.RADIUS_OBJECT, 2))
|
||
var lab := UiKit.label("第 %d 轮" % ri, UiKit.FS_TITLE, true, 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)
|
||
|
||
|
||
# 开战横幅——板级地形变异预告(全局作用域变异首发批 2026-10-04):board_variants 非空时开战
|
||
# 显示一行(文本=「地形变异 · 贫矿脉」式);减动效=静态驻留后即隐(轮横幅先例——行呈现不跳过)。
|
||
# 文案/驻留参数 provisional 归本地化批;普通图恒不发射(组合根按快照 board_variants 空判)。
|
||
func play_board_variant_banner(text: String) -> 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, UiKit.RADIUS_OBJECT, 2))
|
||
var lab := UiKit.label(text, UiKit.FS_TITLE, true, 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(320, 46)
|
||
banner.position = Vector2((size.x - banner.size.x) * 0.5, size.y * 0.30 + 52.0) # 轮横幅下方叠行(首轮同刻两横幅不重叠)
|
||
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)
|