381 lines
12 KiB
Markdown
381 lines
12 KiB
Markdown
# 游戏规则架构
|
||
|
||
本文档用于说明当前项目中“游戏规则”在文档、配置文件、样例 JSON、解析代码和运行时规则引擎之间的实际组织方式。
|
||
|
||
目标:
|
||
|
||
- 说明规则设计从哪里开始
|
||
- 说明公共配置和玩法配置如何分层
|
||
- 说明样例配置、代码解析、运行时规则如何对应
|
||
- 作为后续后台配置管理的架构基线
|
||
|
||
---
|
||
|
||
## 1. 总体原则
|
||
|
||
当前项目采用的是“文档定义规则,配置承载规则,代码解析配置,规则引擎执行配置”的结构。
|
||
|
||
可以概括为四句话:
|
||
|
||
1. 玩法规则先在文档里定义
|
||
2. 规则通过 JSON 配置文件表达
|
||
3. 客户端解析配置生成运行态定义
|
||
4. 规则引擎按运行态定义驱动游戏流程
|
||
|
||
也就是说:
|
||
|
||
**文档是设计源头,配置是规则载体,代码是执行层。**
|
||
|
||
如果换一种更偏运行时的说法:
|
||
|
||
- `MapEngine` 和页面壳子是骨架
|
||
- 默认值层和规则层决定骨架怎么动
|
||
- 配置像神经系统,把活动差异传进运行时
|
||
- 遥测和反馈层负责把玩家状态再回流到界面
|
||
|
||
---
|
||
|
||
## 2. 当前分层结构
|
||
|
||
当前规则体系分成 6 层。
|
||
|
||
### 2.1 公共规则层
|
||
|
||
位置:
|
||
|
||
- [全局规则与配置维度清单](D:/dev/cmr-mini/doc/config/全局规则与配置维度清单.md)
|
||
- [配置选项字典](D:/dev/cmr-mini/doc/config/配置选项字典.md)
|
||
- [当前最全配置模板](D:/dev/cmr-mini/doc/config/当前最全配置模板.md)
|
||
|
||
作用:
|
||
|
||
- 定义系统共用能力有哪些
|
||
- 定义公共字段、可选项和默认值
|
||
- 作为所有玩法的公共配置全集
|
||
|
||
这一层回答的是:
|
||
|
||
- 系统支持哪些规则块
|
||
- 系统有哪些字段
|
||
- 这些字段默认怎么工作
|
||
|
||
### 2.2 玩法设计层
|
||
|
||
位置:
|
||
|
||
- [程序默认规则基线](D:/dev/cmr-mini/doc/gameplay/程序默认规则基线.md)
|
||
- [运行时编译层总表](D:/dev/cmr-mini/doc/gameplay/运行时编译层总表.md)
|
||
- [玩法设计文档模板](D:/dev/cmr-mini/doc/gameplay/玩法设计文档模板.md)
|
||
- [玩法构想方案](D:/dev/cmr-mini/doc/gameplay/玩法构想方案.md)
|
||
- `doc/games/<游戏名称>/规则说明文档.md`
|
||
- `doc/games/<游戏名称>/游戏说明文档.md`
|
||
|
||
作用:
|
||
|
||
- 定义客户端自身应该内建的默认行为
|
||
- 定义某个玩法怎么玩
|
||
- 定义局流程、状态机、计分、胜负、表现
|
||
- 明确该玩法选用了哪些公共规则块
|
||
|
||
这一层回答的是:
|
||
|
||
- 这个玩法的目标是什么
|
||
- 这个玩法如何开始、推进、结束
|
||
- 这个玩法和系统公共能力的关系是什么
|
||
|
||
### 2.3 玩法配置层
|
||
|
||
位置:
|
||
|
||
- `doc/games/<游戏名称>/最小配置模板.md`
|
||
- `doc/games/<游戏名称>/最大配置模板.md`
|
||
- `doc/games/<游戏名称>/全局配置项.md`
|
||
- `doc/games/<游戏名称>/游戏配置项.md`
|
||
- `event/*.json`
|
||
|
||
作用:
|
||
|
||
- 把玩法规则翻译为可执行配置
|
||
- 明确这个玩法实际使用的公共字段子集
|
||
- 给出最小可跑样例和较完整样例
|
||
|
||
这一层回答的是:
|
||
|
||
- 规则具体落到哪些字段
|
||
- 哪些字段是系统默认
|
||
- 哪些字段由玩法覆盖
|
||
- 当前联调跑的是哪份样例配置
|
||
|
||
### 2.4 配置解析层
|
||
|
||
位置:
|
||
|
||
- [remoteMapConfig.ts](D:/dev/cmr-mini/miniprogram/utils/remoteMapConfig.ts)
|
||
- [courseToGameDefinition.ts](D:/dev/cmr-mini/miniprogram/game/content/courseToGameDefinition.ts)
|
||
|
||
作用:
|
||
|
||
- 读取远端或本地 JSON
|
||
- 补齐模式默认值
|
||
- 归一化为运行时使用的定义对象
|
||
|
||
这一层回答的是:
|
||
|
||
- 配置进入程序后如何被解释
|
||
- 系统默认值何时注入
|
||
- 不同玩法模式如何做差异化默认处理
|
||
|
||
### 2.5 运行时默认与设置层
|
||
|
||
位置:
|
||
|
||
- [gameModeDefaults.ts](D:/dev/cmr-mini/miniprogram/game/core/gameModeDefaults.ts)
|
||
- [systemSettingsState.ts](D:/dev/cmr-mini/miniprogram/game/core/systemSettingsState.ts)
|
||
|
||
作用:
|
||
|
||
- 统一维护玩法默认值
|
||
- 统一维护设置页默认值
|
||
- 明确哪些值持久化,哪些锁态不持久化
|
||
- 为页面层和规则层提供同一套默认基线
|
||
|
||
补充约束:
|
||
|
||
- 设置值允许玩家修改并持久化
|
||
- 设置锁态只由系统默认值和活动配置决定
|
||
- 锁态不持久化,也不允许玩家在页面里切换
|
||
- 锁态只在当前游戏配置运行生命周期内生效;本局结束或主动退出后失效
|
||
|
||
### 2.6 运行时编译层
|
||
|
||
位置:
|
||
|
||
- [runtimeProfileCompiler.ts](D:/dev/cmr-mini/miniprogram/game/core/runtimeProfileCompiler.ts)
|
||
- [运行时编译层总表](D:/dev/cmr-mini/doc/gameplay/运行时编译层总表.md)
|
||
- [故障恢复机制](D:/dev/cmr-mini/doc/gameplay/故障恢复机制.md)
|
||
|
||
作用:
|
||
|
||
- 统一合并系统默认值、玩法默认值、活动配置和玩家设置
|
||
- 产出页面、引擎和规则层可直接消费的运行时 profile
|
||
- 逐步替代页面和引擎中分散的默认值判断
|
||
|
||
当前进度:
|
||
|
||
- `settings / telemetry / feedback` 已开始走编译层入口
|
||
- 设置页大部分引擎型设置项已改成统一更新玩家设置,再由编译层回灌引擎
|
||
- `settings` 当前已通过 `MapEngine.applyCompiledSettingsProfile(...)` 统一落地,不再由页面层散着逐项推送
|
||
- `presentation` 和一部分 `game` 字段也已开始接入
|
||
- `map` 也已开始接入地图底座和配置状态这组基础字段
|
||
- `MapEngine.applyRemoteMapConfig(...)` 已开始退回为原始场地与资源入口
|
||
|
||
这一层回答的是:
|
||
|
||
- 程序默认值放在哪里
|
||
- 玩家本地设置如何和系统默认值合并
|
||
- 锁态为什么不能从历史缓存恢复
|
||
- 为什么页面、引擎、规则不应再直接各自读原始配置
|
||
|
||
### 2.7 故障恢复层
|
||
|
||
位置:
|
||
|
||
- [sessionRecovery.ts](D:/dev/cmr-mini/miniprogram/game/core/sessionRecovery.ts)
|
||
- [map.ts](D:/dev/cmr-mini/miniprogram/pages/map/map.ts)
|
||
- [mapEngine.ts](D:/dev/cmr-mini/miniprogram/engine/map/mapEngine.ts)
|
||
|
||
作用:
|
||
|
||
- 在对局进行中低频持久化轻量恢复快照
|
||
- 在异常退出后提供“继续上一局 / 放弃上一局”入口
|
||
- 只恢复核心运行态,不恢复瞬时 UI
|
||
|
||
这一层回答的是:
|
||
|
||
- 非正常退出后如何继续比赛
|
||
- 为什么恢复只保留核心赛局状态
|
||
- 为什么不尝试恢复白卡、答题卡和动效中间态
|
||
|
||
### 2.8 运行时规则层
|
||
|
||
位置:
|
||
|
||
- [classicSequentialRule.ts](D:/dev/cmr-mini/miniprogram/game/rules/classicSequentialRule.ts)
|
||
- [scoreORule.ts](D:/dev/cmr-mini/miniprogram/game/rules/scoreORule.ts)
|
||
- [mapEngine.ts](D:/dev/cmr-mini/miniprogram/engine/map/mapEngine.ts)
|
||
- [map.ts](D:/dev/cmr-mini/miniprogram/pages/map/map.ts)
|
||
- [resultSummary.ts](D:/dev/cmr-mini/miniprogram/game/result/resultSummary.ts)
|
||
- [telemetryRuntime.ts](D:/dev/cmr-mini/miniprogram/game/telemetry/telemetryRuntime.ts)
|
||
- [playerTelemetryProfile.ts](D:/dev/cmr-mini/miniprogram/game/telemetry/playerTelemetryProfile.ts)
|
||
|
||
作用:
|
||
|
||
- 根据运行态定义执行状态流转
|
||
- 响应 GPS、点击、打点、答题、结束等事件
|
||
- 产出 HUD、反馈、结果页等最终体验
|
||
- 明确区分可打目标、引导目标、HUD 目标和展示高亮目标
|
||
|
||
这一层回答的是:
|
||
|
||
- 玩家在游戏中的每一步如何被判定
|
||
- 积分、答题、结束如何结算
|
||
- 页面上显示什么、什么时候显示
|
||
- 活动遥测默认值和玩家身体数据如何合并
|
||
|
||
---
|
||
|
||
## 3. 规则从设计到运行的链路
|
||
|
||
当前实际链路如下:
|
||
|
||
1. 在玩法文档里定义默认规则
|
||
2. 在公共配置文档里定义字段与默认值
|
||
3. 在玩法目录里确定该玩法使用哪些字段
|
||
4. 在 `event/*.json` 中写出样例配置
|
||
5. 由配置解析层读取 JSON 并注入模式默认值
|
||
6. 由默认值与设置层补齐系统默认行为和玩家本地值
|
||
7. 由规则引擎和 `MapEngine` 执行游戏逻辑
|
||
8. 由结果页和 HUD 层展示最终状态
|
||
|
||
其中遥测相关链路补充为:
|
||
|
||
`系统默认值 -> 活动 telemetry 配置 -> 玩家线上身体数据 -> TelemetryRuntime -> HUD 第 2 页`
|
||
|
||
设置相关链路补充为:
|
||
|
||
`系统设置默认值 -> 玩家本地持久化值 -> 当前运行时锁态 -> map.ts / MapEngine`
|
||
|
||
也可以简化成:
|
||
|
||
`规则文档 -> 配置文档 -> 样例 JSON -> 配置解析 -> 规则引擎 -> 运行结果`
|
||
|
||
当前已补一层轻量 smoke tests,用于卡住高风险回归:
|
||
|
||
- 配置继承
|
||
- 起点 / 终点规则
|
||
- 积分赛自由打点
|
||
- 锁态生命周期
|
||
- 超时结束
|
||
|
||
命令:
|
||
|
||
- `npm run test:runtime-smoke`
|
||
|
||
---
|
||
|
||
## 4. 当前目录分工
|
||
|
||
### 4.1 `doc/config`
|
||
|
||
职责:
|
||
|
||
- 公共配置全集
|
||
- 公共字段字典
|
||
- 公共模板
|
||
- 发布和后台管理方案
|
||
|
||
这一层不应该存放某个玩法自己的专属规则文档。
|
||
|
||
### 4.2 `doc/gameplay`
|
||
|
||
职责:
|
||
|
||
- 通用玩法方法论
|
||
- 玩法设计模板
|
||
- 玩法构想和规则架构说明
|
||
|
||
这一层不应该长期存放具体玩法的正式规则文档。
|
||
|
||
### 4.3 `doc/games/<游戏名称>`
|
||
|
||
职责:
|
||
|
||
- 某个具体玩法的完整文档集合
|
||
- 玩法说明
|
||
- 规则说明
|
||
- 最小 / 最大模板
|
||
- 全局配置项子集
|
||
- 游戏配置项子集
|
||
|
||
这一层是具体玩法的唯一正式维护入口。
|
||
|
||
### 4.4 `event/*.json`
|
||
|
||
职责:
|
||
|
||
- 当前可运行样例配置
|
||
- 联调、验证、远端发布的直接输入
|
||
|
||
这一层必须和玩法目录中的文档保持一致。
|
||
|
||
---
|
||
|
||
## 5. 当前已落地的玩法实例
|
||
|
||
### 5.1 顺序打点
|
||
|
||
正式文档入口:
|
||
|
||
- [顺序打点/游戏说明文档](D:/dev/cmr-mini/doc/games/顺序打点/游戏说明文档.md)
|
||
- [顺序打点/规则说明文档](D:/dev/cmr-mini/doc/games/顺序打点/规则说明文档.md)
|
||
- [顺序打点/最小配置模板](D:/dev/cmr-mini/doc/games/顺序打点/最小配置模板.md)
|
||
- [顺序打点/最大配置模板](D:/dev/cmr-mini/doc/games/顺序打点/最大配置模板.md)
|
||
- [顺序打点/全局配置项](D:/dev/cmr-mini/doc/games/顺序打点/全局配置项.md)
|
||
- [顺序打点/游戏配置项](D:/dev/cmr-mini/doc/games/顺序打点/游戏配置项.md)
|
||
- [classic-sequential.json](D:/dev/cmr-mini/event/classic-sequential.json)
|
||
|
||
### 5.2 积分赛
|
||
|
||
正式文档入口:
|
||
|
||
- [积分赛/游戏说明文档](D:/dev/cmr-mini/doc/games/积分赛/游戏说明文档.md)
|
||
- [积分赛/规则说明文档](D:/dev/cmr-mini/doc/games/积分赛/规则说明文档.md)
|
||
- [积分赛/最小配置模板](D:/dev/cmr-mini/doc/games/积分赛/最小配置模板.md)
|
||
- [积分赛/最大配置模板](D:/dev/cmr-mini/doc/games/积分赛/最大配置模板.md)
|
||
- [积分赛/全局配置项](D:/dev/cmr-mini/doc/games/积分赛/全局配置项.md)
|
||
- [积分赛/游戏配置项](D:/dev/cmr-mini/doc/games/积分赛/游戏配置项.md)
|
||
- [score-o.json](D:/dev/cmr-mini/event/score-o.json)
|
||
|
||
---
|
||
|
||
## 6. 文档与代码同步约定
|
||
|
||
后续每次规则变化,建议至少检查 4 层是否同步:
|
||
|
||
1. 公共配置文档是否要补字段或默认值
|
||
2. 对应玩法目录下的规则文档是否要改
|
||
3. 对应 `event/*.json` 样例是否要改
|
||
4. 配置解析和规则引擎是否要改
|
||
|
||
如果只改了其中一层,就容易出现文档、配置、代码不一致。
|
||
|
||
建议统一按下面顺序维护:
|
||
|
||
1. 先改规则文档
|
||
2. 再改配置文档和样例 JSON
|
||
3. 再改解析代码和规则代码
|
||
4. 最后回头核对结果页、HUD 和提示是否与文档一致
|
||
|
||
---
|
||
|
||
## 7. 和后续后台管理的关系
|
||
|
||
当前本地项目里,规则主要由文档和样例 JSON 驱动。
|
||
|
||
后续接后台后,分工仍然建议保持不变:
|
||
|
||
- 玩法文档负责定义规则
|
||
- 公共配置文档负责定义字段
|
||
- 后台负责编辑、版本、校验、装配、发布
|
||
- 客户端继续消费静态 JSON
|
||
|
||
也就是说,后台是管理工具,不是规则源头。
|
||
|
||
---
|
||
|
||
## 8. 一句话总结
|
||
|
||
当前这套实际架构可以概括为:
|
||
|
||
**`doc/config` 管公共规则全集,`doc/games/<游戏名称>` 管玩法规则与配置子集,`event/*.json` 管可运行样例,客户端解析配置后交给规则引擎执行,并由轻量恢复层处理异常退出后的续局。**
|