8.2 KiB
8.2 KiB
00 · 设计规范与符号约定
所属文档集 ← 返回索引
用途:阅读本文档集前的必读指南,定义所有文档统一使用的符号、术语和格式约定。
目录
1. 文档定位原则
1.1 本文档集的边界
| ✅ 应包含 | ❌ 不应包含 |
|---|---|
| 系统的功能目标(做什么) | 特定引擎的组件名称(MonoBehaviour、Node 等) |
| 数据模型与字段语义 | 特定语言的代码语法 |
| 系统间的通信契约 | 特定插件/库的调用方式 |
| 状态机的状态与转换规则 | 文件系统路径、资产命名规范 |
| 行为触发的条件与结果 | 引擎内部执行顺序(Update、FixedUpdate) |
| 配置参数的含义与推荐范围 | Inspector 字段序列化细节 |
| 设计决策的原因(Why) | 代码模块的命名空间划分 |
1.2 阅读层次
本文档集(DesignSpec)
↓ 解释"做什么、为什么"
Docs/Architecture(引擎架构文档)
↓ 解释"代码如何组织、各模块如何实现"
实际代码
↓ 最终实现
2. 抽象数据类型
本文档集使用以下引擎无关的抽象类型:
| 符号 | 含义 | 示例 |
|---|---|---|
Integer |
整数 | hp: Integer |
Number |
浮点数 | speed: Number |
Boolean |
布尔值 | isGrounded: Boolean |
String |
字符串 | id: String |
ID |
唯一标识符(字符串或枚举) | formId: ID |
List<T> |
有序列表 | skills: List<SkillData> |
Map<K,V> |
键值映射 | flagMap: Map<String, Boolean> |
Optional<T> |
可为空的值 | target: Optional<Entity> |
Ref<T> |
对另一数据模型的引用 | weapon: Ref<WeaponData> |
Enum |
枚举类型(正文中明确列出所有值) | DamageType |
Flags |
可组合的位标记集 | DamageFlags |
Duration |
时间长度(秒) | stunDuration: Duration |
Vector2 |
二维方向或坐标 | knockbackDir: Vector2 |
3. 数据模型符号
数据模型描述一组字段的结构,不含逻辑,类似数据表或结构体:
DataModel ModelName {
fieldName : Type // 字段说明
fieldName : Type = default // 带默认值
fieldName : Optional<Type> // 可选字段
──────────────────────────────── // 分隔线表示分组
groupedField : Type // 同组字段
}
示例
DataModel DamagePacket {
rawDamage : Integer // 基础伤害
damageType : DamageType // 伤害类型枚举
knockbackDir : Vector2 // 击退方向(单位向量)
knockbackForce : Number // 击退力度
stunDuration : Duration // 硬直时长(秒)
flags : Flags<DamageFlags>
──────────────────────────────────
sourceId : ID // 攻击来源的唯一标识(用于特殊规则查询)
sourcePosition : Vector2 // 攻击来源位置(计算击退方向时备用)
}
4. 接口契约符号
接口描述一个系统对外暴露的操作与属性,不规定内部实现:
Interface IInterfaceName {
// 只读属性
[readonly] propertyName : Type
// 可写属性
[readwrite] propertyName : Type
// 方法:方法名(参数名: 类型, …) → 返回类型
// 若无返回值写 void
methodName(param: Type) → ReturnType
// 可失败的方法(返回 Result)
methodName(param: Type) → Result<ReturnType>
// 事件(外部可订阅)
[event] onSomething : EventType
}
示例
Interface IHealthOwner {
[readonly] currentHP : Integer
[readonly] maxHP : Integer
[readonly] isAlive : Boolean
takeDamage(packet: DamagePacket) → void
heal(amount: Integer) → void
[event] onHPChanged : Event<HPChangedPayload>
[event] onDied : Event<void>
}
5. 状态机符号
5.1 状态定义
State StateName {
priority : Integer // 数字越大、越难被低优先级状态打断
interruptBy: List<State> // 可被哪些状态强制打断
}
5.2 状态转换图
[StateA]
──条件──► [StateB] // 正常转换
══强制══► [StateC] // 强制(忽略优先级)
~~超时~~► [StateD] // 超时自动转换
[StateB]
──落地────────────► [IdleState]
──攻击输入─────────► [AttackState]
5.3 转换条件格式
| 符号 | 含义 |
|---|---|
──条件──► |
满足条件后转换 |
══强制══► |
外部强制调用,跳过优先级检查 |
~~超时~~► |
经过 N 秒后自动转换 |
[condition AND condition] |
复合条件 |
[NOT condition] |
条件取反 |
6. 事件符号
事件用于系统间的解耦通知,只传递最小必要数据:
Event EventName {
payload: PayloadType // 携带的数据,void 表示无数据
emitter: SystemName // 哪个系统发出
listeners: [SystemA, SystemB, ...] // 典型订阅方(非强制)
}
事件目录格式
| 事件名 | 载荷类型 | 发出方 | 用途 |
|---|---|---|---|
OnPlayerDied |
void |
玩家系统 | 触发复活流程 |
OnHPChanged |
{current, max} |
玩家系统 | 更新 HUD |
7. 系统依赖符号
系统之间的依赖关系通过以下格式表达:
SystemA ──读取──► DataModel // 读取数据
SystemA ──写入──► DataModel // 写入数据
SystemA ──发出──► EventX // 发出事件
SystemA ◄─订阅── EventY // 订阅事件
SystemA ──调用──► IInterface // 调用接口方法
系统间不应出现:
SystemA ──直接引用──► SystemB // ❌ 禁止直接持有另一系统引用
依赖等级
| 等级 | 说明 |
|---|---|
| 强依赖(编译时) | A 的存在必须依赖 B 的接口定义 |
| 弱依赖(运行时事件) | A 通过事件通知 B,B 不存在时 A 仍可正常运行 |
| 数据依赖(只读配置) | A 读取共享配置数据,无运行时交互 |
8. 参数表格式
配置参数表统一格式:
| 参数名 | 类型 | 推荐值 | 说明 | 调整影响 |
|---|---|---|---|---|
walkSpeed |
Number | 6.0 | 地面行走速度(单位/秒) | 越高越灵活,越低越沉重 |
jumpForce |
Number | 16.0 | 跳跃初速度 | 越高跳跃越高,需同步调整重力 |
调整原则:每次只修改一个参数,实测手感后确认。参数间存在联动关系时,文档中注明。
9. 设计决策标注
文档中的设计决策用以下格式标注原因,方便日后回溯:
> **设计决策**:[决策内容]
> **原因**:[为什么这样设计]
> **替代方案**:[考虑过但未选用的方案及原因]
示例
设计决策:弹反成功后增加 +33 灵力,而非固定值
原因:鼓励玩家主动弹反,弹反本身是高风险操作,大幅奖励使弹反策略具有可行的资源通路
替代方案:弹反+0 灵力(纯战斗技巧),但测试发现玩家没有足够动机学习弹反
附:文档写作检查清单
在向本文档集新增或修改文档时,请确认:
- 所有数据类型使用抽象类型(不出现
int,float,string,MonoBehaviour等) - 所有引擎功能通过行为描述替代("物理检测地面"而非"OverlapBox")
- 系统接口以契约格式定义,不包含实现细节
- 参数表包含"调整影响"列
- 重要设计决策附有原因说明
- 文档末尾无悬空的"TODO"或临时注记