W3:相机 rig + band 组装器 + 事件系统 + 殿王战(灰盒);ADR-5 落定

P0 文档
- 架构文档:殿王战 HP 系数 50× → 15×(Balance Bible [B§5] 口径),全文档无残留
- 新增 ADR-5:2D 骨骼动画(Spine)取代 ADR-1 的单位/殿王 billboard 条目
  * 背景/决策/后果/三项被否决方案(多帧 billboard、Skeleton2D、DragonBones)
  * Godot 4.7 接入方式标注"需立项时复核",不臆造 API;挂探针 P12
  * 资产规格约束:部件分离 PNG / 图集 / 锚点命名 / 动画命名 / AI 绑骨质检门槛
  * 数据行纪律影响:sprite_row → 动画资源路径行,坚持"新资产 = 加行"
  * 美术工时对照(pipeline 报告 115-185h)
  * 3D 特效落地约定:走 flipbook 序列帧,理由是 3D 粒子直塞 2D 会绕过单趟
    后处理(ADR-2 红线)导致风格撕裂;挂探针 P13
- ADR-1 标注"单位/殿王条目被 ADR-5 取代",降级为回退规格(§5.1 保留)
- 架构 §8 清单 / §11 探针表 / 【确定】【探针】标注段同步;CLAUDE.md ADR 节同步

P1 横版核心
- camera.csv(10 行,一行一殿)+ camera.schema.json + core/data/camera_def.gd
  * 独立成表的四条理由写入 schema description,不污染 halls.csv
  * 全局标量(弹簧刚度/阻尼/平滑 tau/偷看上限/战前预告分钟)进 balance_tuning.csv
- presentation/stage:camera_rig.gd(进度锚定 + 偷看回弹 + 殿王战推近)
  + hall_band_world.gd + band_world_root.gd(四层视差)+ stage_world.gd
- stage_root 接入横版舞台,取代 W2 十殿色带(hall_band.gd 保留作回退)

P2 玩法系统
- game/event_director.gd:events.csv 四事件 → 触发/持续/效果/二选一/失败哗变
  * 效果全走 EconomyState 既有 API(瞬时区 set_event_mult / set_event_click_mult /
    set_mutiny),不直接改字段;四个出口统一 _clear_runtime 防"漏清永久 ×N"
- game/boss_battle.gd:30s 状态机(INTRO/ACTIVE/RESOLVED)
  * HP = 15 × 进入时产出/s × 殿系数(1.0→2.2),连击 +2%/层封顶 +60%
  * 胜 = 阴德爆发 HP×0.2(进本轮累计口径);败 = 60s 冷却(购路引可消)
  * 不用随机数 → sim 门 #11 可直接复用
- EconomyState 接事件瞬时区与哗变惩罚;GameState 接线 + 快照扩展
- presentation:event_panel.gd(事件卡/二选一)+ boss_arena.gd
  (预告/HP/连击/倒计时/结算/再战);stage_root 布局接入
- debug 构建 dev 热键 F1-F6/F9,走 GameState 既有命令口,不改数值

P3 质量
- 新增 3 个用例:test_camera_data / test_event_director / test_boss_battle
  (进 test_runner.CASE_FILES,共 7 个用例文件)
- 用户验证手册:docs/engineering/2026-10-19-w3-verification-manual.md(文档区)

修掉的两个潜伏缺陷(从根因修,非打补丁)
- gen_balance_sheets.py:halls.is_prestige_gate 落成字符串 "false",
  Godot 的 bool("false") == true → 十殿会被全部判为 prestige gate。
  改为真布尔,并把自检查从 == "true" 收紧为 is True(再犯即断言失败)
- boss_battles.schema.json:hp_factor 漏 type,GDScript SheetImporter 会产出
  字符串 "15"(Python 生成器产出的是数字),两条路径不一致。补 type: number

上报(未擅自改动,等裁定)
- H9/H10 殿王战数学上不可胜:纯军列耗时 = 15 × 殿系数(与产出/s 无关),
  殿系数 >2.0 → 31.5s/33.0s > 30s 限时;而缺口 ∝ 产出/s,点击伤害是常数
  (上限 25.6,不随产出/s 增长)→ 玩家越强越打不过,难度曲线是反的。
  已在 test_boss_battle._test_winnability_doc 把当前事实钉成断言哨兵,
  一旦有人改 hall_factor/active_sec/hp_factor 立刻变红强制重评。修数权属文策渊。

本机验证(无 Godot,靠移植仿真,非代替引擎实跑)
- 把 CameraDef/BossBattle/EventDirector 逐行移植成 JS 喂真实 build JSON,
  134 条断言全绿;9 张表 schema 校验通过且 build 逐字节一致(含新增 camera)
- 静态检查:跨文件方法/字段引用审计、静态调用合法性、src/core 禁 extends Node、
  缩进/括号配平/空函数体 —— 全部 0 问题
- 待本机验证:全部 GDScript 从未被引擎执行过;SubViewport 舞台与 Camera2D
  在 gl_compatibility 下的行为未实测(探针 P12 范畴)
