关于 phaser-migrate
这是一个帮助 Phaser 3 项目迁移到 Phaser 4 的开发技能,也涵盖 Phaser 4 小版本升级及编译通过后仍可能出现的运行时问题。它提供破坏性变更说明、替换建议和迁移检查步骤,适合维护 Phaser 游戏的开发者。
主要功能
- 01梳理 Phaser 3 到 4 的变更
- 02提供 API 替换映射与修复示例
- 03涵盖 Phaser 4 小版本升级
- 04说明编译通过后的运行时问题
- 05提供迁移检查与验证步骤
适用场景
- 01排查 Phaser 3 项目的升级改动
- 02处理 Phaser 4 小版本间迁移
- 03定位类型检查通过但游戏异常的问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yakoub-ai/ phaser4-gamedev --skill phaser-migrate安装后在 Claude Code 中输入/phaser-migrate确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/runtime-gotchas.mdv3-to-v4-changes.mdv4-release-notes.md详细介绍
Phaser 3 → Phaser 4 迁移
从 Phaser 3 迁移到 Phaser 4 通常很简单。核心公共 API 得以保留。本指南涵盖所有破坏性变更及其修复方法,还涵盖 Phaser 4 各小版本之间的迁移(4.0 → 4.1 → 4.2),以及那些虽能顺利编译、却仍会让你感到意外的运行时行为。
步骤 1 — 更新软件包
npm uninstall phaser
npm install phaser
验证已安装的版本:
node -e "const p = require('phaser'); console.log(p.VERSION)"
应显示 4.2.1(或更高的 RC 版本)。
步骤 2 — 检查破坏性变更
运行以下 grep 搜索,在 src/ 目录中查找所有问题:
# 1. Point → Vector2
grep -rn "Geom\.Point\|new Phaser\.Geom\.Point\|Geom\.Point\." src/
# 2. Math.PI2 → Math.TAU
grep -rn "Math\.PI2\b" src/
# 3. Phaser.Structs
grep -rn "Phaser\.Structs\." src/
# 4. DynamicTexture / RenderTexture (check for missing .render())
grep -rn "DynamicTexture\|RenderTexture\|addDynamicTexture\|addRenderTexture" src/
# 5. Removed plugins
grep -rn "Camera3D\|Layer3D\|FacebookInstant\|SpinePlugin\|SpineFile" src/
# 6. TileSprite crop (setCrop on TileSprite — no longer supported)
grep -rn "tileSprite.*setCrop\|setCrop.*tileSprite" src/
# 7. Create.GenerateTexture (removed)
grep -rn "Create\.GenerateTexture\|Phaser\.Create\." src/
# 8. Spine (use official Esoteric plugin instead)
grep -rn "spine\|Spine" src/ -i
# 9. phaser-ie9 entry point
grep -rn "phaser-ie9" .
# 10. WebGL geometry masks (stencil-based masks changed in Phaser 4 — use scissor/viewport instead)
grep -rn "createGeometryMask\|createBitmapMask\|BitmapMask\|setMask\b\|clearMask\|setScissor" src/
步骤 3 — 应用修复
修复 1:Geom.Point → Vector2
Phaser.Geom.Point 已完全移除。请改用 Phaser.Math.Vector2。
// BEFORE (Phaser 3)
const point = new Phaser.Geom.Point(x, y);
point.x = 100;
const distance = Phaser.Geom.Point.GetMagnitude(point);
const clone = Phaser.Geom.Point.Clone(point);
Phaser.Geom.Point.SetMagnitude(point, 50);
// AFTER (Phaser 4)
const point = new Phaser.Math.Vector2(x, y);
point.x = 100;
const distance = point.length();
const clone = point.clone();
point.setLength(50);
Point → Vector2 方法完整映射:
| Phaser 3(静态) | Phaser 4(实例) |
|---|---|
Point.GetMagnitude(pt) | pt.length() |
Point.Clone(pt) | pt.clone() |
Point.SetMagnitude(pt, n) | pt.setLength(n) |
Point.Ceil(pt) | pt.ceil() |
Point.Floor(pt) | pt.floor() |
Point.Invert(pt) | pt.invert() |
Point.Negative(pt) | pt.negate() |
Point.Project(pt, target, out) | pt.project(target) |
Point.GetCentroid(points) | Phaser.Math.GetCentroid(points) |
Point.GetRectangleFromPoints(pts) | Phaser.Math.GetVec2Bounds(pts) |
所有 Geometry 类(Circle、Ellipse、Line、Rectangle、Triangle、Polygon)现在都会在返回点相关结果时使用 Vector2,而不是 Point。
修复 2:Math.PI2 → Math.TAU
// BEFORE (Phaser 3) — NOTE: Math.PI2 was INCORRECTLY π in v3
const fullRotation = Math.PI2; // was wrong!
// AFTER (Phaser 4)
const fullRotation = Math.TAU; // Correct π×2
const halfRotation = Math.PI_OVER_2; // π/2 (new constant)
修复 3:Phaser.Structs → 原生 JS
// BEFORE (Phaser 3)
const myMap = new Phaser.Structs.Map([]);
myMap.set('key', value);
myMap.get('key');
myMap.delete('key');
myMap.getArray();
const mySet = new Phaser.Structs.Set();
mySet.set(value);
mySet.delete(value);
mySet.contains(value);
// AFTER (Phaser 4)
const myMap = new Map<string, any>();
myMap.set('key', value);
myMap.get('key');
myMap.delete('key');
[...myMap.values()];
const mySet = new Set<any>();
mySet.add(value);
mySet.delete(value);
mySet.has(value);
修复 4:DynamicTexture / RenderTexture — 添加 render()
// BEFORE (Phaser 3) — drawing happened immediately
const dynTex = this.textures.addDynamicTexture('key', 200, 200);
dynTex.draw('sprite', 0, 0);
// visible immediately
// AFTER (Phaser 4) — must call render() to commit drawing
const dynTex = this.textures.addDynamicTexture('key', 200, 200);
dynTex.draw('sprite', 0, 0);
dynTex.render(); // ← REQUIRED in v4
修复 5:已移除的插件
Camera3D — 没有替代方案。Phaser 4 仅支持 2D。如果需要 3D,请将 Three.js 与 Phaser 搭配使用。
Layer3D — 没有替代方案。它随 Camera3D 一并移除。
Facebook Instant Games — 已移除。Facebook 不再支持此平台。
Spine 插件(官方 v3/v4 Spine 支持)— 请改用官方的 Esoteric Software Phaser 插件。Phaser 内置的 Spine 插件已不再维护。
修复 6:TileSprite 裁剪
Phaser 4 中的 TileSprite 不再支持纹理裁剪。
// BEFORE (Phaser 3)
const ts = this.add.tileSprite(x, y, w, h, 'texture');
ts.setCrop(0, 0, 100, 100); // no longer works in v4
// AFTER (Phaser 4) — use RenderTexture instead if cropping is needed
const rt = this.add.renderTexture(x, y, 100, 100);
rt.draw('texture', 0, 0);
rt.render();
修复 7:Create.GenerateTexture 已移除
Phaser.Create.GenerateTexture 和所有 Create Palettes 均已移除。
// BEFORE (Phaser 3)
const texture = Phaser.Create.GenerateTexture({ data: palettes, pixelWidth: 2 });
// AFTER (Phaser 4) — use a pre-made image asset, or draw with Graphics
const gfx = this.add.graphics();
gfx.fillStyle(0xff0000);
gfx.fillRect(0, 0, 16, 16);
gfx.generateTexture('red-square', 16, 16);
gfx.destroy();
修复 8:已移除 IE9 入口点
// BEFORE — some projects imported the IE9-compatible build
import Phaser from 'phaser/src/phaser-ie9.js';
// AFTER — just use the standard import
import Phaser from 'phaser';
修复 9:Masks → Camera 视口或 Mask Filter
Phaser 4 移除了 v3 的遮罩类。BitmapMask 已彻底移除,Game Objects 上也不再存在
createGeometryMask() 或 createBitmapMask()。GeometryMask
作为类得以保留,但只有(已弃用的)Canvas 渲染器会使用它——在 Beam 下它不起作用。
// BEFORE (Phaser 3) — geometry mask via stencil buffer
const shape = this.add.graphics().fillRect(x, y, w, h);
const mask = shape.createGeometryMask(); // removed in v4
targetSprite.setMask(mask);
// AFTER (Phaser 4), rectangular clip — give the content its own camera:
const clipCam = this.cameras.add(x, y, w, h);
clipCam.ignore(this.children.list.filter(c => c !== targetSprite));
this.cameras.main.ignore(targetSprite);
// AFTER (Phaser 4), arbitrary shape — the Mask filter:
targetSprite.enableFilters(); // filters is null until you call this
targetSprite.filters!.internal.addMask(shape); // texture key or GameObject
targetSprite.filters!.internal.addMask(shape, true); // inverted
Phaser 4 中没有 camera.setScissor() ——
Phaser.Cameras.Scene2D.Camera 上不存在此方法。请使用 setViewport()。
Phaser.Actions.AddMaskShape() 是一种便捷方法,可通过一次调用创建 Shape 并将其设置为
遮罩——它是 v3 Circle FX 的替代方案。
步骤 4 — 更新 TypeScript 配置
如果使用 TypeScript,请确保 tsconfig.json 符合 v4 的要求:
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src"]
}
Phaser 4 通过自身 package.json 中的 exports 映射发布类型,因此现代解析器可以通过普通的
import Phaser from 'phaser'; 自动找到类型,无需额外配置。
如果你的 v3
tsconfig中有typeRoots: ["./node_modules/phaser/types"]和types: ["Phaser"],请将其删除。 这两个配置用于 Phaser 4 时会导致TS2688: Cannot find type definition file for 'Phaser'错误——v4 只提供一个types/phaser.d.ts文件,它不是有效的类型根目录软件包。
步骤 5 — 验证并测试
# Type check — must pass with 0 errors
npx tsc --noEmit
# Start dev server and check browser console
npm run dev
在浏览器中检查:
- 启动时没有控制台错误
- 所有场景均可正常加载
- 物理效果与 v3 相同
- 动画播放正常
快速迁移检查清单
- 运行
npm install phaser - 移除
tsconfig.json中 v3 时代的typeRoots和types: ["Phaser"];将moduleResolution设为bundler/node16 - 将所有
Phaser.Geom.Point替换为Phaser.Math.Vector2 - 将所有
Math.PI2替换为Math.TAU - 将所有
Phaser.Structs.Map/Set替换为原生Map/Set - 所有
DynamicTexture/RenderTexture在绘制后都调用render() - 删除已移除插件的引用(Camera3D、Layer3D、Facebook、旧版 Spine)
- 替换或移除
TileSprite.setCrop()调用 - 将
Phaser.Create.GenerateTexture替换为 Graphics/纹理 - 将
phaser-ie9导入替换为phaser - 将 WebGL 遮罩(
createGeometryMask/createBitmapMask/BitmapMask)替换为摄像机视口或filters.internal.addMask();不要调用camera.setScissor() -
npx tsc --noEmit通过 -
node skills/phaser-playtest/scripts/playtest.mjs --project .通过——tsc显示绿色并不能说明迁移后的游戏能够正常渲染
其他资源
参考文件
references/v3-to-v4-changes.md— Phaser v3→v4 所有破坏性更改的完整变更日志,包括渲染器内部机制、已弃用的 API 和行为差异references/runtime-gotchas.md— 能顺利编译却仍会让你遇到意外的行为:遮罩、动画状态切换、摄像机跟随、瓦片地图碰撞、onFloor()时机、跨场景连接、缩放管理器。当编译器没有报错但游戏无法正常运行时,请阅读此文。references/v4-release-notes.md— 4.0.0、4.1.0、4.2.0 和 4.2.1 中发布的内容,以及在这些版本之间升级时需要做的更改。升级 Phaser 4 的补丁版本时请阅读,或用于确认你正在追查的错误是否已在上游修复。