docs(roadmap): 新增 E7-⑥ 计算模块化重构(用户 2026-07-31 指定的架构方向)

原则:凡涉及计算的都由专门功能模块负责,便于测试与配置。
AttributeFormula 是已验证的模板(纯静态零依赖,故不启动游戏就能单元断言)。

盘点出计算散落 8 处、仅 1 处已模块化。最严重的是伤害被劈成两半分居两个文件,
且两处都在扣护甲——目前不重复扣仅因调用点特意传 armor=0,而该约定只存在于
调用点,两个函数各自看都是完整公式。连击 +2%/层 也硬编码在管理器里。

记录立项时必须先决定的设计问题与热路径风险,避免实现期顺手定。
顺序:货架 C(含 PriceFormula)先做,本项独立立项。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 16:04:04 +08:00
co-authored by Claude Opus 5
parent 9a5f2c1271
commit d7420a284f
@@ -170,7 +170,39 @@ E6-a 玩家无敌帧(i-frames) ← 先行小项:Boss 弹幕公平性前置,
**依赖**:无。各项可独立作为"缝隙任务"穿插。
**切分(独立小项)**:① DamageNumber 飘字(S,高手感回报);② 敌人 LOD 屏内剔除 + 屏外低频分离(S~M);③ 内容名 tr 化 + 裸中文静态检查(S,i18n 收尾);④ UI 关键面板 `.tscn` 化(M,可选);⑤ C# 热路径落地(L,仅当 GDScript 达性能瓶颈时;当前 500 敌 3.6% 预算,非必需)。
**切分(独立小项)**:① DamageNumber 飘字(S,高手感回报);② 敌人 LOD 屏内剔除 + 屏外低频分离(S~M);③ 内容名 tr 化 + 裸中文静态检查(S,i18n 收尾);④ UI 关键面板 `.tscn` 化(M,可选);⑤ C# 热路径落地(L,仅当 GDScript 达性能瓶颈时;当前 500 敌 3.6% 预算,非必需);⑥ **计算模块化重构(M~L,2026-07-31 立项确认,用户指定)** —— 见下
### E7-⑥ 计算模块化重构(用户 2026-07-31 指定的架构方向)
**原则**:凡涉及计算的都由**专门功能模块**负责,便于测试、配置,符合「专门模块负责专门功能」的设计理念。`AttributeFormula`E3-① 建)是已验证的模板:`class_name` 纯静态、零依赖(不碰 autoload/场景树),因此**不启动游戏就能单元断言**,改公式立刻回归。
**现状盘点(代码复核 2026-07-31)**:计算散落 8 处,仅 1 处已模块化。
| 计算 | 现在住在哪 | 状态 |
| :-- | :-- | :-- |
| 属性合成 | `AttributeFormula` | ✅ 已模块化(模板) |
| 伤害合成(一半) | `DamageContext.calc_damage``damage_context.gd:26`) | ⚠️ 与上下文数据混在同一个类 |
| 伤害合成(另一半) | `EnemyManager.apply_damage:285-289` | ❌ 内联在管理器 |
| 经验曲线 | `PlayerStats.xp_for_level` | 纯静态但与状态混住 |
| 分数 | `EndlessRecords.compute_score` | 同上 |
| 刷新费用 | `ShopManager.get_reroll_cost` | ❌ 内联 |
| 蓝耗 + heat 乘子 | `SpellEvaluator._charge_mana` | ❌ 内联在法术 VM |
| 波次缩放 | `WaveManager:61,62,76` | ❌ 内联三处 |
**最严重的一处 —— 伤害被劈成两半,分别在两个文件里,且两处都在扣护甲**
```gdscript
# damage_context.gd:26
base_damage × mult × (1 resistance) armor × (1 pierce_rate)
# enemy_manager.gd:285-289 ← 又算了一遍
damage × (1 + combo_stacks × 0.02) armor # 保底 1
```
目前**没有**重复扣,因为 `apply_damage_from_context` 特意传 `calc_damage(0.0, res)` 把 armor 置 0 留给下游 —— 但该约定只存在于调用点,两个函数各自看都是完整公式。想知道「这一击到底怎么算」必须同时读两个文件并知道那条不成文约定。连击的 `+2%/层` 也硬编码在管理器里,不在任何数据文件中。
**立项时必须先决定的设计问题**(都不该在实现期顺手定):伤害那两半如何合并、`calc_damage``armor` 参数语义要不要改、连击 `+2%` 进哪个数据文件、DOT 伤害(`status_manager.gd:116` 直调 `apply_damage`,绕过 context 故不享元素抗性,E1-① 记录的已知限制)是否借此一并归位。
**风险**:触碰全游戏最热路径(500 敌 + 1500 弹),必须有迁移前后的基准对比。
**依赖**:无硬依赖。`PriceFormula`(E3-② 货架 C 建)会成为第二个已模块化的例子,可与 `AttributeFormula` 一起确立命名/签名/测试惯例,再据此重构其余 7 处。
**验收标准**:飘字随命中显示;屏外敌人低频更新且 FPS 提升;4 语言无裸中文;MCP/截图实测。