This commit is contained in:
程基岩(engineering-lead) committed 2026-10-20 01:39:14 +08:00
1 parent 422dda6394
commit 4f650aeb39
27 files changed
+2753 -53

No files matched your search

+2 -1
View File
@@ -45,8 +45,9 @@
"description": "殿系数([B§5] H1-H10 = 1.0/1.1/1.2/1.3/1.4/1.6/1.8/2.0/2.1/2.2)"
},
"hp_factor": {
"type": "number",
"const": 15,
"description": "HP 系数([B§5]:15×产出/s×殿系数;[B§11] 由 GDD 50 修正)"
"description": "HP 系数([B§5]:15×产出/s×殿系数;[B§11] 由 GDD 50 修正)。W3 补齐缺失的 type:此前未声明 type 时 SheetImporter 按 string 处理,build 产物出现 \"15\" 字符串(且依赖 Godot Variant 的类型宽松相等才能通过 const 校验),是不该存在的隐式假设。"
},
"army_dps_factor": { "type": "number", "minimum": 0, "description": "军列 DPS = 产出/s × 本值([B§5] 1.0)" },
"intro_sec": { "type": "integer", "minimum": 0, "description": "INTRO 冲锋过场秒数(3s)" },
+104
View File
@@ -0,0 +1,104 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "camera.schema.json",
"title": "camera 表 schema v0(per-hall 相机 rig 数据行,架构 §4.3 / W3 新增)",
"description": "为什么独立成表而不是给 halls.csv 加列:① halls.csv 是「世界身份行」(殿门/解锁批/色板/pacing),被经济核心、sim、UI、引用完整性校验广泛消费;给相机参数加列会让每次手感微调都重写整张十殿表并波及所有消费者;② 相机参数生命周期与数值表不同(灰盒试玩期会高频手调),独立成表后调整 = 只改自己的行;③ 仍是「一行一殿」,年更「新冤案包」= 加一行,check_references 可断言每殿恰一行;④ 全局标量(弹簧刚度/阻尼/平滑时间常数)不随殿变,按既有纪律进 balance_tuning.csv。band_screens = 该 band 占几屏宽(@1280 基准,架构 §4.3 的 2-3 屏);layer_*_scroll = 四层视差滚动系数(0 = 无限远静止,1.0 = 与近景地面同步,>1 = 前景走得更快);focus_ratio = 进度焦点钉在视口的横向比例(0.66 = 右 1/3,GDD §2.4 焦点可见性);arena_* = 殿王战推近时的缩放与构图锚点。",
"x-supported-keywords": [
"type", "properties", "required", "items", "enum", "pattern",
"minimum", "maximum", "minLength", "minItems", "maxItems",
"additionalProperties", "const"
],
"x-unique": ["id", "hall_id"],
"type": "object",
"required": ["sheet", "schema_version", "columns", "rows"],
"properties": {
"sheet": { "const": "camera" },
"schema_version": { "const": 0 },
"columns": {
"type": "array",
"items": { "type": "string" },
"minItems": 11
},
"rows": {
"type": "array",
"minItems": 10,
"maxItems": 10,
"items": {
"type": "object",
"required": [
"id", "hall_id", "band_screens",
"layer_far_scroll", "layer_mid_scroll", "layer_near_scroll", "layer_fore_scroll",
"focus_ratio", "idle_zoom", "arena_zoom", "arena_focus_ratio"
],
"properties": {
"id": {
"type": "string",
"pattern": "^cam_hall_[0-9]{2}$",
"description": "稳定字符串 ID;永不重编号(年更=加行)"
},
"hall_id": {
"type": "string",
"pattern": "^hall_[0-9]{2}_[a-z]+$",
"description": "halls.csv 行 ID(每殿恰一行,由 BalanceData.check_references 断言)"
},
"band_screens": {
"type": "number",
"minimum": 1,
"maximum": 6,
"description": "该 band 横向屏宽数(@1280 基准;架构 §4.3 规定 2-3 屏)"
},
"layer_far_scroll": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "远景水墨层滚动系数(越小越远)"
},
"layer_mid_scroll": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "中景剪影套件层滚动系数(架构 §4.3 定 0.4)"
},
"layer_near_scroll": {
"type": "number",
"minimum": 0,
"maximum": 1.5,
"description": "近景地面层滚动系数(架构 §4.3 定 1.0)"
},
"layer_fore_scroll": {
"type": "number",
"minimum": 1,
"maximum": 2,
"description": "前景层滚动系数(>1 = 比相机走得快)"
},
"focus_ratio": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "军列前线/下一道殿门钉在视口的比例(0.66 = 右 1/3)"
},
"idle_zoom": {
"type": "number",
"minimum": 0.5,
"maximum": 3,
"description": "巡游状态基准缩放"
},
"arena_zoom": {
"type": "number",
"minimum": 0.5,
"maximum": 4,
"description": "殿王战推近缩放(应 > idle_zoom)"
},
"arena_focus_ratio": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "殿王战 arena 中心钉在视口的比例(0.5 = 居中)"
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}