docs: 整理文档目录并对齐代码现状
- 将开发过程/归档文档迁至 docs_dev/(development_plan、certification_checklist、 已废弃的 Cocos 架构草案 archived_cocos_architecture_draft),并修正全部跨引用 - 新增根 README.md(项目介绍,暂定名 Spellforge)与 docs_dev/README.md 索引 - 新增 docs_dev/doc_code_audit_2026-07-20.md:文档 vs 代码交叉审计报告(经 6 路对抗性复核,零证伪),含「代码更优 / 文档更优 / 中性」判定汇总 - 在 docs/ 各设计·技术·机制文档就地加「实现现状 (2026-07-20)」callout: 追认代码更优实现(纯 JSON 数据驱动、SpatialGrid-only 碰撞、MultiMesh 单档、 存档选最新槽等),订正陈旧/矛盾内容(.tres→JSON、Boss HP/阈值/波次、EventID、 StatusManager.apply 签名等),标记未实现功能(C# 热路径、Mana、元进展、 Boss 阶段/抗性、Tutorial、轨迹/连锁/催化等)与 latent bug(CoreFeatureTag 位运算、 pierce 空操作、MAX_OPS 不读 cpu_limit) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,8 @@ graph TD
|
||||
end
|
||||
```
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:数据层实际为**纯 `data/*.json`**(7 个文件:spells / cores / enemies / waves / resonance / status_effects / balance),各 Manager 自行 `FileAccess` 直读;全项目**零 `.tres` 数据资源**(仅 `assets/ui/ui_theme.tres`),无 `resources/` 目录。图中 `ConfigMgr` autoload 虽已注册(`project.godot`),但**从未被任何调用方引用,是死代码**。文中后续所有 `res://resources/**/*.tres` 路径均为设计蓝图,与实际 `data/*.json` 布局不符。详见 [`docs_dev/doc_code_audit_2026-07-20.md`](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 核心子系统:超模块化法术系统 (HMWS)
|
||||
@@ -263,6 +265,11 @@ func reset() -> void:
|
||||
|
||||
`SpellEvaluator` 的 while 循环只能处理线性指令流。为此,在 `SpellEvaluator.compile_wand(core, raw_deck)` 预编译阶段引入 **拓扑扁平化 (Topology Flattening)**,将不同 Core 的空间拓扑提前转换为线性指令序列,运行时 while 循环无需感知拓扑:
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:真实签名与本节伪代码不同:
|
||||
> - `compile_wand(core, raw_nodes: Array)` —— 第 2 参是 `Array` 而非 `SpellDeck`(`spell_evaluator.gd:36`)。
|
||||
> - `execute_compiled(compiled, caster_id: int, spawn_pos: Vector2)` —— 执行期不传 `ctx`/`core`,`feature_tags` 从 `CompiledDeck` 编译期快照读取(`spell_evaluator.gd:321`)。
|
||||
> 详见 [`docs_dev/doc_code_audit_2026-07-20.md`](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
| Core 类型 | 扁平化策略 |
|
||||
| :--- | :--- |
|
||||
| **LINEAR** | 无需处理,直接输出原始 SpellNode 序列 |
|
||||
@@ -279,6 +286,9 @@ func update_max_ops(cpu_limit: int) -> void:
|
||||
# MAX_OPS_PER_CPU = 8(基准值,SpellEvaluator 常量)
|
||||
const MAX_OPS_PER_CPU: int = 8
|
||||
_max_ops = clamp(MAX_OPS_PER_CPU * cpu_limit, 8, 200)
|
||||
# ⚠️ 实现现状(2026-07-20):SpellEvaluator 从不调用本函数、从不读 cpu_limit;
|
||||
# 实际硬编码 max_ops = MAX_OPS_PER_CPU * 5(代码常量为 40,本处写 8,文档内部亦不一致)。
|
||||
# 结果:升级 CPU 词条对施法预算无效——本设计更优,代码待修。见审计报告 D 节。
|
||||
|
||||
func compile_wand(core: CoreDefinition, raw_deck: SpellDeck) -> CompiledDeck:
|
||||
match core.topology:
|
||||
@@ -719,10 +729,14 @@ func _node_has_tag(node: SpellNode, tag_pattern: String) -> bool:
|
||||
* 下穿回滞(`_active_count < 1500 and _collision_mode == 1`):反向切回,避免阈值附近频繁震荡。**⚠️ 反向切换 Jitter 风险**:从 SpatialGrid 切回 Area2D 时,约 1500 颗子弹需要重新启用 Node(`process_mode = INHERIT`)。若全部在单帧完成,将产生约 1500 次节点状态更改(额外 1~2ms,可见微卡顿)。**缓解策略**:反向切换同样须分帧渐进(`BATCH_ENABLE_PER_FRAME = 100`,约 15 帧完成),过渡期内存活子弹继续走 SpatialGrid 路径,碰撞正确性不受影响。
|
||||
* 两段路径(信号回调 vs 手动查询)最终均调用同一 `_on_bullet_hit(bullet_id, enemy_id)` 函数,后处理逻辑完全共用。
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:上述 Area2D 优先 + `_collision_mode` 三档运行时切换**从未实现**。现状是 **SpatialGrid-only**:`BulletManager._check_collision` 无条件走 `SpatialGrid.query_circle`,代码中不存在 Area2D / CircleShape2D / `body_entered` / `_collision_mode` / `BATCH_DISABLE_PER_FRAME`。这一简化与 `implementation_plan.md` §S0 的 **R-04 决议**(永久锁定 SpatialGrid 为 200+ 主力、不保留 Area2D 回退)一致——本节 §4.3/§4.4 属尚未同步的旧设计。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
### 4.4 渲染优化
|
||||
|
||||
子弹渲染策略依据同屏数量分三档,**Area2D 与 MultiMeshInstance2D 不共存**——MultiMesh 绕过节点树,意味着子弹无法挂载 Area2D。因此两者适用于不同的弹幕规模区间:
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:下表三档**未实现**。现状:`MultiMeshInstance2D` **从第 1 帧起单档常开**(无 Node2D 池、无 <200/200-2000 档),子弹与敌人均走 MultiMesh。同步是 **GDScript 逐实例 `set_instance_transform_2d` 循环**(非文档的 C# `SetBuffer` 批量上传);子弹无按型颜色(统一 `modulate`),敌人有 per-instance color。既然碰撞已 SpatialGrid-only,Node 池档位已无意义,此简化为**代码更优**。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
| 同屏弹幕数 | 渲染方案 | 碰撞方案 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| < 200 | Node Pool (Node2D) | Area2D | 全功能,支持粒子特效、信号回调 |
|
||||
@@ -771,6 +785,8 @@ func _node_has_tag(node: SpellNode, tag_pattern: String) -> bool:
|
||||
|
||||
> **目标**:60fps → 单帧总预算 **16.67ms**。以下为 S0 性能验收的基准分配;S0 Profiler 实测后需将"S0 实测值"列回填并提交 git,作为后续切片的性能基线快照。
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:下表"语言"列标注 C#(`BulletManagerCs`/`EnemyManagerCs`/`SpatialGridCs`/`SpellEvaluatorCs`)的热路径**均未接线**——三个 C# 内核从未实例化、从未进场景树,战斗逻辑 **100% 由 GDScript 回退路径承载**(R-08 顺延)。C# `AsSpan()` 零拷贝在代码中不存在。表中"S0 实测值"确为 GDScript 回退实测(见 :795 摘要)。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
| 系统 | 语言 | 预算上限 | S0 实测值 | 说明 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `BulletManagerCs._PhysicsProcess` | C# | 2.0ms | **0.37ms** | 2000 子弹 GDScript SoA 积分(P-S0-01;C# 热路径 S1 填充后预计更低) |
|
||||
@@ -823,6 +839,8 @@ func _node_has_tag(node: SpellNode, tag_pattern: String) -> bool:
|
||||
|
||||
### 5.1 GameCycleManager 状态机 (FSM)
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:`GameCycleManager` Autoload **不存在**。顶层状态机现内嵌在场景子节点 `combat_manager.gd`,仅 **5 态**(INIT/BATTLE/SETTLEMENT/SHOP/GAME_OVER),缺文档的 WAVE_INTRO 开场、WAVE_RESULT 升级卡结算、GAME_CLEARED 通关、PAUSE 独立态(暂停改由 `get_tree().paused` 处理)。`GAME_STATE_CHANGED` payload 用字符串态名而非枚举。同理 §5.10 的 `UIManager` Autoload 也不存在——全部 UI 在 `combat_s2.gd` 程序化构建,无 `HUD.tscn`/`shop.tscn` 等场景,`DamageNumber` 飘字未实现。下文 GameCycleManager/UIManager 相关设计保留作目标蓝图。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
`GameCycleManager` 是游戏最顶层的协调者,持有全局状态机并驱动各 Manager 的生命周期。
|
||||
|
||||
```gdscript
|
||||
@@ -2815,6 +2833,8 @@ DoT(持续伤害)、召唤物(Minion)、持续性法术的属性在**施
|
||||
|
||||
> **结论:采用独立的 MinionManager(方案 B),不在 EnemyManager 中混管召唤物。**
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:MinionManager 存在,但数据结构用的是 **`Array[Dictionary]`(随 §5.12)而非本节的 SoA `stride=8`**(两处文档矛盾,代码选了 Array);`behavior_state` 枚举未实现。召唤物**只实现了 Stationary 炮台一种**,随从/卫星/镜像(含 hp/碰撞体积/移动)均未落地。`MAX_MINIONS=20` FIFO 顶替已实现。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
`MinionManager` 为独立的 Autoload 单例,管理玩家召唤的炮台/傀儡/宠物类实体:
|
||||
|
||||
- **与 EnemyManager 隔离**:EnemyManager 的 SoA 中 `faction_and_type` 字段不扩展到友军,
|
||||
@@ -2894,7 +2914,8 @@ func _physics_process(delta: float) -> void:
|
||||
while _zone_data[base + 6] >= _zone_data[base + 5]:
|
||||
_zone_data[base + 6] -= _zone_data[base + 5] # -= tick_interval 保留余量精度
|
||||
for t_id in targets:
|
||||
StatusManager.apply(t_id, sid, 1.0, int(_zone_data[base + 7])) # intensity=1.0, owner_id=zone_owner
|
||||
# ⚠️ 修正(2026-07-20):真实签名 apply(entity_id, status_type_id, stacks:int=1, duration:float=-1.0, owner_id:int=-1)——5 参
|
||||
StatusManager.apply(t_id, sid, 1, -1.0, int(_zone_data[base + 7])) # stacks=1, duration=default, owner_id=zone_owner(现实 zone_manager.gd:60 即如此调用)
|
||||
|
||||
if _zone_data[base + 4] <= 0.0: # duration 耗尽,移除此 Zone
|
||||
var cx_exp: float = _zone_data[base + 0]; var cy_exp: float = _zone_data[base + 1]
|
||||
@@ -2923,6 +2944,8 @@ func reset() -> void:
|
||||
|
||||
> **结论**:所有 Feature Tag 字符串必须通过 `CoreFeatureTag` 常量访问,禁止在业务代码中写裸字符串。
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:代码**未按本节的 `String` 常量 + `in` 判定实现**。`core_feature_tag.gd` 实为 **`int` 常量**(PERSISTENT_MEMORY=1, DUAL_STREAM=2, ALWAYS_CAST_LAST=3, SHUFFLE_DECK=4, INFINITE_SPELLS=5),`core.feature_tags` 为 `int` 位掩码,用 `&` 判定。**⚠️ 潜在 bug**:这些值非 2 的幂,`&` 会串扰(如 `ALWAYS_CAST_LAST(3) & PERSISTENT_MEMORY(1) = 1` 误判持久内存;当前仅 `wand_memory=1` 未触发)。修复建议:改真·2 的幂位标志(1,2,4,8,16),或回退到本节的 String + `in`(后者天然无冲突)。详见 [审计报告 D 节](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
```gdscript
|
||||
# core_feature_tag.gd (Autoload: CoreFeatureTag)
|
||||
## Core 特性标签常量表 — 所有系统通过此处引用,禁止裸字符串
|
||||
@@ -2974,6 +2997,8 @@ const ALWAYS_CAST_LAST: String = "always_cast_last"
|
||||
|
||||
> **结论:S2 实现波次边界自动存档,采用 A/B 双槽写入防崩溃损坏,支持断点续玩。**
|
||||
|
||||
> **⚠️ 实现现状 (2026-07-20 审计)**:A/B 双槽 + 波次自动存档 + `WM_CLOSE` 兜底 + 链式迁移已实现。差异:① 选槽逻辑现按 `saved_at` **时间戳选最新未损坏槽**(比下文伪代码"固定顺序取第一个有效"更健壮,**代码更优**);② `SCHEMA_VERSION` 已到 **2**(新增 `wand` 键),本节仅记 v1;③ 实存字段为 `wave_num/shop_seed/player_stats/wand`,**缺** `elapsed_sec`(影响无尽续玩计时)、`active_core_idx`、`unlocked_upgrades`、多 Core 数组(待补)。详见 [审计报告](../../docs_dev/doc_code_audit_2026-07-20.md)。
|
||||
|
||||
商业 Roguelite(Hades / Slay the Spire / Balatro)均支持中途退出后恢复到当前波次起始状态。
|
||||
|
||||
**存档时机**:
|
||||
|
||||
Reference in New Issue
Block a user