97 lines
8.4 KiB
Markdown
97 lines
8.4 KiB
Markdown
# 代码规范(Dungeon Sweeper)
|
||
|
||
> 约束范围:`game/` 代码同尺度;与 AGENTS.md「硬性红线」节硬约束(数值表单点 / RNG 封闭流 / Core 零 UI / fail-fast / spec-AC 一致性)并行生效,冲突以用户裁决为准。
|
||
> 分工:本文管结构 / 契约 / 语言 / 数值 / 流程五类;测试的编写与验收见 `design/engineering/test-conventions.md`;真实反例库见同目录 `code-conventions-cases.md`(不常驻加载,对规则适用有疑义时查)。
|
||
|
||
**写任何代码前必须通读本文件。**
|
||
|
||
---
|
||
|
||
## 1. 结构纪律——高内聚、低耦合
|
||
|
||
### 1.1 禁止上帝对象
|
||
一个类只承载一个职责。场景主脚本(main)= **组合根**:模式流转、信号接线、核心写调用的唯一出口;渲染、文案拼装、状态装配一律拆分为独立视图/装配器类。单文件超过 ~400 行即触发审视。
|
||
|
||
### 1.2 一切功能以类封装,禁止裸函数堆
|
||
设计稿与实现同尺度:功能 = 类(状态 + 行为 + 信号),类是封装的最小交付单位。工具性纯函数只允许挂在明确的宿主类下(静态装配器/工厂),不允许无主散落。
|
||
|
||
### 1.3 依赖单向,核心写调用完成
|
||
依赖方向唯一:`views →(信号)→ 组合根 →(写调用)→ core`。视图零核心写调用(纯 setter / 信号外发优先);"读核心状态 → 拼展示文案"集中于装配器(presenter);核心写接口(settle_batch / player_request_refresh / runner 推进)只允许在组合根出现。
|
||
|
||
### 1.4 命名 = 领域命名,禁止系统 ID 前缀
|
||
文件名与类名禁止 `a1_`/`b1_`/`c1_` 等系统 ID 前缀(`a1_board_generator.gd` → `board_generator.gd`)。设计追溯不靠前缀:代码↔设计的追溯由 GDD 文档承担,系统 ID 只作为文档的追溯锚;文件头注不承担追溯职责,不写任何文档链接(§1.4.1)。豁免:D2 schema 类与 autoload;文档/夹具登记名(如 b4_golden)属文档层。
|
||
|
||
### 1.4.1 文件头 = `##` 文档注释,介绍本模块
|
||
|
||
头注以 Python 规范为权威(GDScript 语法近 Python,官方风格指南对文件头零条款,不自造标准):Google Python Style Guide §3.8.2——文件应以描述模块内容与用法的 docstring 开头;PEP 257——模块一般都应有 docstring,摘要压一行。载体只用 `##` 文档注释(Godot 官方载体,进编辑器 F1 帮助),头注以说清模块为度,长度不设硬限。
|
||
|
||
黑名单(出现即违规):日期与变更叙事——改动史查 `git log`/`git blame`,变更背景读迭代实现报告;与其他文档或其他文件头重复的内容——零新信息不写;一切文档反向链接——「实现 GDD:xxx」「指路:架构见 xxx」一类全部废止,代码↔设计追溯由 GDD 文档承担。
|
||
|
||
机器闸:`tools/audit_file_headers.py`(static_scan S10:变更叙事黑名单机械可判子集)。行数上限与类别白名单已停用。
|
||
|
||
### 1.5 禁止事实约定
|
||
任何"大家默认这么做"的惯例必须成文进本文件(或 AGENTS.md)才算存在。写代码时发现未成文但必须遵守的约定 → 当场补条文,不许靠惯性延续。
|
||
|
||
---
|
||
|
||
## 2. 契约纪律——跨层/跨类调用的语义
|
||
|
||
### 2.1 信号与事件契约成文
|
||
每个跨类信号:参数语义、发送时点、消费方依赖,必须在发送方 `##` 文档注释成文,每信号一行;装不下时迁契约文档。状态机的每次迁移路径都必须发出对应事件——**缺一条路径的事件 = 消费方永久等待 = 软锁**。
|
||
|
||
### 2.2 跨层标识符语义单一且成文
|
||
位置(index)/ 句柄(handle)/ 键(key)是三种不同的东西。跨类传递标识符时,传递方的语义必须与接收方契约逐字一致,禁止凭"当前恰好相等"传值。
|
||
|
||
### 2.3 模态覆盖层层级规则
|
||
覆盖层遮挡关系由场景树加入顺序决定。打开任何模态覆盖层时,必须显式隐藏会遮挡它的全屏层;新增覆盖层必须登记其在 z 序中的位置,并提供"打开可见性"的场景断言。
|
||
|
||
### 2.4 状态字段语义显式
|
||
跨战斗/跨场景携带或恢复的状态字段,其语义来源必须显式(表值 / 明确入参),禁止用入参隐式定义。
|
||
|
||
---
|
||
|
||
## 3. 测试纪律
|
||
|
||
已独立成文:`design/engineering/test-conventions.md`(探针标配 / 回归断言 / 提交前全量验证 / 验收清单落码规范)。
|
||
|
||
---
|
||
|
||
## 4. 语言纪律——GDScript 4.x 实战坑(本项目踩实)
|
||
|
||
1. **多行 lambda 内禁止嵌套 match / 复杂控制流**(解析不可靠)——信号处理体一律抽成命名方法 + `bind` 传状态。
|
||
2. **Dictionary 取值返回 Variant,无类型推断**——参与算术或传参前显式声明类型(`var x: float = ...`)。
|
||
3. **RichTextLabel:`append_text()` 不回写 `text` 属性**——读可见文本用 `get_parsed_text()`。
|
||
4. **lambda 捕获循环变量按创建时值**——循环内先落地局部变量再捕获,或用 `bind`。
|
||
5. **重命名脚本必须同步 `.uid` 文件**;新增 `class_name` 后必须跑一次编辑器扫描刷新全局类缓存,否则 `--headless --script` 模式解析失败。
|
||
6. **`print` 格式占位符与实参类型必须匹配**(`%d` 配 String = 静默输出字面量)。
|
||
7. **语言纪律已机器化为 S9 类型闸**——`tools/audit_type_hints.py`,执行载体=静态扫描域 S9(`game/tests/static_scan.sh`),退出码 0=归零。扫描面=产品码(`game/core`+`game/data`+`game/presentation`;probe/sim/tests 不在扫描面——测量面容器直构是既有惯例)。三规则:R1 无类型容器(显式非参数化 `Dictionary`/`Array` 注解)/R2 有值返回缺返回类型(纯副作用缺 `-> void` 属写法面不入闸)/R3 参数缺类型(`_init` 豁免——构造注入面形态自由)。
|
||
8. **`:= {}` 推断形态不算债**——`var x := {}` 类赋值推断属类型推断合法面,不入 R1 扫描;只有显式写的非参数化容器注解才算无类型容器。
|
||
9. **行级白名单通道 `# type-hint: ignore`**——豁免该行不入 S9;豁免理由必须随行注明(现行例:`board_generator` 四函数的 db 参鸭子型——typed 参拒冒烟夹具 `_BoardRowStub` 注入)。
|
||
10. **`# rng-seed-exempt` 标记豁免通道**——S1/S2 随机函数扫描对该行豁免;限定用途=非玩法 RNG 消费面的引擎熵(现行例:组合根种子编辑框空态取 `randi()`——建种子不进玩法封闭流)。
|
||
11. **`--script` 模式禁裸 autoload 标识符**——`ConfigDB`/`RngService` 等 autoload 名在 `--headless --script` 模式编译器不解析(parse error);产品码与测试夹具一律经节点路径取用(`get_node("/root/…")`/`AUTOLOAD_PATH_*` 常量);静态扫描域 S5 硬失败承载在位。
|
||
12. **Variant 参数化现行口径**——账本类字典/数组标注 `Dictionary[Variant, Variant]`/`Array[Variant]` 即合格(满足 R1);元素类型精化列后续事项、不入硬纪律,口径变更须用户裁决后续批次另行写入。
|
||
|
||
---
|
||
|
||
## 5. 数值与汇报纪律
|
||
|
||
### 5.1 数值口径必须显式标注尺度
|
||
任何期望值/均值汇报必须写明口径:**每格 / 每板 / 每战 / 每关**。混用口径 = 误导。
|
||
|
||
### 5.2 调参先测量,改后复测
|
||
改任何玩法数值前,先用扫描工具产出基线(通关率/难度类读数走 `balance_verifier.py` 冒险段,机制类读数走 `reward_expectation.gd` 等);改完必须复测回填数据。禁止拍脑袋调参。
|
||
|
||
### 5.3 数值设计必须跨尺度推演
|
||
在单一尺度校准的数值,必须推演其在更大尺度的复合结果(每战合理 × 关内囤积 = 关卡灾难;反例见 code-conventions-cases.md §5.3)。
|
||
|
||
### 5.4 用户拍板的实现零发挥
|
||
拍板范围外的细节一律不自行补全——以"待办问题"清单列出等裁决。
|
||
|
||
---
|
||
|
||
## 6. 流程纪律
|
||
|
||
1. **大改动三段走**:设计稿/伪代码 → 用户审阅 → 实现;实现禁止先于审阅。改动明细只进 git 提交信息,README 与代码内不写修改记录(doc-conventions 第 5 节「禁写变更记录」)。
|
||
2. **实现批完成后的登记义务**:待办清单条目按 doc-conventions §12.1 推进状态,批次过程与结论进 git 提交信息与 `reports/`(根目录会话状态文件已废除,禁止再在其中登记条目)。
|
||
3. **呈现层缺陷的教训回写 D1 GDD 设计输入**(信号载荷 schema / 场景级测试 / 时点状态可见性)。
|