9.3 KiB
ADR-0003: 场景结构与棋盘渲染(Scene Structure & Board Rendering)
Status
Accepted(2026-09-12,solo 模式用户授权代决;迭代期可推翻重议)
部分修订(2026-09-23):Decision 3 棋盘渲染形态条款由 ADR-0006 部分取代——棋盘本体定向迁 Node2D 渲染(D 区 Phase A 先行,B 区舞台后续批),「禁盲目迁移」条款解除,其登记的探针耦合成本转为迁移批义务(实证收敛为 _cells 键面 + click_cell + cell_size 三点,公共面契约保持即可零改造)。Alternative 2(逐格 Node2D)的否决理由「无必要」因表现层升级需求不再成立;autoload 清单、类形态、CJK 字体前置等其余条款不变。
Date
2026-09-12
Engine Compatibility
| Field | Value |
|---|---|
| Engine | Godot 4.7.2-stable |
| Domain | Core / Scripting + UI |
| Knowledge Risk | LOW-MEDIUM(结构决策 LOW;渲染呈现项 MEDIUM——CanvasItem 线条 AA 羽化移除已核实,godot-specialist 校验含 2 项实质修正后通过) |
| References Consulted | docs/engine-reference/godot/(四文件);godotengine/godot#6360(--script 无 autoload) |
| Post-Cutoff APIs Used | None |
| Verification Required | CJK 字体随包发行的显示核对(首次正式导出 checklist 增补项);D1 正式化时若执行 _draw 迁移则另核命中测试/无障碍 |
ADR Dependencies
| Field | Value |
|---|---|
| Depends On | ADR-0001(组合根接线纪律)、ADR-0002(project.godot 基线同批落盘) |
| Enables | 正式工程骨架搭建;D1 正式化 |
| Blocks | ADR-0004 扫描域(引用本 ADR 的 core 隔离规则) |
| Ordering Note | 棋盘渲染形态裁决(本 ADR §Decision 3)与 ADR-0004 探针耦合——见 Decision 3 的迁移工作项 |
Context
Problem Statement
正式工程骨架需要定稿:autoload 清单、core/presentation 的类形态与目录结构、棋盘渲染的实现路径。切片已验证一套形态,但初稿 ADR 把"自绘 _draw()"当作切片事实——godot-specialist 校验发现切片 BoardView 实为 GridContainer + 逐格常驻控件,本 ADR 按校验修正。
Constraints
- Core 层零 UI 依赖、headless 可跑(D2 Rule 7);--script 模式下 core 禁裸引用 autoload 全局标识符(编译期即炸——见 ADR-0004)
- 同屏 draw calls < 200;棋盘 ≤12×12(MVP 量级)+数字/小人/旗/变异多层叠加(视觉锚绘制优先级栈)
- 领域命名规范(docs/code-conventions.md:禁 ID 前缀、头注溯源)
Requirements
- 切片验证过的结构不推倒(用户拍板"按常规老路子")
- 呈现层与核心的写边界:核心写调用唯一发生在组合根
- 中文文案可显示(运行时默认字体无 CJK 字形——specialist 核实)
Decision
1. autoload 清单 = {ConfigDB, RngService}(定名锁定),仅此两个。 战斗编排器等核心类为普通类、由组合根按局实例化——非 autoload、非场景节点。
2. 类形态与目录结构:core/ 纯逻辑类 = RefCounted;ConfigDB/RngService = autoload Node 单例(引擎约束:autoload 脚本必须 extends Node);presentation/ = Control 派生视图单元。
res://
├── core/ # RefCounted 纯逻辑(board_generator / minesweeper_rules /
│ # action_economy / battle_orchestrator / unit_container /
│ # status_container / reward_economy / level_runner / 数据类)
│ # —— 零 Control 引用、零 .tscn preload、零 autoload 全局标识符裸引用
├── data/
│ ├── schemas/ # D2 schema 类(Resource 派生——D2 体系,非本 ADR 变更项)
│ └── tables/ # .tres 数值表(单一事实源)
├── presentation/
│ ├── views/ # 九单元:BoardView / HUDView / BattleLogView / ItemWindowOverlay /
│ │ # NodeOverlay / LevelStripView / TunePanel / UiKit
│ ├── hud_presenter.gd
│ └── main.tscn + main.gd # 组合根:模式流转 + 信号接线 + 核心写调用唯一落点
├── smoke/ # 冒烟脚本 + 探针场景(ADR-0004)
└── docs/architecture/
3. 棋盘渲染形态:MVP 沿用切片已验证形态——GridContainer + 逐格常驻控件(BoardView 持 _cells,refresh 内逐格更新);自绘 _draw() 迁移登记为 D1 正式化候选工作项(非本 ADR 承诺)。
- specialist 校验事实:切片 BoardView = GridContainer + 逐格 Button(
_paint_cell逐格更新),三探针与该形态耦合(ui_probe 断言_cells非空、click_probe 依赖click_cell入口)。初稿"_draw 是切片形态的正式化"不成立,按事实修正。 - 形态对比留档:逐格控件(现状)= 命中测试/悬停/焦点由引擎承担、探针兼容;代价 = 控件树随格数增长(12×12=144 控件,实测无压力)。
_draw()= 单 draw call、绘制优先级栈完全可控;代价 = 自建命中测试/悬停 + 三个探针改造(_cells断言与click_cell入口失效)+ 无障碍面缺失 + 需补Viewport.push_input端到端输入探针。 - 裁决:D1 正式化 GDD 评审时按当时视觉需求(biome 色板、雾纹理、动效复杂度)二选一;在此之前禁盲目迁移(探针改造是隐藏成本)。任一形态下 CanvasItem 线条 AA 羽化移除(4.7)需注意——格边框用填充
draw_rect不受影响。
4. CJK 字体前置(specialist 补登,两种形态都受影响):Godot 运行时默认字体不含 CJK 字形——全部中文文案(按钮/标签/结算明细)必须随包发行 CJK 字体并设为 theme 默认字体。登记为 D1 正式化硬性前置项 + 首次导出 checklist 项。
Architecture Diagram
见 docs/architecture/architecture.md System Layer Map + Module Ownership(本 ADR 是其工程形态落点)。
Key Interfaces
- 组合根 = 唯一核心写调用落点(settle_batch / submit_window_selection / runner 推进)——切片纪律转正
- 视图单元 = 信号外发 + setter 只读注入(BoardView 只读 A2、动作信号外发不碰核心写)
Alternatives Considered
Alternative 1: 战斗编排器设为 autoload
- Cons: 编排器持有跨局状态却永生——生命周期与战斗域契约冲突(Uninit/BattleOver 状态机要求按局重建);与"autoload = 全局基础设施"边界冲突。
- Rejection Reason: 切片形态(按局实例化)已验证且语义正确。
Alternative 2: 棋盘 = 每格一个 Node2D
- Pros: 独立节点动画/模组方便。
- Cons: 每节点处理开销与 Control/Node2D 混管复杂度;无必要(specialist 指出 2D 同材质有批处理,draw call 论据最弱,但节点开销与混管论据成立)。
- Rejection Reason: 逐格控件已覆盖需求且已验证。
Alternative 3: TileMapLayer 承载棋盘
- Cons: 4.5 物理分块默认变更(纯视觉不踩,但物理用途即触);瓦片语义与"变体标记/数字/旗多层叠加"不匹配。
- Rejection Reason: 语义不匹配是硬伤;现形态无此问题。
Consequences
Positive
- 结构与切片零迁移成本;core 隔离规则可静态扫描(ADR-0004)
- 棋盘形态留有 D1 期复议空间且复议成本已如实登记
Negative
- 逐格控件形态在 D1 需要高表现力时可能仍需迁移 _draw(成本已登记:探针改造 + 命中测试自建 + push_input 端到端探针)
- CJK 字体为新增资产义务(发行体积 +)
Risks
- D1 正式化时遗漏"探针与形态耦合"约束 → 缓解:本 ADR Decision 3 + ADR-0004 探针节双登记
- core 类被随手加 autoload 裸引用 → 缓解:ADR-0004 静态扫描(parse 期即炸的事实使该风险自暴露)
GDD Requirements Addressed
| GDD System | Requirement | How This ADR Addresses It |
|---|---|---|
| d2-data-config.md | Rule 7 零 UI 依赖;Rule 2 单点访问 | core 隔离规则 + autoload 清单固化(ConfigDB/RngService 定名) |
| game-concept.md | 视觉锚(绘制优先级栈、双通道) | 棋盘形态两案对比留档,D1 正式化按锚需求裁决 |
| b1-settlement.md | Core Rule 1 编排器按局生命周期 | 编排器非 autoload、组合根按局实例化 |
| docs/code-conventions.md | 领域命名 / 组合根纪律 | 目录结构与 Key Interfaces 转正 |
Performance Implications
- CPU: 144 常驻控件逐格更新——切片实测无压力;_draw 迁移后更优(单 draw call)
- Memory: 可忽略
- Load Time: CJK 字体载入一次性成本
- Network: 不适用
Migration Plan
切片即目标形态(结构零迁移);CJK 字体接入与 _draw 复议归 D1 正式化批次。
Validation Criteria
- 冒烟 88/88 + 三探针在正式工程维持全绿
- 静态扫描:core/ 零 Control extends / 零 .tscn preload / 零 autoload 全局标识符裸引用(ADR-0004 域)
- 中文文案在导出包内显示正常(导出 checklist)
Related Decisions
- ADR-0001(接线纪律)、ADR-0002(渲染器与窗口键)、ADR-0004(扫描域与探针)
- docs/architecture/architecture.md(Module Ownership / Required ADRs——本 ADR 落定后其 §Required ADRs 第 3 项闭合)