279 lines
13 KiB
Markdown
279 lines
13 KiB
Markdown
# 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 依赖 B,B 依赖 A | 引入事件频道或接口打断循环 |
|
||
| **隐式顺序耦合** | 系统 A 必须在 B 之后执行才正确 | 改用事件触发替代时序依赖 |
|
||
| **状态同步噩梦** | 多个系统各自维护同一份数据的副本 | 确立唯一所有者,其他系统订阅变化 |
|
||
| **胖配置数据** | 配置数据里混入运行时逻辑 | 严格区分 Config 和 RuntimeState |
|