关于 phaser-playtest
phaser-playtest 是用于 Phaser 4 游戏运行时验证的技能。基于 Playwright 的测试框架检查浏览器加载、场景、渲染、资源、帧率和错误,并支持脚本化场景进行回归测试。
主要功能
- 01无头 Chromium 运行检查
- 02场景、画布与资源验证
- 03帧率采样与错误检测
- 04脚本化输入和状态断言
- 05开发与构建测试模式
- 06JSON 报告与截图
适用场景
- 01验证超出 TypeScript 检查范围的游戏改动
- 02测试游戏验收标准
- 03复现脚本化游戏过程
- 04在 CI 中运行游戏检查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yakoub-ai/ phaser4-gamedev --skill phaser-playtest安装后在 Claude Code 中输入/phaser-playtest确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
examples/scenario.example.mjsreferences/instrumenting-games.mdplaytest-harness.mdscripts/playtest.mjs详细介绍
Phaser 4 测试游玩(运行时验证)
npx tsc --noEmit 可以证明代码能够编译,但无法说明游戏是否能够运行。以下每种故障都能通过类型检查,却仍会导致发布的游戏出问题:
| 故障 | 玩家看到的情况 | TypeScript 的提示 |
|---|---|---|
| 资源路径拼写错误 | 精灵不可见 | 无——它只是一个字符串 |
场景未添加到 scene: [] | 黑屏 | 无 |
create() 在执行第一行后抛出异常 | 场景只构建了一半 | 无 |
| 深度/透明度/摄像机滚动设置错误 | 画布空白 | 无 |
| 未添加物理体 | 玩家穿过地板 | 无 |
| 发射器未限制发射数量 | 12 fps | 无 |
运行时验证不是可选项。 任何涉及场景生命周期、资源加载、物理或渲染的更改完成后,都应运行测试框架,然后再告诉用户一切正常。
运行测试
node "${CLAUDE_PLUGIN_ROOT}/skills/phaser-playtest/scripts/playtest.mjs" --project .
测试框架会自行启动开发服务器、驱动无头 Chromium,然后关闭服务器。无需配置,也无需测试文件。
项目中需要安装 Playwright(只需安装一次):
npm install -D playwright && npx playwright install chromium
检查内容
- 页面加载 — 文档的 HTTP 状态
- 创建画布 — 是否存在尺寸有效的
<canvas>(失败 ⇒ Phaser 未启动) - 可访问 Phaser 实例 — 在
window上查找Phaser.Game - 游戏已启动 —
isBooted === true - 活动场景 — 正在运行的场景,以及每个场景包含的显示对象数量
- 场景渲染内容 — 场景的显示列表为空时发出警告
- 帧率 — 根据实际帧采样计算中位数和第 5 百分位 FPS
- 画布渲染内容 — 像素分析;可捕获黑屏问题
- 没有未捕获的异常 — 显示带堆栈的
pageerror - 没有控制台错误
- 所有资源均已加载 — 包括被开发服务器伪装成
200 text/html的文件
退出代码 0 = 通过,1 = 检查失败,2 = 测试框架错误。会写入
.playtest/report.json 和 PNG 截图。
选项
| 标志 | 用途 |
|---|---|
--project DIR | 项目根目录(默认:cwd) |
--url URL | 测试已运行的服务器,而非启动新服务器 |
--mode dev|build | build 会运行 npm run build + preview,可捕获基础路径和打包错误 |
--scenario FILE | 驱动脚本化游戏流程(见下文) |
--device iphone|android | 移动设备视口、DPR、触控和 UA |
--settle MS | 探测前的等待时间(默认 3000;预加载较慢时可调高) |
--fail-on-warn | 将控制台警告视为失败(CI) |
--json | 仅输出 JSON,用于解析结果 |
--headed | 显示浏览器 |
让游戏可测试(一行代码)
深度检查需要游戏实例。打包后的游戏会将它保存在模块作用域中,因此仅在开发构建中将其实例公开:
const game = new Phaser.Game(config);
if (import.meta.env.DEV) (window as any).__PHASER_GAME__ = game;
export default game;
没有这行代码,测试框架仍会捕获黑屏、异常和 404,但会跳过场景、FPS 和状态断言,并明确提示这一点。添加此行不会影响生产环境。有关确定性测试钩子(随机数生成器设定种子、时间控制、状态注入),请参阅 references/instrumenting-games.md。
场景脚本
场景脚本会驱动输入,并对实时游戏状态进行断言。在每个 expression 中,game 都绑定到正在运行的实例。
// playtest/combat.mjs
export default [
{ name: 'reaches gameplay', action: 'expect',
expect: { expression: `game.scene.isActive('GameScene')`, equals: true } },
{ name: 'walk right', action: 'key', key: 'ArrowRight', duration: 600 },
{ name: 'player advanced', action: 'expect',
expect: { expression: `game.scene.getScene('GameScene').player.x > 400`, equals: true } },
{ name: 'attack lands', action: 'press', key: 'Space',
expect: { expression: `game.registry.get('enemyHp')`, atMost: 90 } },
{ name: 'after-combat', action: 'screenshot' },
{ name: 'holds frame rate', action: 'expect',
expect: { expression: `game.loop.actualFps`, atLeast: 55 } },
];
操作:wait(ms)、key(key、duration)、press(key)、click(画布相对坐标 x、y)、screenshot(name)、expect。
断言:equals(深度比较)、atLeast、atMost,或用于检查真值的裸 expression。
完整参考:references/playtest-harness.md。
示例:examples/scenario.example.mjs。
将计划转化为测试
/phaser-gdd 或 phaser-architect Agent 给出的验收标准可直接转化为场景步骤。应在功能规格确定时编写场景,而不是等功能出问题后再写:
| 验收标准 | 场景断言 |
|---|---|
| “玩家能跳起 3 格高” | game.scene.getScene('GameScene').player.y,atMost: spawnY - 96 |
| “敌人受到 3 次攻击后死亡” | 按攻击键 ×3,然后检查 enemy.active,equals: false |
| “分数在不同场景间保留” | 启动 GameOver,然后检查 game.registry.get('score'),atLeast: 10 |
| “有 50 个敌人时仍以 60fps 运行” | 通过 eval 生成敌人,然后检查 game.loop.actualFps,atLeast: 55 |
读取失败信息
| 测试框架输出 | 首先检查的根本原因 |
|---|---|
canvas created 失败 | 场景在 constructor/init 中抛出异常,或打包文件返回 500。查看控制台错误。 |
active scenes: no scene is running | 场景未添加到 scene: [],或 create() 在完成前抛出异常 |
canvas renders content 画布为空,但场景处于活动状态 | 对象不在摄像机视野内、alpha: 0、深度不正确,或摄像机未跟随对象 |
scenes render content 提示内容为空 | create() 提前返回了——通常是 try 吞掉了异常 |
all assets load 因 text/html 失败 | 路径拼写错误,或资源位于 src/ 而非 public/ |
frame rate 过低 | 粒子数量未限制、未使用对象池,或每帧都在分配对象。使用 /phaser-analyze。 |
Phaser game instance found 发出警告 | 添加上方的 __PHASER_GAME__ 行 |
CI
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx tsc --noEmit
- run: node scripts/playtest.mjs --project . --mode build --fail-on-warn
将 playtest.mjs 复制到项目自己的 scripts/ 中,这样 CI 就不必依赖已安装的插件。
规范
- 在报告功能已完成之前运行测试框架,而不是等用户报告 Bug 后再运行。
tsc通过但 playtest 失败,意味着工作尚未完成。- 失败时,先阅读
.playtest/report.json和截图,再修改代码。此处同样应先调查,再行动,就像使用phaser-debugger一样。 - 在
playtest/下为每个主要功能保留一个场景;它们是回归测试。
如果问题是由玩家报告的
如果你来到这里是因为有人报告 Bug,而不是因为你刚改了代码,请使用 skills/phaser-feedback/,不要马上编写场景。它会指导你先对报告进行分类(“太难了”并不算缺陷,也没有可复现步骤),并根据问题描述选择合适的构造——“有时会发生”用 --repeat,“卡住”用 sample,“耗时太长”用 waitFor,“运行一段时间后变慢”用 --heap。