
Phaser 3.19 Naofumi 版本全解析Tween 事件系统重构、Shader 离屏渲染与快照能力实战指南【免费下载链接】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.19.md 为核心系统梳理 Phaser 3.19.0 Naofumi2019 年 8 月 8 日发布对 Tween 补间系统的重大重构、Spine 插件 3.7 运行时的完整升级以及 Shader 离屏渲染、Render Texture 快照、WebGL 上下文事件等新能力的落地细节。文中所有功能均结合当前仓库源码逐一印证读完你将掌握 3.19 引入的新 API 的完整用法、行为变化背后的实现原理以及在项目中使用这些特性的可复现实战方案。版本背景与变更总览Phaser 3.19.0 以动漫角色 Naofumi 命名是继 3.18 Raphtalia 之后的一个里程碑版本。3.18 完成了输入系统旧队列模式的清理与鼠标滚轮、鼠标按键状态的原生支持而 3.19 则把重心放在了三块Tween 系统重构Tween 从普通对象升级为事件发射器新增start/from/to三段式属性配置与StaggerBuilder交错构建器并重写了seek逻辑Shader 渲染管线增强Shader 可以离屏渲染到自己的帧缓冲输出可作为纹理供 Sprite 等其他游戏对象使用实现了着色器级联渲染快照体系Render Texture、WebGL 帧缓冲和 Canvas 均支持按像素、按区域取图可直接保存到 Texture Manager。此外还包含 Spine 插件 3.7 Runtime 完整升级、输入命中区调试可视化、WebGL 上下文丢失/恢复事件等一系列新特性与数十项 Bug 修复。Tween 系统重构从数据对象到事件发射器Tween 继承 EventEmitter事件体系全面落地3.19 之前Tween 的生命周期回调主要靠配置对象中的onStart、onComplete等函数钩子行为分散且难以统一监听。3.19 让Tween类直接继承事件发射器从此可以在补间实例上使用tween.on(...)监听其自身事件。在源码层面这一变化体现在 BaseTween.jsBaseTween通过Extends: EventEmitter继承eventemitter3并在构造函数中调用EventEmitter.call(this)。所有 Tween 与 Timeline 都基于该基类因此事件能力对两者同时生效。3.19 新增的 Tween 事件常量位于 src/tweens/events 目录每个事件对应一个字符串常量事件常量监听写法触发时机Tween.ACTIVE_EVENTtween.on(active, fn)Tween 被 Tween Manager 激活可能因 delay 尚未实际开始补间Tween.START_EVENTtween.on(start, fn)Tween 真正开始补间第一个属性Tween.UPDATE_EVENTtween.on(update, fn)Tween 属性每次更新Tween.LOOP_EVENTtween.on(loop, fn)Tween 循环一次且loopDelay若有已到期之后Tween.REPEAT_EVENTtween.on(repeat, fn)属性重复一次且repeatDelay若有已到期之后Tween.YOYO_EVENTtween.on(yoyo, fn)属性执行 Yoyo 反弹且hold延迟若有已到期之后Tween.COMPLETE_EVENTtween.on(complete, fn)Tween 完成或被停止对应的事件常量文件如 TWEEN_ACTIVE_EVENT.js、TWEEN_START_EVENT.js也明确了事件参数回调会收到(tween, targets)其中targets在补间有多个目标时是目标数组。一个完整的事件监听示例this.tweens.add({ targets: image, x: 500, ease: Power1, duration: 3000 }).on(start, function (tween, targets) { // Tween 真正开始改变属性时才触发delay 结束后 console.log(补间开始); }).on(update, function (tween, targets) { console.log(当前进度, tween.progress); }).on(complete, function (tween, targets) { console.log(补间完成); });onActive 与 onStart 语义分离这是 3.19 的一个重要行为修正也是 变更日志 中标注为 Fix #3330 的问题此前onStart在 Tween Manager 激活补间的瞬间就会触发即使补间仍处于 delay 阶段。现在onActive对应Tween.ACTIVE_EVENTTween Manager 将补间唤醒的那一刻触发即使尚未开始补间任何值onStart对应TWEEN_START_EVENT仅在 Tween 真正开始补间属性值时触发通常位于 delay 到期之后。从 Tween.js 的seek实现src/tweens/tween/Tween.js#L500-L534可以看到Tween 在重置、初始化数据后先调用dispatchEvent(Events.TWEEN_ACTIVE, onActive)随后才逐步推进至属性更新两个回调的先后次序在内部被严格区分。配套的Tween.startDelay属性在初始化时被设置为最短启动前时间每帧递减直到归零后触发onStart变更日志 对这一机制有明确说明。属性配置升级start / from / to 三段式3.19 之前补间属性只有从当前值到目标值一种模型无法表达先瞬移再补间的复杂需求。3.19 为属性配置新增了from与start键与既有目标值to组合出三种模式对应 Fix #4493// 模式一from to // 先在 delay 到期后把 alpha 瞬移到 0再从 0 补间到 1 alpha: { from: 0, to: 1 } // 模式二start to // 补间一激活就立即把 alpha 置为 0然后在整个 duration 内补间到 1 alpha: { start: 0, to: 1 } // 模式三start from to // 激活立即置 0delay 结束后置 0.5再从 0.5 补间到 1 alpha: { start: 0, from: 0.5, to: 1 }这套机制在源码中由 TweenData.js 承担getStartValue负责取start阶段的起始值getEndValue负责取to目标值getActiveValue即TweenData.getActiveValue属性在非空时提供激活瞬间立即写入目标属性的值。TweenData 完成时会把current精确置为start或end取决于播放方向并把这个终值写入目标属性保证补间结束后属性值与目标严格一致。seek 重写任意时间点精确跳转Tween.seek在 3.19 被彻底重写Fix #4409现在可以在补间未播放或已播放时跳转到任意时间点——无论补间是否包含 repeat、loop、delay 或 hold 设置。关键设计是跳转过程中默认不触发任何事件与回调通过内部isSeeking标志控制见 Tween.js#L75-L80方法签名为seek(amount, delta, emit)其中delta控制跳转的步长默认 16.6ms步长越大跳转越快但精度越低emit为true时允许跳转过程发出事件实现上先重置并重新初始化补间数据再按Math.floor(amount / delta)迭代步进到目标时间点详见 Tween.js#L500-L534。var tween this.tweens.add({ targets: image, x: 1000, duration: 2000, repeat: 3 }); // 直接跳到补间开始后 1500ms 的位置不触发任何事件 tween.seek(1500);新增 StaggerBuilder多目标交错补间StaggerBuilder是 3.19 新增的构建器函数src/tweens/builders/StaggerBuilder.js它返回一个交错函数Tween 系统会为每个目标调用该函数基于目标索引、总目标数及配置计算出该目标的属性值如 delay。它通过this.tweens.stagger(...)暴露给用户入口见 TweenManager.js#L536-L574。三种基本用法源码 JSDoc 与 TweenManager.js 均有完整示例// 1) 固定步长每个目标依次延迟 100ms this.tweens.add({ targets: [spriteA, spriteB, spriteC], scale: 0.2, ease: linear, duration: 1000, delay: this.tweens.stagger(100) }); // 2) 区间步长delay 在 500ms ~ 1000ms 之间在所有目标间均匀分布 delay: this.tweens.stagger([ 500, 1000 ]) // 3) 网格 方向 缓动10x6 网格从中心向外交错使用 cubic.out 缓动 delay: this.tweens.stagger(500, { grid: [ 10, 6 ], from: center, ease: cubic.out })StaggerConfig支持的关键配置项对应 StaggerBuilder.js 的参数解析配置键说明start交错结果的起始偏移量默认0ease对交错数值应用缓动函数如cubic.out默认nullgrid形如[宽度, 高度]的网格数组按网格坐标计算欧氏距离而非线性索引from交错起点first首个目标、last末个目标、center从中心向外或一个数值索引默认0值得注意的实现细节网格模式预计算一旦提供grid构建器会预先计算每个网格单元到起点的距离并缓存在gridValues二维数组中StaggerBuilder.js#L79-L130避免每次更新重复计算数值模式from为数字时使用Math.abs(from - index)作为交错索引因此可以指定任意起始目标区间模式[value1, value2]的差值被均分到所有目标上配合缓动函数可生成非线性交错。仓库的测试用例 tests/tweens/builders/StaggerBuilder.test.js 覆盖了上述行为默认数值模式下index 0返回 0、index 1返回value1 * 1、start偏移叠加、浮点交错值、单目标total1边界、从 center 向外扩散、from: last从末到首、from数值索引以及 0 值与负值交错等场景可直接作为功能契约参考。回调签名与内部机制的连带调整3.19 对与 Tween 相关的若干函数签名做了统一使用自定义函数的用户需要关注getStart/getEnd自定义属性函数的签名由(target, key, value)扩展为(target, key, value, targetIndex, totalTargets, tween)新参数追加在末尾旧函数无需改动即可继续工作LoadValue 生成器函数如delay、repeat的签名同步改为同样的六参数形式若你自定义过此类生成器需要按新签名修改TweenData构造函数新增index与getActive参数TweenData.js 的类注释有完整说明直接创建 TweenData 的代码需使用新签名easeParams此前只对字符串形式的缓动名生效现在对任何自定义缓动函数同样生效Fix #3826GetEaseFunction现在接受更宽松的字符串输入支持小写如back也支持省略方向中的ease前缀如back.in、back.inoutTween 与 Timeline 的state变更都会先于事件/回调设置允许你在事件处理器中安全地修改 Tween 状态TIMELINE_LOOP_EVENT移除了语义错误的loopCounter参数通过TweenManager.create创建的补间现在无需手动激活直接调用play即可启动Fix #4632Tween.onLoop/onRepeat回调严格在对应延迟loopDelay/repeatDelay到期后触发Timeline 的onLoop/onComplete也遵循同样的延迟语义。Shader 离屏渲染让着色器输出成为纹理3.19 为 Shader.js 引入了完整的离屏渲染管线核心是Shader.setRenderToTexture方法src/gameobjects/shader/Shader.js#L395-L424。调用后 Shader 不再直接绘制到显示列表而是渲染到自己的帧缓冲 / WebGLTexture从而实现着色器级联把一个 Shader 的输出作为另一个 Shader 的sampler2D输入纹理化把 Shader 输出注册到 Texture Manager供 Sprite、Image 等任何基于纹理的游戏对象使用。var shader this.add.shader(myShader, x, y, width, height); // 将 shader 离屏渲染并注册为名为 doodle 的纹理 shader.setRenderToTexture(doodle); // 直接使用该纹理创建 Image this.add.image(400, 300, doodle);源码实现要点Shader.js#L395-L424方法内部创建一个与 Shader 同尺寸的离屏相机和DrawingContextglTexture保存 WebGLTexture 引用传入key时会调用scene.sys.textures.addGLTexture(key, this.glTexture)将纹理注册进全局 Texture Manager一旦启用renderToTexture标志置为trueShader 每帧刷新离屏纹理因此引用该纹理的 Sprite 会随 Shader 实时更新注意它保存的是活动引用销毁 Shader 前务必清理使用该纹理的对象。配套 API 一览API说明Shader.setSampler2DBuffer(texture)将某个 WebGLTexture 直接作为 Shader 的 sampler2D uniform 传入用于多 Shader 互相作为缓冲Shader.renderToTexture布尔属性标记 Shader 是否处于离屏渲染状态Shader.framebuffer保存 WebGLFramebuffer 引用Shader.glTexture保存 WebGLTexture 引用Shader.texture保存注册到 Texture Manager 后的 Phaser Texture 引用TextureManager.addGLTexture(key, glTexture)新方法见 src/textures/TextureManager.js#L525把 WebGLTexture 按 key 注册进纹理管理器TextureSource.isGLTexture布尔属性标记底层数据是否为 WebGLTextureTextureTintPipeline.batchSpriteGLTexture 来源的 TextureSource 渲染时自动翻转 UV渲染快照从 Render Texture、帧缓冲与 Canvas 取图3.19 把截图能力系统化覆盖 WebGL 与 Canvas 两条渲染路径并统一支持单像素取色与区域取图两种形态。Render Texture 快照RenderTexture.js 新增三个方法snapshot(callback, type, encoderOptions)src/gameobjects/rendertexture/RenderTexture.js#L646对整个 Render Texture 当前状态截图返回 Image 对象snapshotArea(x, y, width, height, callback, type, encoderOptions)RenderTexture.js#L615截取指定区域snapshotPixel(x, y, callback)RenderTexture.js#L672提取单个像素返回 Color 对象。// 截取整个 Render Texture 并打印 Image renderTexture.snapshot(function (image) { console.log(image); // 可进一步 this.textures.addImage(saved, image) 存入纹理管理器 }); // 提取 (10, 10) 处的像素颜色 renderTexture.snapshotPixel(10, 10, function (color) { console.log(color.r, color.g, color.b, color.a); });WebGL 帧缓冲与 Canvas 快照WebGLRenderer.snapshotFramebuffer配合工具函数WebGLSnapshot可对任意 WebGL 帧缓冲如 Render Texture 或 Shader 使用的那个取单像素 Color 或区域 Image并可选保存到 Texture ManagerCanvasRenderer.snapshotCanvas对任意 Canvas 对象执行同样的两种取图操作SnapshotState对象新增isFramebuffer布尔值与bufferWidth、bufferHeight整数属性用于描述快照来源。纹理管理器的配套能力RenderTexture.glTexture属性直接暴露 Render Texture 底层的 WebGLTexture方便作为 sampler2D 传给 ShaderTextureManager.getBase64现在对非图像纹理如 WebGL 纹理会发出控制台警告CanvasTexture.update在 WebGL 下会自动调用refreshdraw与drawFrame均如此Canvas 模式下无需再手动 refreshCanvasTexture.getPixels默认区域改为0x0 至 宽 x 高无参数调用即可取得全部像素。新特性速查输入调试、几何类型、上下文事件与更多输入命中区调试可视化InputPlugin.enableDebug(gameObject, color)src/input/InputPlugin.js#L2632为指定游戏对象的命中区创建一个调试形状实时跟踪该对象帮助检查命中区大小与位置InputPlugin.removeDebug(gameObject)InputPlugin.js#L2751移除并销毁调试形状Pointer.locked只读属性通过 Pointer Lock API 判断指针是否已锁定Pointer.updateWorldPoint(camera)基于相机变换更新指针的worldX/worldYPointer.movementX/movementY在指针锁定时直接取自 DOM 事件值不再增量累加Fix #4611Pointer.velocity与Pointer.midPoint现在每帧更新无论指针是否移动基于motionFactor平滑衰减。WebGL 上下文丢失与恢复3.19 用事件取代了旧的回调机制Game.CONTEXT_LOST_EVENTWebGL 上下文丢失时由 Game 实例派发Game.CONTEXT_RESTORED_EVENT上下文恢复时派发对应的WebGLRenderer.lostContextCallbacks/onContextLost与restoredContextCallbacks/onContextRestored已移除事件常量定义于 src/core/events。this.game.events.on(CONTEXT_LOST, function () { // 保存关键状态准备恢复 }); this.game.events.on(CONTEXT_RESTORED, function () { // 重新加载纹理、重建缓冲 });几何类型常量新增GEOM_CONST常量对象src/geom/const.js统一标识各几何体类型。Circle、Ellipse、Line、Point、Polygon、Rectangle、Triangle均新增只读type属性用于快速类型比较配合 src/geom 下各几何模块使用。其他值得关注的新能力Math.ToXY(index, width, height, out?)src/math/ToXY.js把一维索引转换为网格中的Vector2坐标例如 6×4 网格中索引 16 返回(4, 2)超出范围返回零向量GroupCreateConfig.quantity用配置对象创建 Group 时可通过quantity直接指定创建数量适用于不需要frameQuantity/repeat高级能力的单帧对象批量创建PluginManager.removeGameObject/GameObjectFactory.remove/GameObjectCreator.remove自定义游戏对象类型插件销毁时可反注册工厂与创建器避免污染全局命名空间Pointer新属性button与leftButtonReleased/rightButtonReleased/middleButtonReleased/backButtonReleased/forwardButtonReleased方法由 3.18 引入3.19 持续完善指针事件处理Texture.remove(name)按名称从 Texture 中移除 FrameFix #4460WebGLRenderer.currentType/newType/nextTypeMatch暴露当前渲染对象的类型信息为跨对象批处理提供判断依据。Bug 修复与行为修正精选3.19 修复了大量影响实际开发的问题以下挑选与日常开发最相关的几类渲染与翻转类Sprite 设置flipX/flipY后偏移帧渲染错位、动画抖动的问题Fix #4636 / #3813带自定义枢轴的动画如 Texture Packer pivot 生成的翻转后错位Fix #4155Arc / Circle 形状在 WebGL 下中心偏移半半径的问题Fix #4620Origin.updateDisplayOrigin不再对显示原点做Math.floor1×1 像素对象可以正确使用 0.x 原点Fix #4126TransformMatrix.rotation现在返回正确归一化后的旋转值。输入与指针类Pointer.getDuration在桌面返回负值 / 移动端返回 NaNFix #4612downTime/upTime/moveTime的 NaN 问题同步修复InputManager.resetCursor会先检查 canvas 元素是否存在Fix #4662在pointerdown/pointerup处理器中调用Scene.destroy不再因访问已销毁的管理器而报错Fix #4436POINTERLOCK_CHANGE事件恢复由 Input Manager 派发requestPointerLock()不再报错。Tilemap 与物理类Tilemap.renderDebug因调用过期的 Graphics API 而失败的问题Tilemap.createFromObjects现在会使用传入的scene参数Matter.Factory.constraint/joint/worldConstraint支持零长度约束长度可设为 0 或省略自动计算DynamicTilemapLayer.destroy/StaticTilemapLayer.destroy增加幂等保护不会重复执行销毁序列。Scale Manager 与生命周期类全屏模式下报错 TypeError: this.removeFullscreenTarget is not a functionFix #4605缩放值无法从其他值改回 1Fix #4633ScaleManager._resetZoom新增内部标志在游戏缩放因子变化时置位HEADLESS 模式销毁 Scene 时不再因访问 gl renderer 而抛错Fix #4467。Tween 专项修复Tween.restart会把elapsed、progress、totalElapsed、totalProgress归零而不是累加Animation.setRepeat能正确重置repeatCounter使已绑定的补间实例同步改变重复次数Fix #45532 帧动画移除一帧后再渲染不再报错Fix #4621Shader.uniforms改用深拷贝Extend 而非 Clone避免多个 Shader 实例共享 uniformsFix #4641。变更带来的迁移注意事项如果你正从 3.18 或更早版本升级需要关注以下破坏性 / 行为变化onStart语义变化依赖激活即触发逻辑的代码应改用新的onActiveseek默认静默旧代码中依赖 seek 触发回调的行为不再成立需要时显式传入emit true自定义生成器签名扩展自定义delay/repeat生成器与getStart/getEnd函数需要适配新的六参数签名上下文回调移除onContextLost/onContextRestored已被CONTEXT_LOST/CONTEXT_RESTORED事件取代Timeline 事件参数变化TIMELINE_LOOP_EVENT不再携带loopCounter参数。当前仓库的 Tween 实现已演进至 src/tweens含tween/BaseTween.js、tween/Tween.js、tween/TweenData.js与builders/StaggerBuilder.js等配套测试位于 tests/tweens3.19 引入的机制事件分发、start/from/to 属性解析、stagger 交错计算等至今仍是 Phaser 3 后续版本 Tween 系统的基础阅读 tests/tweens/builders/StaggerBuilder.test.js 与 tests/tweens/TweenManager.test.js 可以进一步验证这些行为的边界条件。【免费下载链接】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),仅供参考