关于 render-textures
Phaser 4 纹理绘制技能,面向需要在离屏纹理上合成、生成或采样游戏画面的开发者。内容涵盖 RenderTexture 与 DynamicTexture 的差异、命令缓冲区及常见图案。
主要功能
- 01RenderTexture 与 DynamicTexture 用法
- 02命令缓冲区渲染
- 03纹理绘制、填充与擦除
- 04纹理快照与像素读取
- 05程序化纹理和小地图模式
适用场景
- 01将多个游戏对象合成为纹理
- 02生成平铺或星空等程序化纹理
- 03制作固定在摄像机上的小地图
- 04读取纹理区域或像素数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ phaserjs/ phaser --skill render-textures安装后在 Claude Code 中输入/render-textures确认已加载。
详细介绍
渲染纹理与动态纹理
在 Phaser 4 中将游戏对象绘制到离屏纹理 -- RenderTexture 游戏对象、用于共享纹理的 DynamicTexture、Stamp 辅助工具、命令缓冲区渲染、快照、程序化生成以及小地图模式。
关键源码路径: src/gameobjects/rendertexture/、src/textures/DynamicTexture.js、src/gameobjects/stamp/、src/textures/typedefs/StampConfig.js、src/textures/typedefs/CaptureConfig.js
相关技能: ../sprites-and-images/SKILL.md、../loading-assets/SKILL.md、../cameras/SKILL.md
快速开始
// In a Scene's create() method:
// 1. RenderTexture -- a visible game object with its own DynamicTexture
const rt = this.add.renderTexture(400, 300, 256, 256);
rt.draw('player', 128, 128); // draw a texture by key at center
rt.fill(0x222244, 0.5); // semi-transparent fill
rt.render(); // flush the command buffer
// 2. DynamicTexture -- a shared texture in the Texture Manager
const dt = this.textures.addDynamicTexture('composite', 512, 512);
dt.stamp('coin', null, 64, 64, { scale: 2, angle: 45 });
dt.render();
this.add.image(400, 300, 'composite'); // any game object can use it
// 3. Stamp game object -- lightweight Image that ignores camera scroll
const hud = this.add.stamp(10, 10, 'heart');
核心概念
RenderTexture 与 DynamicTexture
Phaser 4 将纹理绘制拆分为两个层级:
| RenderTexture | DynamicTexture | |
|---|---|---|
| 它是什么 | Image 游戏对象 + 自动创建的 DynamicTexture | Texture Manager 中的纹理 |
| 创建方式 | this.add.renderTexture(x, y, w, h) | this.textures.addDynamicTexture(key, w, h) |
| 自身是否可见 | 是(它继承自 Image) | 否(必须赋值给某个游戏对象) |
| 可否跨对象共享 | 可通过 saveTexture(key) 实现 | 可以,通过 key |
| 可否跨场景使用 | 否(属于单个 Scene) | 可以(纹理是全局的) |
| 是否有位置/缩放/透明度 | 是(具备所有 Image 组件) | 否(它是 Texture,不是 GameObject) |
何时使用哪一个:
- 当你需要一个可绘制的单一可见表面时(绘画画布、拖尾效果、合成精灵),使用 RenderTexture。
- 当许多游戏对象共享同一张生成纹理时,或者你需要为遮罩/着色器提供纹理,或者需要跨场景访问时,使用 DynamicTexture。
RenderTexture 是一个轻量代理。诸如 draw()、stamp()、fill()、clear()、erase()、snapshot() 之类的方法都会委托给它底层的 this.texture(一个 DynamicTexture)。
原点说明: RenderTexture 继承自 Image,因此其原点默认为 (0.5, 0.5)。如果你想要左上角定位(常见于全屏或小地图 RT),请调用 rt.setOrigin(0, 0)。
命令缓冲区(v4 架构)
在 Phaser 4 中,绘制调用(draw、stamp、fill、clear、erase、repeat、capture)不会立即执行。它们会把命令推入一个 commandBuffer 数组。你必须调用 .render() 来刷新并执行缓冲区。
rt.clear();
rt.fill(0x000000);
rt.draw(sprite, 128, 128);
rt.render(); // REQUIRED -- nothing appears without this
对于 RenderTexture 游戏对象,renderMode 属性控制自动渲染:
| 模式 | 行为 |
|---|---|
'render'(默认) | 每个 tick 将纹理内容绘制到帧上。内容变化时你需手动调用 render()。 |
'redraw' | 每帧自动调用 render(),但不会显示自身。适用于被其他对象复用的纹理。 |
'all' | 每帧调用 render(),并且将自身绘制到帧上。 |
rt.setRenderMode('all'); // auto-render + display every frame
rt.setRenderMode('all', true); // same, plus preserve the command buffer
保留模式
默认情况下,命令缓冲区在 render() 后会被清空。调用 preserve(true) 可在多次渲染之间保留命令,从而让相同的绘制每帧重放:
rt.preserve(true);
rt.clear();
rt.draw(sprite);
// On every subsequent render(), clear + draw will repeat
Stamp 游戏对象
Stamp(this.add.stamp(x, y, texture, frame))是一个轻量级 Image 子类,在渲染时会忽略相机滚动和变换。它在 DynamicTexture 内部被用于绘制操作,也可用于 HUD 元素。它继承了 Image,并带有自定义渲染节点(DefaultStampNodes)。
stamp() 方法与 Stamp 游戏对象的区别
它们是不同的东西:
rt.stamp(key, frame, x, y, config)-- RenderTexture/DynamicTexture 上的一个方法,用于将纹理帧绘制到表面,并支持变换选项(alpha、tint、angle、scale、origin、blendMode)。this.add.stamp(x, y, texture, frame)-- 一个工厂方法,用于创建一个 Stamp 游戏对象并添加到 Scene 显示列表中。
常见模式
绘制精灵和游戏对象
const rt = this.add.renderTexture(0, 0, 800, 600);
// Single game object at an offset
rt.draw(sprite, 100, 100);
// Array of objects
rt.draw([sprite1, sprite2, sprite3]);
// Group or Container (only visible children are drawn)
rt.draw(enemyGroup);
rt.draw(myContainer, 50, 50); // offset added to children positions
// Entire Scene display list
rt.draw(this.children);
// Texture by string key
rt.draw('explosion', 200, 200);
// Don't forget to flush
rt.render();
draw() 方法接受:可渲染的游戏对象、Group、Container、Display List、其他 RenderTexture/DynamicTexture、纹理帧、纹理键字符串,或上述任意类型的数组。
注意:draw() 上的 alpha 和 tint 参数仅适用于纹理帧/字符串。游戏对象在绘制时会使用自身的 alpha 和 tint。
使用 Config 盖章纹理
stamp() 方法在完全变换控制下绘制纹理帧。该帧默认以 x/y 位置为中心(原点 0.5)。
rt.stamp('bullet', null, 100, 100, {
alpha: 0.8,
tint: 0xff0000,
angle: 45, // degrees (takes precedence over rotation)
scale: 2, // uniform scale
scaleX: 1.5, // overrides scale for X
scaleY: 0.5, // overrides scale for Y
originX: 0, // top-left origin
originY: 0,
blendMode: 0
});
rt.render();
Capture —— 使用覆盖项绘制(v4)
capture() 方法在临时属性覆盖下绘制游戏对象,之后恢复原始属性:
rt.capture(player, {
x: 64,
y: 64,
scale: 0.5,
alpha: 0.8,
rotation: Math.PI / 4,
transform: 'world', // 'local', 'world', or a TransformMatrix
camera: someCamera // optional camera override
});
rt.render();
这适用于在不修改对象本身的情况下,以不同的位置/缩放绘制对象。
填充和清除
// Fill entire texture with color
rt.fill(0xff0000); // solid red
rt.fill(0x000000, 0.5); // semi-transparent black
// Fill a region
rt.fill(0x00ff00, 1, 10, 10, 100, 50); // green rect at (10,10) size 100x50
// Clear everything (transparent)
rt.clear();
// Clear a region
rt.clear(10, 10, 100, 50);
rt.render();
擦除
擦除使用 ERASE 混合模式在纹理中切出空洞:
rt.fill(0xffffff); // white background
rt.erase(circleSprite, 100, 100); // punch a hole shaped like the sprite
rt.render();
重复 / 平铺纹理
// Fill the entire RenderTexture with a tiled pattern
rt.repeat('grass', null); // tile the whole surface
rt.repeat('brick', null, 0, 0, 256, 128); // tile a specific region
rt.repeat('tile', 'frame2', 0, 0, 512, 512, {
tileScaleX: 2,
tileScaleY: 2,
tilePositionX: 16,
alpha: 0.8
});
rt.render();
快照(像素捕获)
快照从帧缓冲读取像素数据。它们开销大且会阻塞——请谨慎使用。
// Full texture snapshot -- callback receives an HTMLImageElement
rt.snapshot(function (image) {
document.body.appendChild(image); // or use as texture source
});
// Area snapshot
rt.snapshotArea(0, 0, 128, 128, function (image) {
// image is 128x128 region from top-left
}, 'image/jpeg', 0.8);
// Single pixel -- callback receives a Phaser.Display.Color
rt.snapshotPixel(64, 64, function (color) {
console.log(color.r, color.g, color.b, color.a);
});
用作其他对象的纹理源
const rt = this.add.renderTexture(0, 0, 256, 256);
rt.draw(complexScene);
rt.render();
// Register in the Texture Manager under a key
rt.saveTexture('composited');
// Now any game object can use it
this.add.image(400, 300, 'composited');
this.add.sprite(100, 100, 'composited');
// Updates to the RenderTexture automatically reflect on all users
对于 DynamicTexture,键在创建时设置:
const dt = this.textures.addDynamicTexture('terrain', 1024, 1024);
dt.repeat('grass', null);
dt.render();
this.add.image(512, 512, 'terrain'); // already keyed
程序化生成
const dt = this.textures.addDynamicTexture('starfield', 800, 600);
dt.fill(0x000011);
for (let i = 0; i < 200; i++) {
const x = Phaser.Math.Between(0, 800);
const y = Phaser.Math.Between(0, 600);
const brightness = Phaser.Math.FloatBetween(0.3, 1);
dt.stamp('star', null, x, y, { alpha: brightness, scale: Phaser.Math.FloatBetween(0.5, 1.5) });
}
dt.render();
this.add.image(400, 300, 'starfield');
小地图模式
create() {
// Small RenderTexture as minimap
this.minimap = this.add.renderTexture(700, 50, 150, 100);
this.minimap.setScrollFactor(0); // fixed to camera
this.minimap.setRenderMode('all'); // auto-render every frame
this.minimap.preserve(true);
}
// In update or a callback:
this.minimap.clear();
this.minimap.fill(0x111111);
// Draw scaled-down versions of world objects
this.minimap.capture(player, { x: px * 0.1, y: py * 0.1, scale: 0.1 });
// render() is automatic in 'all' mode
命令缓冲区中的回调
在绘制命令之间插入逻辑,这些逻辑会在 render() 期间执行:
rt.clear();
rt.draw(background);
rt.callback(() => {
// Runs during render, after background is drawn
sprite.setTint(0xff0000);
});
rt.draw(sprite);
rt.callback(() => {
sprite.setTint(0xffffff); // restore after drawing
});
rt.render();
调整大小
// Resize erases all content and recreates the framebuffer
rt.resize(512, 512);
// Optional: disable force-even rounding
rt.resize(513, 513, false);
内部摄像机
RenderTexture 和 DynamicTexture 都有一个 .camera 属性,用于控制绘制时游戏对象的定位方式。滚动、缩放和旋转此摄像机以变换绘制的内容。注意:stamp() 会忽略摄像机;只有 draw() 和游戏对象渲染会遵循它。
rt.camera.setScroll(100, 50);
rt.camera.setZoom(2);
rt.draw(sprite); // sprite drawn with camera transform applied
rt.render();
API 快速参考
RenderTexture(继承自 Image)
| 方法 | 签名 | 描述 |
|---|---|---|
draw | (entries, x?, y?, alpha?, tint?) | 绘制游戏对象、纹理、组等 |
capture | (entry, config) | 使用临时属性覆盖进行绘制 |
stamp | (key, frame?, x?, y?, config?) | 使用变换盖章纹理帧 |
erase | (entries, x?, y?) | 使用 ERASE 混合模式绘制 |
fill | (rgb, alpha?, x?, y?, w?, h?) | 用颜色填充 |
clear | (x?, y?, w?, h?) | 清除为透明 |
repeat | (key, frame?, x?, y?, w?, h?, config?) | 将纹理平铺为填充图案 |
render | () | 刷新命令缓冲区 |
preserve | (bool) | 在渲染之间保留命令缓冲区 |
callback | (fn) | 将回调插入命令缓冲区 |
resize | (w, h?, forceEven?) | 调整大小(擦除内容) |
saveTexture | (key) | 在 Texture Manager 中注册 |
setRenderMode | (mode, preserve?) | 设置 'render'、'redraw' 或 'all' |
snapshot | (callback, type?, quality?) | 完整快照到 Image |
snapshotArea | (x, y, w, h, callback, type?, quality?) | 区域快照 |
snapshotPixel | (x, y, callback) | 单个像素到 Color |
DynamicTexture(继承自 Texture)
与 RenderTexture 相同的绘制方法(draw、stamp、erase、fill、clear、repeat、capture、render、preserve、callback、snapshot、snapshotArea、snapshotPixel),另外还有:
| 方法/属性 | 描述 |
|---|---|
setSize(w, h?, forceEven?) | 调整纹理大小 |
camera | 用于绘制定位的内部摄像机 |
commandBuffer | 待处理绘制命令的数组 |
drawingContext | 带帧缓冲的 WebGL DrawingContext |
getWebGLTexture() | 返回底层 WebGLTextureWrapper |
StampConfig(用于 stamp() 配置参数)
| 属性 | 默认值 | 描述 |
|---|---|---|
alpha | 1 | Alpha 值 |
tint | 0xffffff | 色调(仅 WebGL) |
angle | 0 | 角度(非零时覆盖 rotation) |
rotation | 0 | 弧度 |
scale | 1 | 统一缩放 |
scaleX / scaleY | 1 | 各轴缩放(覆盖 scale) |
originX / originY | 0.5 | 原点 |
blendMode | 0 | 混合模式 |
CaptureConfig(用于 capture() 配置参数)
| 属性 | 描述 |
|---|---|
transform | 'local'、'world' 或 TransformMatrix |
camera | 用于渲染的相机覆盖 |
x、y、alpha、tint、angle、rotation | 临时覆盖游戏对象属性 |
scale、scaleX、scaleY | 缩放覆盖 |
originX、originY、blendMode | 其他覆盖 |
工厂方法
this.add.renderTexture(x, y, width?, height?) // default 32x32
this.add.stamp(x, y, texture, frame?)
this.textures.addDynamicTexture(key, width?, height?, forceEven?) // default 256x256
注意事项
-
必须调用
render()。 在 Phaser 4 中,绘制方法会缓冲命令。在调用render()之前不会显示任何内容(除非使用renderMode: 'all'或'redraw')。 -
不能绘制到自身。 DynamicTexture/RenderTexture 会静默跳过引用自身的条目。
-
渲染后命令缓冲区会清空。 如果你需要相同的命令每帧重放,请在绘制前调用
preserve(true)。 -
stamp()忽略内部相机。 只有通过draw()或capture()绘制的游戏对象才会遵循.camera属性。纹理图章按绝对位置定位。 -
默认尺寸不同。 RenderTexture 默认为 32x32。DynamicTexture 默认为 256x256。
-
forceEven会将尺寸向上取整。 默认情况下,为保证渲染质量,宽度/高度会取整为偶数。如果你需要精确的奇数尺寸,请将false作为最后一个参数传入。 -
快照开销很大。 它们使用
readPixels(WebGL),会阻塞 GPU 管线。避免逐帧快照。snapshotPixel比完整的snapshot更廉价。 -
WebGL1 的帧缓冲没有抗锯齿。 绘制到 RenderTexture 的形状和 Graphics 可能会有锯齿边缘。请改用预渲染的 sprite 纹理。
-
resize()会擦除内容。 调整大小会销毁并重新创建帧缓冲。 -
saveTexture是重命名,不是复制。 调用saveTexture(key)会在 Texture Manager 中以该键分配 DynamicTexture。用不同的键再次调用会将其重命名。如果不先保存就销毁 RenderTexture,纹理会随之销毁。 -
draw()的 alpha/tint 参数仅影响 Texture Frame。 绘制游戏对象时,它们使用自己的 alpha 和 tint 值。draw()上的alpha和tint参数仅在绘制纹理字符串或 Frame 实例时生效。 -
WebGL 上下文丢失。 DynamicTexture 的内容会在上下文丢失时丢失。请监听
restorewebgl事件以重新绘制。 -
Group/Container:x、y 偏移是叠加的。 当使用
rt.draw(group, x, y)绘制 Group 或 Container 时,x/y 偏移会加到每个子项的位置上。位于 (100, 50) 的子项在以偏移 (10, 10) 绘制后,会出现在纹理中的 (110, 60)。
源文件映射
| 文件 | 描述 |
|---|---|
src/gameobjects/rendertexture/RenderTexture.js | RenderTexture 游戏对象(继承 Image,代理到 DynamicTexture) |
src/gameobjects/rendertexture/RenderTextureFactory.js | this.add.renderTexture() 工厂注册 |
src/gameobjects/rendertexture/RenderTextureRender.js | RenderTexture 的 WebGL/Canvas 渲染函数 |
src/gameobjects/rendertexture/RenderTextureRenderModes.js | 枚举:RENDER、REDRAW、ALL |
src/textures/DynamicTexture.js | 核心 DynamicTexture 类(命令缓冲区、绘制、快照) |
src/textures/DynamicTextureCommands.js | 命令常量(CLEAR、FILL、STAMP、DRAW、ERASE 等) |
src/textures/typedefs/StampConfig.js | 用于 stamp() 的 StampConfig 类型定义 |
src/textures/typedefs/CaptureConfig.js | 用于 capture() 的 CaptureConfig 类型定义 |
src/gameobjects/stamp/Stamp.js | Stamp 游戏对象(轻量 Image,忽略相机滚动) |
src/gameobjects/stamp/StampFactory.js | this.add.stamp() 工厂注册 |