关于 game-architecture
供 Three.js 或 Phaser 浏览器游戏开发者参考的架构技能,涵盖核心循环规划、事件驱动模块、集中式状态与配置。还提供重启安全实践和发布前验证清单。
主要功能
- 01优先实现核心循环
- 02EventBus 通信模式
- 03集中管理状态与配置
- 04安全重启的生命周期实践
- 05分层系统组织
- 06发布前验证清单
适用场景
- 01规划浏览器游戏架构
- 02通过事件解耦游戏模块
- 03避免重启后残留状态
- 04发布前检查游戏准备情况
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ playableintelligence/ game-creator --skill game-architecture安装后在 Claude Code 中输入/game-architecture确认已加载。
附带文件system-patterns.md
详细介绍
游戏架构模式
用于构建结构良好的浏览器游戏的参考知识。这些模式适用于 Three.js(3D)和 Phaser(2D)游戏。
参考文件
详细参考内容请参阅此目录中的配套文件:
system-patterns.md— 对象池、Delta 时间归一化、资源释放、波次/生成系统、增益/强化道具系统、触觉反馈、资源管理
核心原则
-
优先实现核心循环:在进行任何润色之前,先实现最精简的游戏玩法循环。顺序为:输入 -> 移动 -> 失败条件 -> 计分 -> 重启。只有核心循环正常运行后,才能添加视觉效果、音频或增强反馈。初始范围应尽量精简:1 个场景/关卡、1 种机制、1 个失败条件。
-
事件驱动通信:模块之间绝不通过相互导入进行通信。所有跨模块消息都通过带有预定义事件常量的单例 EventBus 传递。
-
集中管理状态:由单个 GameState 单例保存所有游戏状态。系统直接读取状态,并通过事件修改状态。不要在各个模块中分散存放状态。
-
集中管理配置:每个魔法数字、平衡数值、资源路径、生成点和计时值都放入
Constants.js。游戏逻辑文件中不得包含硬编码数值。 -
编排器模式:由一个
Game.js类初始化所有系统、管理游戏流程(启动 -> 游戏中 -> 死亡/胜利 -> 重启),并运行主循环。系统不得自行初始化。默认不设标题画面——直接启动游戏玩法。仅当用户明确要求时,才添加标题/菜单场景。 -
确保重启安全且结果确定:游戏玩法必须能在完整的重启周期中正常运行。
GameState.reset()会恢复完整的干净初始状态。清理/关闭时移除所有事件监听器。跨重启周期不得残留过期引用、计时器、补间动画或孤立的物理体。连续重启 3 次进行测试——第 3 次运行的行为必须与第 1 次相同。 -
明确划分职责:代码按功能层组织:
core/- 基础层(Game、EventBus、GameState、Constants)systems/- 引擎级系统(输入、物理、音频、粒子)gameplay/- 游戏机制(玩家、敌人、武器、计分)level/- 世界构建(关卡构建、资源加载)ui/- 界面(菜单、HUD、叠加层)
事件系统设计
事件命名约定
按功能领域分组,使用 domain:action 格式:
export const Events = {
// Player
PLAYER_DAMAGED: 'player:damaged',
PLAYER_HEALED: 'player:healed',
PLAYER_DIED: 'player:died',
// Enemy
ENEMY_SPAWNED: 'enemy:spawned',
ENEMY_KILLED: 'enemy:killed',
// Game flow
GAME_STARTED: 'game:started',
GAME_PAUSED: 'game:paused',
GAME_OVER: 'game:over',
// System
ASSETS_LOADED: 'assets:loaded',
LOADING_PROGRESS: 'loading:progress'
};
事件数据契约
始终传递结构化数据对象,不要传递原始值:
// Good
eventBus.emit(Events.PLAYER_DAMAGED, { amount: 10, source: 'enemy', damageType: 'melee' });
// Bad
eventBus.emit(Events.PLAYER_DAMAGED, 10);
状态管理
GameState 结构
将状态划分为清晰的领域:
class GameState {
constructor() {
this.player = { health, maxHealth, speed, inventory, buffs };
this.combat = { killCount, waveNumber, score };
this.game = { started, paused, isPlaying };
}
}
游戏流程
适用于 2D 和 3D 游戏的标准流程:
Boot/Load -> Gameplay <-> Pause Menu (if requested)
-> Game Over -> Gameplay (restart)
默认不设标题画面。 游戏直接启动到游戏玩法。Play.fun 小组件会在游戏顶部的安全区显示分数、排行榜和钱包连接,因此无需在游戏内设置分数 HUD。仅当用户明确要求时,才添加标题/菜单场景。
常见架构陷阱
- 未连接的物理体 — 创建静态物理体(例如地面、墙壁)后,如果没有通过
physics.add.collider()或physics.add.overlap()将其与其他物体连接,就不会对游戏玩法产生任何影响。每个边界或障碍物都需要明确连接到它应当与之交互的实体。创建任何静态物体后,应立即添加碰撞器调用。 - 交互元素被重叠的显示对象挡住 — 构建 UI(按钮、菜单)时,场景列表中最上层的显示对象会接收指针事件。切勿将交互元素藏在装饰层后面。可以让视觉元素本身支持交互,或者确保命中区域上方没有渲染任何内容。
- 先打磨,后做玩法 — 在核心循环正常运作之前添加粒子效果、屏幕抖动和转场,是常见的时间陷阱。先让输入 -> 操作 -> 失败条件 -> 计分 -> 重新开始正常运作。其他一切都属于润色。
- 重新开始时未清理 — 忘记移除事件监听器、销毁计时器以及在
shutdown()中释放资源,会导致重新开始后出现异常行为、事件重复触发和内存泄漏。
发布前验证清单
在认定游戏已完成之前,请确认所有项目均已通过验证:
- 核心循环 — 玩家可以开始游戏、进行游戏、输赢,并查看结果
- 重新开始 — 连续运行 3 次,行为一致且无异常
- 移动设备输入 — 触摸/轻触/滑动/陀螺仪均可正常工作;点击目标最小尺寸为 44px
- 桌面设备输入 — 键盘和鼠标均可正常工作
- 响应式布局 — 窗口大小改变时,画布能正确调整尺寸
- 常量 — 游戏逻辑中没有硬编码的魔法数字
- EventBus — 模块间通信没有直接跨模块导入
- 清理 — 关闭时移除所有监听器,并释放资源
- 静音切换 — 请参阅
mute-button规则 - 基于 delta 的移动 — 所有移动都使用 delta 时间,而非帧数
- 构建 —
npm run build成功,且没有错误 - 无错误 — 运行时没有未捕获的异常或控制台错误