Files
zeling_v2/Docs/DesignSpec/01_SystemArchitecture.md
2026-05-08 11:04:00 +08:00

279 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01 · 系统架构总览
> **所属文档集** [← 返回索引](./README.md)
> **摘要**:定义游戏的核心设计哲学、系统全景图、模块边界与系统间通信规范。
---
## 目录
1. [设计哲学](#1-设计哲学)
2. [系统全景图](#2-系统全景图)
3. [系统分层模型](#3-系统分层模型)
4. [通信模式规范](#4-通信模式规范)
5. [数据层与逻辑层分离](#5-数据层与逻辑层分离)
6. [模块边界原则](#6-模块边界原则)
7. [系统优先级与生命周期](#7-系统优先级与生命周期)
---
## 1. 设计哲学
### 1.1 四大核心原则
| 原则 | 含义 | 实践方式 |
|------|------|---------|
| **零耦合** | 系统间不持有彼此的直接引用 | 通过事件频道或统一接口通信 |
| **数据驱动** | 行为由配置数据决定,而非硬编码 | 参数外置为可配置数据模型 |
| **行为契约** | 系统对外只暴露接口,不暴露实现 | 所有跨系统调用通过接口进行 |
| **单一职责** | 每个系统只负责一件事 | 系统边界清晰,不兼管相邻职责 |
### 1.2 设计动词
理解游戏整体架构的关键词汇:
- **探索**:玩家自由穿越相互连接的房间,逐渐解锁新区域
- **弹反**:高风险高回报的格挡反击,是核心战斗循环的差异化机制
- **形态切换**:三种形态提供不同战斗风格,玩家选择适合当前情况的形态
- **资源循环**:灵力(攻击积累)→ 技能消耗 → 再攻击积累,形成持续循环
---
## 2. 系统全景图
```
┌─────────────────────────────────────────────────────────────────────┐
│ 输入层Input Layer
│ 处理原始输入 → 转化为游戏动作事件 → 缓冲管理 │
└──────────────────────────────┬──────────────────────────────────────┘
│ 输入动作事件
┌──────────────────────────────▼──────────────────────────────────────┐
│ 玩家层Player Layer
│ ┌──────────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
│ │ 移动系统 │ │ 战斗系统 │ │ 形态系统 │ │ 资源系统 │ │
│ │(Movement) │ │ (Combat) │ │ (Form) │ │(Resource)│ │
│ └──────────────┘ └─────────────┘ └─────────────┘ └──────────┘ │
└──────────────────────────────┬──────────────────────────────────────┘
│ 玩家状态事件
┌──────────────────────────────▼──────────────────────────────────────┐
│ 世界层World Layer
│ ┌──────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 敌人系统 │ │ 世界系统 │ │ 进程系统 │ │
│ │ (Enemy) │ │ (World) │ │(Progression)│ │
│ └──────────────┘ └─────────────┘ └─────────────┘ │
└──────────────────────────────┬──────────────────────────────────────┘
│ 世界状态事件
┌──────────────────────────────▼──────────────────────────────────────┐
│ 支撑层Support Layer
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ UI 系统 │ │ 音频系统 │ │ 存档系统 │ │ 叙事系统 │ │
│ │ (UI) │ │ (Audio) │ │ (Save) │ │(Narrative│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 经济系统 │ │ 反馈系统 │ │
│ │(Economy) │ │(Feedback)│ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 3. 系统分层模型
### 层级定义
| 层级 | 名称 | 职责 | 依赖方向 |
|------|------|------|---------|
| L0 | **配置层** | 只读的设计数据(参数表、模板)| 被所有层引用,不依赖任何层 |
| L1 | **输入层** | 原始输入 → 标准化动作事件 | 依赖 L0 |
| L2 | **玩家层** | 玩家实体的所有行为 | 依赖 L0, L1 |
| L3 | **世界层** | 敌人、关卡、进程 | 依赖 L0, L2通过接口|
| L4 | **支撑层** | UI、音频、存档、叙事 | 订阅 L2, L3 的事件 |
> **设计决策**高层系统L4只通过事件订阅低层系统L2、L3不直接调用。
> **原因**UI 系统永远不应"告诉"玩家系统去做什么,只需观察状态变化后更新显示。
---
## 4. 通信模式规范
系统间通信允许三种方式,按优先级排序:
### 4.1 事件频道(优先使用)
```
发出方 接收方
──────── ────────
系统 A 系统 B
└─ 发出 Event<Payload> └─ 订阅 Event<Payload>
└─ 执行响应逻辑
```
**规则**
- 发出方不知道谁在监听
- 接收方不知道谁发出了事件
- 事件只传递"发生了什么",不传递"如何处理"的指令
- 单次事件One-shot不轮询
### 4.2 接口调用(功能依赖)
```
调用方 被调用方
──────── ────────
系统 A 实现了 IInterface 的系统 B
└─ 持有 IInterface 引用 └─ 提供 IInterface 实现
└─ 调用 IInterface.Method()
```
**规则**
- 调用方只知道接口,不知道实现
- 接口定义在公共层,不属于任何具体系统
- 允许同步调用并获取返回值
### 4.3 共享数据读取(只读访问)
```
消费方 数据源
──────── ────────
系统 A 配置数据 / 运行时状态数据
└─ 只读访问共享数据 └─ 数据由其所有者系统维护
```
**规则**
- 消费方只读,不写
- 写入权唯一归属于数据的所有系统
- 其他系统通过事件订阅感知数据变化,不轮询
### 4.4 禁止的通信方式
| 禁止模式 | 原因 |
|----------|------|
| 系统 A 直接持有系统 B 的具体引用 | 产生双向耦合,修改 B 影响 A |
| 系统 A 轮询系统 B 的状态 | 性能浪费,职责不清 |
| 事件携带"命令"语义("去做 X"| 事件只通知,不指令 |
| 支撑层系统调用玩家/世界层方法 | 违反依赖方向UI 不应控制游戏逻辑 |
---
## 5. 数据层与逻辑层分离
### 5.1 两类数据
| 类型 | 说明 | 生命周期 | 示例 |
|------|------|---------|------|
| **配置数据Config** | 设计时填写,运行时只读 | 常驻内存 | 移动速度、伤害倍率、关卡布局 |
| **运行时状态State** | 运行时动态变化 | 随场景/游戏生命周期 | 当前 HP、已解锁能力、世界标志位 |
### 5.2 配置数据模型的设计原则
```
ConfigData 特征:
✅ 字段全部只读
✅ 可被多个系统引用(共享)
✅ 可在运行前被工具验证合理性
✅ 变更不需要修改代码,只修改数据
❌ 不包含运行时可变字段
❌ 不包含对具体系统的引用
```
### 5.3 运行时状态的所有权
每份运行时状态只有**一个系统**拥有写权限:
| 状态 | 所有系统 | 其他系统访问方式 |
|------|---------|----------------|
| 玩家 HP | 玩家系统 | 事件订阅 `OnHPChanged` |
| 世界标志位 | 叙事系统 / 世界系统 | 只读接口查询 |
| 背包道具 | 进程系统 | 只读接口查询 |
| 货币余额 | 经济系统 | 事件订阅 `OnGeoChanged` |
---
## 6. 模块边界原则
### 6.1 边界定义规则
系统的边界由以下三要素确定:
1. **输入**:系统响应的事件 + 调用的接口
2. **输出**:系统发出的事件 + 对外提供的接口
3. **状态**:系统独占写权限的运行时数据
### 6.2 系统边界一览
| 系统 | 输入来源 | 输出目标 | 独占状态 |
|------|---------|---------|---------|
| 输入系统 | 设备原始信号 | 动作事件(发出)| — |
| 玩家系统 | 输入动作事件 | 玩家状态事件 | HP、灵力、魄元、灵泉、Geo、能力 |
| 战斗系统 | 碰撞检测结果 | 伤害事件、命中事件 | — |
| 敌人系统 | 玩家位置(只读)| 敌人行动事件 | 敌人 HP、AI 状态 |
| 世界系统 | 玩家位置(只读)| 场景切换事件 | 房间发现状态、存档点激活状态 |
| 进程系统 | 玩家动作事件 | 解锁事件 | 已解锁能力、完成度 |
| 存档系统 | 存档/读档请求 | — | 持久化数据快照 |
| UI 系统 | 全部状态事件(订阅)| 输入事件(菜单操作)| UI 层堆叠状态 |
| 音频系统 | 全部状态事件(订阅)| — | 当前音乐状态 |
| 经济系统 | 购买/掉落事件 | 货币变化事件 | Geo 余额 |
| 叙事系统 | 世界/玩家事件 | 对话事件、结局评估 | 世界标志位 |
---
## 7. 系统优先级与生命周期
### 7.1 启动顺序
系统初始化应遵循依赖顺序,低层先于高层初始化:
```
1. 存档系统(读取持久化数据)
2. 配置数据加载(所有 Config 可用)
3. 输入系统
4. 玩家系统(使用配置和存档数据初始化)
5. 世界系统(加载场景数据)
6. 敌人系统(使用世界数据初始化)
7. 支撑层系统UI、音频、叙事等
```
### 7.2 关卡切换时的系统行为
| 事件 | 各系统行为 |
|------|----------|
| 触发场景切换 | 世界系统发出 `OnSceneTransitionBegin` |
| 过渡动画播放 | UI 系统显示过渡遮罩;输入系统暂停接收 |
| 旧场景卸载 | 敌人系统、VFX 等局部系统销毁 |
| 新场景加载 | 世界系统重建房间;敌人系统重新初始化 |
| 玩家状态恢复 | 玩家系统将 HP/技能应用至新场景(不重置)|
| 切换完成 | 世界系统发出 `OnSceneTransitionEnd`;输入系统恢复 |
### 7.3 死亡与复活流程
```
玩家 HP 降至 0
→ 玩家系统发出 OnPlayerDied
→ 输入系统:禁止所有输入
→ UI 系统:播放死亡遮罩动画
→ 音频系统:切换至死亡音乐
→ 存档系统:记录死亡位置(遗骸数据)
→ 世界系统:在上次死亡位置生成遗骸实体
等待(玩家按键或自动)→ 触发复活
复活流程:
→ 世界系统:加载最近存档点所在场景
→ 玩家系统:恢复存档时的 HP / 灵泉次数(见存档规范)
→ 输入系统:恢复输入
→ UI 系统:淡出遮罩
→ 音频系统:恢复区域音乐
```
---
## 附:常见架构陷阱与规避方法
| 陷阱 | 典型表现 | 规避方法 |
|------|---------|---------|
| **上帝对象** | 一个系统知道所有其他系统的状态 | 拆分为多个专责系统 |
| **循环依赖** | A 依赖 BB 依赖 A | 引入事件频道或接口打断循环 |
| **隐式顺序耦合** | 系统 A 必须在 B 之后执行才正确 | 改用事件触发替代时序依赖 |
| **状态同步噩梦** | 多个系统各自维护同一份数据的副本 | 确立唯一所有者,其他系统订阅变化 |
| **胖配置数据** | 配置数据里混入运行时逻辑 | 严格区分 Config 和 RuntimeState |