Phaser 3.70 “Yotsuba“ 更新解读:Round Pixels、Nine Slice、Arcade 碰撞分类与 FX 优化实战指南

发布时间:2026/9/19 8:37:45
Phaser 3.70 “Yotsuba“ 更新解读:Round Pixels、Nine Slice、Arcade 碰撞分类与 FX 优化实战指南 Phaser 3.70 Yotsuba 更新解读Round Pixels、Nine Slice、Arcade 碰撞分类与 FX 优化实战指南【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser版本说明本文以 CHANGELOG-v3.70.mdPhaser 3.70.0 Yotsuba2023 年 11 月 10 日发布为核心结合当前仓库Phaser 4.2.1源码验证其中的关键 API 实现。文中标记为v3.70 新增的能力多数在当前仓库中依然存在可放心作为开发参考个别默认值在后续版本中有所调整文章会明确标注。导读Phaser 3.70 是 3.x 时代一次以渲染精度、工作流效率与物理精度为核心的更新它把像素取整Round Pixels从 CPU 迁移到 GPU 并默认开启让像素级游戏和相机滚动更平滑它支持 Texture Packer v7.1 导出的 scale9 数据让 Nine Slice 精灵无需手写边框即可创建它为 Arcade Physics 引入了碰撞分类Collision Categories与直接控制Direct Control机制让物理层拥有更细粒度的碰撞控制同时还为 FX 系统增加了运行时开关与大量内存/性能修复。读完本文你将掌握 3.70 各项新特性的配置方法、源码级原理与实战用法。一、Round Pixels像素取整从 CPU 迁移到 GPU1.1 为什么需要 Round Pixels在 WebGL 渲染中游戏对象常被放置在非整数坐标上例如相机滚动产生的小数位移。此时纹理采样会落在像素边界之间导致相邻像素被混合采样画面出现亚像素模糊sub-pixelation。v3.70 之前Phaser 在 CPU 端对每个 sprite 的位置、origin、缩放做取整计算v3.70 起这一系列运算被整体搬进了顶点着色器vertex shader。1.2 核心变化一览v3.70 更新日志明确列出了本次重构的关键点Game Config 的roundPixels默认值改为true所有游戏对象默认按整数像素位置渲染避免非整数偏移带来的亚像素问题尤其在高缩放比的相机滚动场景下更平滑。核心顶点着色器Multi、Single、Mobile新增uRoundPixelsuniform由对应 pipeline 统一设置取整计算全部在 GPU 完成可为高强度游戏省下大量 CPU 数学运算。CanvasRenderer.batchSprite同步适配Canvas 渲染器现在也会读取 Camera 的roundPixels属性并应用到drawImage调用上两个渲染器行为一致。Camera.preRender不再对 origin、follow 坐标和 scrollX/Y 取整仅对 World view 取整。MultiPipeline.batchSprite不再自行取整Single、Mobile Pipeline 复用该方法quad 顶点数据直接交给 shader 处理。TransformMatrix.setQuad移除匿名函数以提升性能且其roundPixels参数改为可选、默认false。1.3 配置方式与像素艺术的边界const config { type: Phaser.AUTO, roundPixels: true, // v3.70 起默认为 true此处显式声明更清晰 // ... 其他配置 };特别注意v3.70 中只有roundPixels默认被打开pixelArt依旧默认false。如果你在做像素风游戏仍需显式开启pixelArt: true, // 会自动把 antialias/antialiasGL 置 false并把 roundPixels 置 true1.4 源码验证与版本演进提示在 Config.js 中可以看到roundPixels与pixelArt的联动逻辑依然保留pixelArt开启时强制roundPixels true。同时需注意版本差异当前仓库v4.2.1中roundPixels的默认值已恢复为false见 Config.js。也就是说3.70 曾将其默认开启但后续版本又调回关闭。因此在新版本项目中若需要像素级精确渲染建议显式配置roundPixels: true不要依赖默认值。从源码结构可以推断GPU 取整的核心机制uRoundPixelsuniform shader 内取整在设计上独立于默认值开关因此无论默认值如何只要显式开启该路径都会生效。二、Texture Packer Nine SliceAtlas 直接驱动九宫格精灵2.1 背景什么是 scale9 数据Texture Packer v7.1.0 及更高版本导出 Phaser 3 Atlas JSON 时可以对精灵开启 scale9 复选框并拖拽参考线。导出后的 JSON 会包含新的scale9对象Phaser 解析 Atlas 后即可直接据此创建 Nine Slice 游戏对象无需在代码中手动指定边框尺寸。2.2 新 API 与行为变化NineSlice 可不传宽高创建省略 width/height 时自动使用纹理帧frame的尺寸。自动读取 Frame 的 scale9 数据创建 NineSlice 时若关联 Frame 带有 scale9 数据会自动填充所有 border 值。NineSlice.setSlices新增可选参数skipScale9即使 Frame 带 scale9 数据也可强制使用手动指定的边框值。Frame.setScale9(x, y, width, height)新方法为给定 Frame 设置 scale9 数据Texture Packer 解析器内部调用也可直接手动调用。Frame.scale9只读 booleanFrame 是否带有 scale9 数据。Frame.is3Slice只读 booleanFrame 的 scale9 数据是 3-slice 还是 9-slice。JSONHash与JSONArray解析器都会检测 JSON 中的scale9数据并通过Frame.setScale9写入。2.3 源码验证在 Frame.js 中setScale9的实现同时计算了 3-slice 判定setScale9: function (x, y, width, height) { var data this.data; data.scale9 true; data.is3Slice (y 0 height this.height); data.scale9Borders.x x; data.scale9Borders.y y; data.scale9Borders.w width; data.scale9Borders.h height; return this; }可以看到is3Slice的判定逻辑当中心矩形的 y 为 0 且高度等于整个帧高度时说明只按水平方向三等分即为 3-slice。scale9、is3Slice两个只读属性也在 Frame.js 中实现为基于内部data的 getter。在 NineSlice.js 中setSlices的实现印证了skipScale9的优先级逻辑当skipScale9为 false 且frame.scale9为 true 时会优先使用 Frame 上的 scale9 边框数据。这也解释了为何 Texture Packer 导出的数据能开箱即用。2.4 实战示例// 1) 使用 Texture Packer 导出的 AtlasJSONArray 格式内含 scale9 数据 this.load.atlas(ui, assets/ui.png, assets/ui.json); // 2) 直接创建 NineSlice无需指定边框宽高省略时使用帧尺寸 const panel this.add.nineslice(400, 300, ui, panel); // 3) 指定尺寸边框自动来自 scale9 数据 const stretched this.add.nineslice(400, 300, ui, panel, 600, 400); // 4) 若想覆盖 Atlas 中的边框使用 skipScale9 参数 stretched.setSlices(600, 400, 20, 20, 20, 20, true); // 5) 手动为任意 Frame 设置 scale9 数据 const frame this.textures.getFrame(ui, panel); frame.setScale9(30, 0, 100, 64); // 也可手动构造 3-slice 数据三、Arcade Physics碰撞分类、直接控制与滑动因子3.1 碰撞分类Collision Categories细粒度碰撞过滤v3.70 为 Arcade Physics 引入了 32 个可用的碰撞分类默认行为不变所有 body 相互碰撞但你现在可以对碰撞关系做顶层过滤——这是最大的性能红利一个 Sprite 若被设置为不与某个 Physics Group 碰撞则完全跳过对该 Group 每个子对象的检查省下大量逐对检测时间。新增 API 一览API作用World.nextCategory()创建一个新碰撞分类并返回每个世界最多 32 个Body.collisionCategory/Body.collisionMask两个新属性本体的分类、可碰撞的分类列表Body.setCollisionCategory(category)设置本体分类Body.setCollidesWith(mask)设置本体会与哪些分类碰撞Body.resetCollision()将分类与掩码重置为默认与所有碰撞注意setCollisionCategory、setCollidesWith、resetCollision不仅存在于 Body还直接暴露在Arcade Sprites、Images、Tilemap Layers、Groups 和 Static Groups上因此可以像sprite.setCollidesWith(...)这样直接调用。这些分类会被collide、overlap方法以及Collider对象自动使用。由于过滤发生在顶层你往往可以显著减少 Collider 的数量也无需在碰撞回调里手工过滤配对。源码佐证在 World.js 与 World.js 中可以看到碰撞检测的位掩码判断(body1.collisionMask body2.collisionCategory) 0 || (body2.collisionMask body1.collisionCategory) 0即只要有一方的 mask 不包含另一方的 category就直接跳过碰撞/重叠检测——这正是顶层过滤的底层实现。3.2 直接控制Direct Control用位置驱动物理体Body.setDirectControl(value)切换directControl布尔属性默认false。开启后Body 会根据相对上一帧的位置变化来推算速度。这意味着你可以直接改 body 的 x/y或用 Tween、Path、跟随 Pointer移动它而不必操作 velocity/acceleration由于速度是根据位移推算出来的碰撞解析依旧生效碰撞时仍会按常规把速度传递给被撞物体。典型场景用 Tween 移动一个物体并希望它推动其他物理体。3.3 滑动因子Slide Factor控制被推后的速度保留Body.slideFactor是一个 Vector2控制 Body 被其他 Body 推动后保留多少速度默认值为(1, 1)保留全部设为(0, 0)则完全不保留即能被推动但自身不获得速度。// 被推后完全不保留速度如冰块、被推动的静态感物体 body.setSlideFactor(0, 0); // 保留一半水平速度、完全保留垂直速度 body.setSlideFactor(0.5, 1);源码验证在 Body.js 中slideFactor默认初始化为new Vector2(1, 1)setSlideFactor方法见 Body.js碰撞后的速度应用见 Body.js 与 Body.js即this.velocity.x vx * this.slideFactor.x的形式。directControl的默认false与setDirectControl方法同样存在于 Body.js 与 Body.js。3.4 综合实战示例const categoryPlayer this.physics.world.nextCategory(); const categoryEnemy this.physics.world.nextCategory(); // 玩家只与敌人碰撞不与地形组碰撞 playerBody.setCollisionCategory(categoryPlayer); playerBody.setCollidesWith(categoryEnemy); // 敌人组与玩家碰撞 enemyGroup.setCollisionCategory(categoryEnemy); enemyGroup.setCollidesWith(categoryPlayer); // 一个被 Tween 推动的推板用直接控制 零滑动因子 pusherBody.setDirectControl(true); pusherBody.setSlideFactor(0, 0); this.tweens.add({ targets: pusher, x: 800, duration: 2000 });四、FX 系统更新与修复4.1 新增 FX 全局开关v3.70 在 Game Config 中新增两个布尔属性用于控制内置 FX 是否启用。这是单一开关single-set flags游戏启动后不可再切换。若不需要 FX关闭它们可以节省纹理内存、减少 shader 编译从而加快启动时间const config { type: Phaser.AUTO, disablePreFX: true, // 禁用所有 Game Object 的 Pre FX 创建与使用 disablePostFX: true, // 禁用所有 Game Object 的 Post FX 创建与使用 };配套的底层变化包括PipelineManager延迟创建 FX Pipeline改在boot方法中依据这两个配置值决定是否创建。PipelineManager.renderTargets数组不再预填充禁用 Pre FX 时省下纹理内存。PostFXPipeline.bootFX原boot重命名不再于构造函数中调用而是在 FX 被 Pipeline Manager 激活时才调用把 Render Target 与 shader 等资源的创建延迟到 FX 实际使用的那一刻进一步节省内存。4.2 关键 Bug 修复Circle FX 新增backgroundAlpha属性可设置 Circle FX 背景色的 alpha感谢 rexrainbow。PostFXPipeline 的 RenderTarget 自动 resize所有 RenderTarget 现默认autoResize: true修复了游戏尺寸变化时渲染目标与画布失步的问题Issue #6503。Blur FX 质量参数修复此前FX.Blur的quality参数未写入属性、BlurFXPipeline也未绑定对应 shader导致始终使用低质量 Blur同时FXBlurLow片元着色器补上了offsetuniform消除了 45 度方向的模糊伪影。Tilemap 层 PostFX 绘制调用量骤减此前给 Tilemap Layer 加 PostFX 会对层内每个 tile各应用一次修复后每层只应用一次。更新日志给出的实测简单地图的 draw calls 从12,000 降到 52且 FX 开销不再随 tile 数量增长。注意这是 3.70 版本记录的修复数据供理解优化幅度参考。五、其他新增特性与实用 API5.1 文本Text增强Text.setRTL()新方法将文本设为从右到左渲染感谢 rexrainbow。Text.setLetterSpacing()与Text.letterSpacing新方法/属性设置字符间距正负均可负值让字符更近。性能警告启用后 Phaser 会逐字符渲染该文本对象而不是一次 draw 整个字符串长文本或大量文本时开销极高大段精细间距文本建议改用位图字体bitmap font。text.setLetterSpacing(2); // 字距 2 text.setRTL(); // 从右到左渲染5.2 动画与粒子randomFrame新布尔属性可配置在 Animation Config 与 Play Animation Config 中默认false。开启后动画开始播放时会随机挑选一帧让同一时间创建的一组精灵使用同一动画呈现更多样化。对应新增Animation.randomFrame与AnimationState.randomFrame属性。粒子发射器动画配置升级ParticleEmitter配置对象的anims属性现在支持完整的Phaser.Types.Animations.PlayAnimationConfig可控制随机起始帧、repeat delays、yoyo 等Issue #6478。ParticleEmitter.clearDeathZones()/clearEmitZones()新方法清空此前创建的死亡区域/发射区域。ParticleEmitter.addDeathZone改为返回数组返回创建的 Death Zone 实例数组与addEmitZone行为一致。5.3 瓦片地图TilemapTilemapLayer.setTintFill()新方法对区域内瓦片应用填充式fill-based着色区别于setTint的叠加式additive-based。Tile.tintFill新布尔属性控制瓦片着色是叠加式还是填充式供TilemapLayerWebGLRenderer使用。Tilemaps.ObjectLayer.id/Tilemaps.LayerData.id新属性返回 Tiled 中指定的层 ID若地图未指定或层名不唯一时返回 0便于在层名不唯一时按 ID 定位层。5.4 时间轴Timeline条件事件创建TimelineEvent时可设置新的可选回调if该回调在事件开始时被调用返回true才继续处理事件启动 tween、播放声音等否则跳过该事件——由此可在 Timeline 内构建条件事件。timeline.add({ tween: { targets: sprite, x: 500, duration: 1000 }, if: () this.health 0 // 条件不满足则跳过 });5.5 其他值得关注的点GameObject.setTexture新增可选参数updateSize与updateOrigin控制设置纹理时是否更新对象尺寸与原点两者都会传给setFrame。Physics.Arcade.World.singleStep()新方法让 Arcade 物理世界精确推进 1 步调试利器感谢 monteiz。RenderTarget.willResize(w, h)新方法判断给定新宽高是否会导致 Render Target 被重设尺寸。Structs.Map.setAll(elements)新方法批量向 Map 中写入数组元素可链式调用。Geom.Line.setFromObjects(objA, objB)新方法以两个对象Game Object 或 Vector2 类对象的位置设置线段端点。Curves.Path.defaultDivisions新属性与getPoints(stepRate)新可选参数控制路径采样点密度。5.6 更新与修复亮点节选AnimationManager.globalTimeScale全局生效现在作用于所有使用 Animation 组件的游戏对象可全局加速/减速所有动画感谢 TJ09。Rope 支持 Post FXRope 游戏对象现会调用initPostPipeline可直接应用 glow、blur 等后处理Issue #6550。Tween 销毁防护Tween.stop与Tween.remove现在会先检查Tween.parent是否存在避免对已销毁 tween 误调用导致报错Issue #6539。iOS 启用原生稳定排序iOS 及任何识别为AppleWebKit的浏览器将Device.es2019置为true使用原生数组稳定排序修复 iOS 上重叠粒子闪烁问题Issue #6483。Math.Wrap回滚到旧版本Issue #6479。Graphics 默认样式透明Graphics 游戏对象现在默认线条与填充为全透明黑色避免未设置样式时误渲染其他 Shape 的颜色。Tile改用AlphaSingle组件此前错误使用Alpha组件导致每角独立 alpha方法看似可用实则渲染无效现已修正为单一 alpha 值Issue #6594。Game Config 宽高字符串解析加强width/height传字符串时带%如100%按父容器比例解析其他如800px一律视为固定值避免字符串乘出巨大画布导致 WebGL 纹理超限。LoaderPlugin.shutdown清理监听器Scene 关闭时清除绑定在 Loader 实例上的事件监听Issue #6633。DynamicTexture内存泄漏修复preDestroy更名为destroy并正确清理引用setSize不再残留 WebGLTextureDynamicTexture.width/height现作为只读属性暴露。多 Atlas 粒子渲染修复ParticleEmitterWebGLRenderer改用particle.frame作为批次中的glTexture来源修复粒子从多图集纹理取错帧的问题Issue #6515。Sprite Sheet 法线贴图加载顺序修复无论法线贴图是否先于精灵表完成加载精灵表都会与法线贴图正确合并进 Texture ManagerIssue #6491。六、升级注意事项速查渲染roundPixels在 3.70 默认开启当前 v4.2.1 默认已恢复为false建议显式配置pixelArt始终需要显式开启。Nine Slice升级 Texture Packer 到 v7.1.0 即可享受 scale9 自动导出旧 Atlas 不受影响仍可手动传边框。Arcade Physics碰撞分类默认行为与旧版完全一致全碰撞新增 API 是可选增强directControl与slideFactor默认关闭/为 1不会改变既有物理表现。FXdisablePreFX/disablePostFX必须在 Game Config 中设置且启动后不可变若使用 FX 建议升级以获取 Blur 质量、RenderTarget resize 等修复。文本letterSpacing逐字符渲染成本高大段文本请使用位图字体。参考资料更新日志原文changelog/v3/3.70/CHANGELOG-v3.70.md游戏配置解析src/core/Config.jsFrame 的 scale9 支持src/textures/Frame.jsNineSlice 的 setSlices 与 skipScale9src/gameobjects/nineslice/NineSlice.jsArcade Body 的 slideFactor / directControlsrc/physics/arcade/Body.js、src/physics/arcade/Body.jsArcade World 的碰撞掩码过滤src/physics/arcade/World.js文中所有源码路径均基于当前仓库Phaser 4.2.1API 名称与 changelog 记载一致个别默认值如roundPixels随版本演进有调整已在对应小节明确说明。【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考