mcpField
G
game-architecture

game-architecture

github.com/playableintelligence开发3501.2k 次安装22 周前更新
代码仓库

关于 game-architecture

供 Three.js 或 Phaser 浏览器游戏开发者参考的架构技能,涵盖核心循环规划、事件驱动模块、集中式状态与配置。还提供重启安全实践和发布前验证清单。

主要功能

  1. 01优先实现核心循环
  2. 02EventBus 通信模式
  3. 03集中管理状态与配置
  4. 04安全重启的生命周期实践
  5. 05分层系统组织
  6. 06发布前验证清单

适用场景

  1. 01规划浏览器游戏架构
  2. 02通过事件解耦游戏模块
  3. 03避免重启后残留状态
  4. 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 种机制、1 个失败条件。

  2. 事件驱动通信:模块之间绝不通过相互导入进行通信。所有跨模块消息都通过带有预定义事件常量的单例 EventBus 传递。

  3. 集中管理状态:由单个 GameState 单例保存所有游戏状态。系统直接读取状态,并通过事件修改状态。不要在各个模块中分散存放状态。

  4. 集中管理配置:每个魔法数字、平衡数值、资源路径、生成点和计时值都放入 Constants.js。游戏逻辑文件中不得包含硬编码数值。

  5. 编排器模式:由一个 Game.js 类初始化所有系统、管理游戏流程(启动 -> 游戏中 -> 死亡/胜利 -> 重启),并运行主循环。系统不得自行初始化。默认不设标题画面——直接启动游戏玩法。仅当用户明确要求时,才添加标题/菜单场景。

  6. 确保重启安全且结果确定:游戏玩法必须能在完整的重启周期中正常运行。GameState.reset() 会恢复完整的干净初始状态。清理/关闭时移除所有事件监听器。跨重启周期不得残留过期引用、计时器、补间动画或孤立的物理体。连续重启 3 次进行测试——第 3 次运行的行为必须与第 1 次相同。

  7. 明确划分职责:代码按功能层组织:

    • 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 成功,且没有错误
  • 无错误 — 运行时没有未捕获的异常或控制台错误

评论

支持 Markdown