Phaser 4.0.0 RC7 新特性全解析:滤镜、渐变、噪声、Tint 与纹理系统升级指南
【免费下载链接】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/v4/4.0-rc/CHANGELOG-v4.0.0-rc.7.md 编写,全面梳理 Phaser 4.0.0 Release Candidate 7 引入的新功能与修复项。你将掌握:如何用一行 Action 为相机或 GameObject 快速搭建 Bloom/Shine 特效与蒙版;如何用全新的
Gradient、Noise游戏对象与ColorBand/ColorRamp构建程序化渐变与噪声纹理;如何理解 Tint 体系的破坏性重构;以及纹理、位图字体、TimeStep等关键修复的底层原理与实战影响。
引言:RC7 带来了什么
Phaser 4.0.0 Release Candidate 7(下文简称 RC7)是 Phaser 4 正式发布前的关键候选版本,聚焦于把渲染管线中最"炫酷"的部分——滤镜(Filters)、渐变(Gradient)、程序化噪声(Noise)、蒙版(Mask)与着色(Tint)——从"能用"打磨到"好用"。它引入了一批开箱即用的动作(Actions),让原本需要手工组合多层滤镜才能实现的 Bloom、Shine 特效变成一行调用;新增了Gradient与Noise系列游戏对象,让开发者无需编写 GLSL 即可在场景中直接渲染渐变与多种噪声图案;同时对 Tint 系统做了破坏性重构,用tintMode取代了旧的tintFill语义。
本文以该 CHANGELOG 为骨架,结合 src/actions、src/display/ColorBand.js、src/gameobjects/gradient/Gradient.js、src/gameobjects/noise/Noise.js 等源码,逐一展开每个特性背后的实现原理与配置细节。
一、Actions 新工具:一行代码搭建视觉特效
RC7 在 src/actions 目录中新增了四个动作工具。它们都是纯函数,接收"目标或目标数组",返回创建出的资源引用,方便你后续手动控制。
1.1 AddEffectBloom:给场景叠加辉光
Phaser.Actions.AddEffectBloom(items, config)通过组合多个滤镜来模拟 Bloom 辉光效果。根据 src/actions/AddEffectBloom.js 的实现,它内部按以下顺序组装管线:
ParallelFilters:将滤镜流分成top与bottom两路,使特效结果能与原图重新合成;Threshold:剔除较暗的颜色,只保留高亮区域;Blur:将剩余的高亮颜色向外扩散,形成光晕。
配置参数(均来自 src/actions/AddEffectBloom.js 的默认值解析):
| 参数 | 默认值 | 作用 |
|---|---|---|
threshold | 0.5 | 亮度阈值,高于此值的像素才参与辉光 |
blurRadius | 2 | 模糊半径 |
blurSteps | 4 | 模糊步数 |
blurQuality | 0 | 模糊质量等级 |
blendAmount | 1 | 辉光与原图的混合强度 |
blendMode | BlendModes.ADD | 辉光混合模式,默认加法混合 |
useInternal | false | 使用内部还是外部滤镜列表 |
基本用法:
// 给场景主相机直接叠加辉光 Phaser.Actions.AddEffectBloom(this.cameras.main); // 返回值是数组,可解构出内部滤镜进行精细控制 const { parallelFilters, threshold, blur } = Phaser.Actions.AddEffectBloom(this.cameras.main)[0]; // 关闭或销毁辉光 parallelFilters.active = false; // 停用 parallelFilters.destroy(); // 销毁实战注意:Bloom 最适合作为全屏效果。源码注释明确指出,如果把它应用在带有透明区域的 GameObject 上,辉光无法与背景正确混合——因为光晕需要 ADD 混合,而物体本身需要 NORMAL 混合,二者无法兼得。因此对 GameObject 应用 Bloom 时,建议使用不透明贴图。
1.2 AddEffectShine:模拟高光掠过表面
Phaser.Actions.AddEffectShine(items, config)模拟一个高光在表面上掠过的镜面反射效果(例如高亮重要物品、传达光泽感)。从 src/actions/AddEffectShine.js 可以看到,它内部会创建一整组资源:
- 一个Gradient对象生成高光区域;
- 一个DynamicTexture承载高光区域;
- 一个Tween动画驱动高光移动;
- 一个Blend滤镜将高光与图像合成;
- 可选一个ParallelFilters把图像其余部分加回。
关键配置(见 src/actions/AddEffectShine.js 与文档注释):
| 参数 | 默认值 | 作用 |
|---|---|---|
direction | 0.5(弧度) | 高光移动方向 |
scale | 2 | 高光尺度,默认为目标两倍,保证高光完全离开画面后再循环 |
radius | 0.5 | 半径偏移,给渐变留出进出画面的空间 |
colorFactor | [1.15, 0.85, 0.85, 1] | 高光 RGBA 颜色系数,可大于 1 制造超亮高光;默认带轻微红调 |
displacementMap/displacement | 无 /0.1 | 给渐变叠加置换滤镜,模拟轻微磨砂表面 |
duration/yoyo/ease | 2000/false/ 无 | Tween 动画参数 |
repeatDelay | 0 | 循环间隔 |
reveal | false | 开启"揭示"模式,图像仅在光扫过时可见 |
useExternal | false | 使用外部还是内部滤镜列表 |
示例:缓慢地让一道青色高光在图片上来回扫动,并叠加置换贴图做出脏旧质感:
const { dynamicTexture, gradient, tween } = Phaser.Actions.AddEffectShine(this.image, { duration: 5000, direction: Math.PI / 2, scale: 1, displacementMap: 'displace', colorFactor: [ 0.5, 2, 2, 1 ], yoyo: true, ease: 'Quad.inout' })[0]; // 返回数组源码中值得注意的是:方向角会被规范化到0..2π区间,并根据象限自动计算渐变的起点角(左上/右上/左下/右下),见 src/actions/AddEffectShine.js。所有资源都会在目标销毁时自动清理(DESTROY/DESTROY_EVENT事件钩子),每个目标拥有独立资源集,互不影响。
1.3 AddMaskShape:形状蒙版一键生成
Phaser.Actions.AddMaskShape(items, config)用 Shape 快速为 GameObject 或 Camera 添加蒙版。根据 src/actions/AddMaskShape.js 的实现,它创建一个形状并用FitToRegion将其缩放到目标区域,支持模糊边缘与反相。
形状类型(config.shape):circle(默认)、square、rectangle、ellipse。矩形与椭圆用config.aspectRatio控制宽高比(默认1)。
其他配置:
| 参数 | 默认值 | 作用 |
|---|---|---|
padding | 0 | 向内部收缩形状区域,给模糊扩散留出空间 |
blurRadius/blurQuality/blurSteps | 无 | 给蒙版形状叠加模糊滤镜,实现柔和边缘 |
invert | 无 | 是否反转蒙版 |
region | 场景画布或对象尺寸 | 目标区域;不传时自动推断 |
scaleMode | 无 | 传递给 FitToRegion 的缩放模式 |
useInternal | false | 内部还是外部滤镜列表 |
示例(摘自 src/actions/AddMaskShape.js):
const mask = Phaser.Actions.AddMaskShape(target, { blurRadius: 2, padding: 2 })[0]; // 返回 Mask 滤镜数组 const shape = mask.maskGameObject; // 持有 shape 引用可防止被垃圾回收 const blur = shape.filters.external.list[0];几个实现细节值得留意:创建的 Shape 会立即从场景子列表中移除(src/actions/AddMaskShape.js),无需管理生命周期,待 Mask 滤镜销毁后自动被回收;padding通过重新构建一个内缩的Rectangle区域实现;默认蒙版是"圆形但按画布 X/Y 两轴分别缩放",因此严格说不再是正圆。
1.4 FitToRegion:把对象变换进任意区域
Phaser.Actions.FitToRegion(items, scaleMode, region, itemCoverage)将对象变换到某个矩形区域(如屏幕)内。它非常适合快速铺满背景、移动对象而不必关心原点、或覆盖已知尺寸的缺口。
三种 scaleMode(见 src/actions/FitToRegion.js):
| scaleMode | 行为 |
|---|---|
-1 | 两轴等比缩放,对象内切于区域(完全在区域内) |
0 | 两轴独立缩放,恰好填满区域(默认,可能拉伸变形) |
1 | 两轴等比缩放,对象外接区域(完全覆盖区域) |
区域默认为场景画布{ x: 0, y: 0, width: scene.scale.width, height: scene.scale.height }。如果目标是 Container 这类没有尺寸/原点属性的对象,可用itemCoverage传入width、height、originX、originY补充数据(优先级高于对象自身属性)。负缩放会被转为正数,需要翻转请自行处理。
二、ColorBand 与 ColorRamp:程序化渐变的数据基础
RC7 新增的两个显示类Phaser.Display.ColorBand与Phaser.Display.ColorRamp是整个渐变体系的基石,被Gradient游戏对象内部使用。
2.1 ColorBand:两个颜色之间的一次过渡
src/display/ColorBand.js 描述一次从colorStart到colorEnd的颜色过渡,并支持三个控制维度:
middle(默认0.5):控制过渡的中间点形状。源码使用伽马曲线调整渐变斜率,数学关系为0.5 = middle^gamma,即gamma = log(middle, 0.5)(见 src/display/ColorBand.js)。interpolation:插值样式,取值 0-4:0 LINEAR:直线混合;1 CURVED:首尾变化快、中间平缓,适合凸面;2 SINUSOIDAL:中间变化快、首尾平缓,适合平滑过渡;3 CURVE_START:起点变化快、终点平缓;4 CURVE_END:终点变化快、起点平缓。
模式 2/3/4 直接使用 circular 缓动函数,模式 1 使用基于单位圆的自定义公式(src/display/ColorBand.js)。
colorSpace:混合发生的色彩空间,取值 0-3:0 RGBA:各通道直接混合(在 RGB 空间混合不符合人眼感知,可能产生不准确结果);1 HSVA_NEAREST:在 HSVA 空间混合,更好保留饱和度与明度,色相按最短角度混合(如红与蓝走紫色而非绿色);2 HSVA_PLUS:色相角总是递增;3 HSVA_MINUS:色相角总是递减。
setColors()接受多种颜色格式:数字(24/32 位 RGB/ARGB)、十六进制字符串、0-1 范围的 RGB/RGBA 数组,或Color对象实例(src/display/ColorBand.js)。颜色以未预乘 alpha的方式处理,因此 RGB 值可以大于 alpha。
2.2 ColorRamp:由多个 ColorBand 组成的色带序列
src/display/ColorRamp.js 将多个ColorBand首尾相接成一条色带,供Gradient使用。注意:波段必须端到端紧密排列、不能有缝隙,渐变着色器默认假设如此;首尾可以留空,但重叠与缝隙的行为不可预期。
ColorRamp的核心亮点是GPU 编码:默认开启的gpuEncode会把整条色带编码进一张数据纹理(data texture),供着色器直接采样。encode()的编码布局如下(src/display/ColorRamp.js):
- 前 2 个 texel:首波段起点与末波段终点;
- 中间一块:二叉对称树,用于在着色器中按进度快速定位所属波段。例如 10 个波段的端点存储顺序为
[7, 3, 11, 1, 5, 9, 13, 0, 2, 4, 6, 8, 10, 12, 14],不存在的索引会被填充; - 最后一块(从
dataTextureFirstBand开始):每个波段 3 个 texel,依次为colorStart、colorEnd、以及colorSpace*255 + interpolation + middle/2的合成值。
常用方法:
setBands(bands, encode):替换波段并自动重新编码;fixFit(start, end, purgeZeroLength, encode):让每个波段的起点对齐上一波段终点,消除缝隙;可强制拉长到指定范围(如 0-1);默认剔除零长度波段;splitBand(band, steps, quantize, encode):把一个波段拆分成多个,quantize为 true 时每个子波段用单一平色(量化);getColor(index):取色带中 0-1 进度位置的颜色;destroy():销毁数据纹理。
兼容性提醒:如果你手动修改波段数据而非通过
setBands(),必须自行调用encode()重建数据纹理;自动更新仅在创建与setBands()时发生,因为框架不希望在你即将覆盖的数据上浪费重建开销。
三、GameObjects.Gradient:直接渲染渐变的新游戏对象
Phaser.GameObjects.Gradient是一个渲染渐变的四边形游戏对象。从 src/gameobjects/gradient/Gradient.js 可知,它本质上是一个使用专用着色器程序的Shader子类(Extends: Shader),片段着色器为Gradient-frag,并注入Ramp-glsl头来读取 ColorRamp 数据纹理。它的颜色数据由ColorRamp(内含一个或多个ColorBand)决定,色带沿shape布局、从start位置出发,shapeMode决定渐变向其他区域的填充方式。
3.1 五种形状(shapeMode)
RC7 提供LINEAR、BILINEAR、RADIAL、CONIC_SYMMETRIC、CONIC_ASYMMETRIC五种渐变形状。注意形状被适配到正方形:如果宽高不等,形状会被拉伸变形——有时这正是你想要的。
3.2 四种重复模式(repeatMode)
渐变进度是一个数值(0 为shape向量起点,1 为终点),重复模式决定了超出 0-1 范围后的行为(src/gameobjects/gradient/Gradient.js):
| 值 | 名称 | 行为 |
|---|---|---|
0 | EXTEND | 值被钳制在 0-1,两端变成平色 |
1 | TRUNCATE | 0-1 之外的值被丢弃,两端变透明 |
2 | SAWTOOTH | 对 1 取模,渐变重复(锯齿) |
3 | TRIANGULAR | 升到 1 再降回 0,来回平滑往复(三角波) |
注意:圆锥渐变(conic)除非施加
offset,否则永远不会离开 0-1 范围;加了 offset 后表现可能异常。
3.3 噪点抖动与动画
- Interleaved Gradient Noise 抖动:通过
dither配置启用,用交错梯度噪声抖动消除渐变条带(banding)伪影; - 动画:直接修改
offset属性即可让渐变动起来。文档建议:模式 1(TRUNCATE)下把 offset 在 -1 到 1 之间动画可制造一次性冲击波;模式 2(SAWTOOTH)或 3(TRIANGULAR)则适合制造持续移动的图案。若修改色带数据,需调用gradient.ramp.encode()重建。
示例(来自 src/gameobjects/gradient/Gradient.js):
// 一个简单的从左到右线性渐变 scene.add.gradient(undefined, 100, 100, 200, 200); // 一个发光的"光晕":径向渐变 + 抖动 + 正弦波动画 var halo = scene.add.gradient({ bands: [ { start: 0.5, end: 0.6, colorStart: [ 0.5, 0.5, 1, 0 ], colorEnd: 0xffffff, colorSpace: 1, interpolation: 4, }, { start: 0.6, end: 1, colorStart: 0xffffff, colorEnd: [ 1, 0.5, 0.5, 0 ], colorSpace: 1, interpolation: 3, }, ], dither: true, repeatMode: 1, // TRUNCATE shapeMode: 2, // RADIAL start: { x: 0.5, y: 0.5 }, shape: { x: 0.5, y: 0.0 }, }, 400, 300, 800, 800); // 动画:随时间改变 offset halo.offset = 0.1 * (1 + Math.sin(time / 1000));Gradient 具备普通 GameObject 的一切能力:可交互、可放进滤镜与蒙版中。相关工厂/创建器位于 src/gameobjects/gradient。
四、GameObjects.Noise 系列:程序化噪声渲染
RC7 引入一整族噪声游戏对象(src/gameobjects/noise),它们同样是Shader子类(片段着色器Noise-frag)。
4.1 Noise:白噪声
Phaser.GameObjects.Noise渲染"白噪声"——随机值。根据 src/gameobjects/noise/Noise.js,噪声通过对偏移像素坐标做哈希生成,因此同一位置永远生成同一噪声,效果可复现。
noiseOffset([x, y]数组):动画滚动噪声。浮点精度对此效果至关重要:滚动很远会出块状物,滚动极近会导致输出完全改变。更有效的做法是用setRenderToTexture把它当纹理喂给 TileSprite。noisePower(默认1):控制值曲线,雕琢输出等级——幂越高压低高值,幂越低压低低值。noiseColorStart/noiseColorEnd(默认黑→白):低值/高值对应的颜色,可自定义任意颜色与 alpha。- 算法可选择三角函数或 PCG哈希;输出支持灰度、随机彩色或随机法线贴图。
4.2 NoiseCell2D / 3D / 4D:细胞噪声
NoiseCell2D、NoiseCell3D、NoiseCell4D提供 Cellular/Worley/Voronoi 噪声,支持:
- 锐利或平滑边缘渲染,或随机平色填充;
- 平滑地在 XY 平面滚动,或沿 Z / ZW 轴演进图案;
- 叠加八度(octave)细节;
- 渲染为纹理或法线贴图,供其他特效使用。
4.3 NoiseSimplex2D / 3D:单纯形噪声
NoiseSimplex2D、NoiseSimplex3D提供单纯形噪声(Perlin 噪声的继任者),支持:
- 用梯度流(gradient flow)让噪声动画平滑循环;
- 叠加八度细节;
- 施加湍流(turbulence)与输出塑形,实现多种效果;
- 同样支持渲染为纹理或法线贴图。
配合Math.Hash、Math.HashCell、Math.HashSimplex(见下文第六节)可在 CPU 端生成同类哈希/噪声场。
五、Tint 系统重构:tintMode 取代 tintFill
RC7 对 Tint 体系做了破坏性重构,这是从 Phaser 3 迁移时最需要注意的变更之一(详见 src/gameobjects/components/Tint.js 与 src/renderer/TintModes.js):
tint与setTint()现在纯粹影响颜色设置。旧版本中它们会静默关闭填充(fill)模式;tintFill与setTintFill()被移除;- 新增属性
tintMode与方法setTintMode()负责设置着色填充模式; Phaser.TintModes枚举全部合法模式(仅 WebGL 生效):
| 模式 | 值 | 说明 |
|---|---|---|
MULTIPLY | 0 | 乘法着色(默认),着色色与纹理色相乘 |
FILL | 1 | 填充着色,着色色替换纹理色但尊重纹理 alpha(可用于受击闪白) |
ADD | 2 | 加法着色,着色色加到纹理色上,尊重 alpha |
SCREEN | 4 | 提亮纹理暗部 |
OVERLAY | 5 | 提亮亮部、压暗暗部 |
HARD_LIGHT | 6 | 类似 OVERLAY,但着色色与纹理色对调 |
- FILL 模式现在能正确处理部分 alpha;BitmapText 着色也恢复正常;
- 迁移提示:
foo.setTintFill(color)改为foo.setTint(color).setTintMode(Phaser.TintModes.FILL)(旧方法在调用时会打印迁移错误提示,见 src/gameobjects/components/Tint.js)。
六、Math 哈希家族:CPU 端的噪声基元
RC7 在 src/math 新增三个哈希工具,与 Noise 游戏对象互为表里:
Math.Hash:对 1/2/3/4 维输入做快速哈希,支持三角函数或 PCG 方法;Math.HashCell:把哈希结果用于 Worley 噪声场,产生连续但块状(lumpy)的场;Math.HashSimplex:基于单纯形噪声实现的哈希,产生连续平滑的场。
七、滤镜家族扩张与回归
RC7 大幅扩充了 src/filters 目录:
CombineColorMatrix:在图像之间重混 alpha 及其他通道;GradientMap:用渐变与图像自身亮度重新着色;Key:移除或隔离指定颜色(键控色);ImageLight:基于图像的光照(image-based lighting),一种柔和、高真实感的照明方式;PanoramaBlur:为ImageLight预处理图像;NormalTools:法线贴图处理工具;Quantize:减色与抖动;Vignette(从 Phaser 3 回归):现在可设置可配置的边框颜色而非擦除 alpha,并支持有限的混合模式;Wipe(从 Phaser 3 回归):现在可设置被擦除区域显示的纹理,并提供方向性揭示/擦除效果的辅助函数。
八、纹理系统:setSource 家族与类型整理
Texture#setSource:更新纹理的源。注意:源会更新,但派生值(如对象尺寸)不会——建议在尺寸相同的纹理间切换,以免出现意外的变换(src/textures);Texture#setDataSource:原本已存在,本次改造得更像setSource一样好用;TextureManager#addFlatColor:创建自定义颜色、alpha、宽高的平色纹理,适合作为尚未加载的纹理的临时替身;TextureSource#updateSource:直接切换源;- 新增
Phaser.Types.Textures.TextureSource与TextureSourceElement类型,简化日益增多的纹理源管理。
九、RC7 修复项盘点
TimeStep#stepLimitFPS:丢弃更少的帧,在目标帧率下运行更流畅。FPSConfig#limit文档明确:仅在将游戏人为降速到低于显示器刷新率时才需要帧率限制(感谢 @Flow、@Antriel 的讨论);Shape:修复了虽带光照组件却不响应光照的问题;SpriteGPULayer:修复创建时间被 0 干扰的问题;- 混合模式泄漏:修复
Container内混合模式泄漏到兄弟节点的问题; ParseXMLBitmapFont:修复纹理偏移;DynamicTexture:修复初始为 2 的幂分辨率、后被缩放到非 2 的幂时变黑的问题。现在任何 WebGL 纹理缩放,2 的幂用REPEAT环绕、非 2 的幂用CLAMP_TO_EDGE;TextureManager.addUint8Array:修复预乘 alpha 与 flipY 的错误。
十、从 Phaser 3 迁移到 RC7 的要点清单
- Tint 填充:
setTintFill(color)→setTint(color).setTintMode(Phaser.TintModes.FILL); - 若要 Phaser 3 式 Bloom(辉光强度会压暗而非混合),在
AddEffectBloom中设置blendAmount: 0.5、blurQuality: 1,再关闭threshold并给parallelFilters.bottom添加乘法混合(详见 src/actions/AddEffectBloom.js 的模拟示例); - 纹理切换务必保持尺寸一致,或主动检查派生尺寸;
- 帧率限制只在人为降速时使用;
Vignette/Wipe的行为已升级,参数含义有变化,重新阅读文档后再用。
结语
RC7 是 Phaser 4 渲染能力的一次集中释放:Actions 让 Bloom、Shine、蒙版这些"高级感"效果成为一行代码的日常操作;Gradient与Noise系列把程序化视觉从"写 GLSL"降维到"配参数";ColorBand/ColorRamp的 GPU 编码设计为复杂色带提供了高性能采样路径;Tint 重构则让着色模式语义清晰、可组合。若需追根溯源,建议对照阅读 src/actions、src/display/ColorBand.js、src/display/ColorRamp.js、src/gameobjects/gradient/Gradient.js、src/gameobjects/noise 与 src/filters,并在 tests 中查找对应测试用例验证行为。
【免费下载链接】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),仅供参考