-
Notifications
You must be signed in to change notification settings - Fork 4
Textures
Textures have a key, a first frame name, a map of frames, one or more source images (canvas, image, or video), and zero or more data source images (normal maps). There are three texture classes, CanvasTexture, DynamicTexture, and Texture.
The maximum texture dimensions depend on the device; you can check renderer.getMaxTextureSize()
. 2048px for mobile and 4096px for desktop should be safe.
Frames are rectangular areas on a texture. Frames have a name, position, several dimensions (realWidth
and realHeight
are most important), and an optional custom pivot point. The docs call frame names "names" (for atlas textures) and "indexes" (for spritesheet textures) but they are all the same thing. All textures have a special frame, named __BASE
, that represents the entire texture.
Textures are stored in the Texture Manager, this.textures
in a scene or game.textures
. Textured game objects hold their current texture and frame in their texture
and frame
properties.
There are three built-in textures: __DEFAULT
(32 × 32 transparent), __MISSING
(32 × 32 green slashed box), and __WHITE
(4 × 4 white).
const keys = this.textures.getTextureKeys(); // → ['mummy', 'bat', 'torch', …]
textures.get()
always returns a texture; it will be the __MISSING
texture if no such key exists. So you should use textures.exists()
first.
const texture = this.textures.exists('mummy') ? this.textures.get('mummy') : null;
const frameNames = this.textures.get('mummy').getFrameNames(); // → [0, 1, 2, …]
for (const textureKey of this.textures.getTextureKeys()) {
console.info(textureKey, this.textures.get(textureKey).getFrameNames(true));
}
const mummyFrame1 = this.textures.getFrame('mummy', 1);
// OR
const mummyFrame1 = this.textures.get('mummy').get(1);
A texture itself has no dimensions, technically; for those you want to read from the base frame:
const { realWidth, realHeight } = this.textures.getFrame('mummy', '__BASE');
// Nearest-neighbor filter (pixelated)
this.textures.get('mummy').setFilterMode(Phaser.Textures.FilterMode.NEAREST);
// Linear filter (antialiased)
this.textures.get('mummy').setFilterMode(Phaser.Textures.FilterMode.LINEAR);
A game object's texture
and frame
hold its current texture and frame, so you can access them there instead of from the texture manager. Just remember that you're working with shared objects.
const mummy = this.add.sprite(0, 0, 'mummy', 1);
console.log(mummy.texture.key); // → 'mummy'
console.log(mummy.frame.name); // → 1
const mummyFrame1 = mummy.texture.get(1);
Usually you won't be creating textures directly. Phaser creates textures for you when you load images.
-
load.image()
creates a texture with the single frame__BASE
. -
load.spritesheet()
creates a texture with frames named as integers starting from0
, plus__BASE
. -
load.atlas()
orload.unityAtlas()
creates a texture with frames named in the atlas data, plus__BASE
. -
load.multiatlas()
creates the same, with multiple source images
In Phaser terms a "spritesheet" has uniform cells in rows or columns and an "atlas" has frames in any size and position. Phaser can load atlases created by Texture Packer (any "Phaser 3" format) or Unity.
Phaser can use any image format that the browser can display. SVGs are rasterized (by the browser) when a texture is created. Phaser v3.60 supports WebGL compressed textures.
If you already have a complete image or canvas somehow, you can add it to the Texture Manager directly using methods such as addImage()
, addSpriteSheet()
, addAtlas()
. These methods are very similar to the corresponding load methods, but they take a sourceImage
argument (the image or canvas) instead of an URL.
You can make a second texture from the same source this way, maybe if you wanted to create a different frame set:
this.textures.addImage('mummyCopy', this.textures.get('mummy').getSourceImage());
for (const frame of Object.values(this.textures.get('sprites').frames)) {
if (frame.name === '__BASE') {
continue;
}
frame.customPivot = true;
frame.pivotX = 0.5;
frame.pivotY = 1;
console.log(frame.texture.key, frame.name, frame.pivotX, frame.pivotY);
}
texture.add(frameName, sourceIndex, x, y, width, height);
You can use numeric or string frame names. sourceIndex
is 0
for single-source textures.
Frames can be cloned but you then have to add the new frame object manually:
// Clone frame 0 of texture "asp".
const aspFrame = this.textures.cloneFrame('asp', 0);
// Add it as frame 0 of the "bat" texture.
const batTexture = this.textures.get('bat');
batTexture.frames[aspFrame.name] = aspFrame;
batTexture.frameTotal += 1;
You can add frames to any texture. Here you can "convert" a single-frame texture into a multi-frame spritesheet texture:
this.load.image('example', 'example.png');
this.load.once('filecomplete-image-example', () => {
const texture = this.textures.get('image');
texture.firstFrame = 0;
texture.add(0 /* … */);
texture.add(1 /* … */);
texture.add(2 /* … */);
texture.getFrameNames(); // -> [0, 1, 2]
});
In practice you usually add frames to create a multi-frame Canvas Texture or Dynamic Texture (see below).
A Canvas Texture has a canvas with a 2d rendering context as its source. You can use any of the Canvas API on it. You can draw texture frames on it, but not game objects (cf. Dynamic Texture).
You can create a blank canvas texture with createCanvas()
:
const texture = this.textures.createCanvas('key', width, height);
Or use an existing canvas:
const texture = this.textures.addCanvas('key', canvas);
Use drawFrame()
to draw another texture frame onto the Canvas Texture:
texture.drawFrame('mummy', 1, x, y);
or draw()
if you have a source image (unusual):
texture.draw(sourceImage, x, y);
If you work on the canvas context directly, refresh the texture when finished:
const ctx = texture.getContext();
// CanvasTexture has its own `width` and `height`.
// You could also read these from the base frame, as with the Texture class.
const { width, height } = texture;
ctx.fillStyle = 'ghostwhite';
ctx.fillRect(0, 0, width, height);
texture.refresh();
refresh()
is required to update the texture for display in WebGL rendering mode. Don't call refresh()
after draw()
or drawFrame()
; it's already included.
If you need to use getPixel()
or getPixels()
after drawing, call update()
instead of refresh()
.
A Dynamic Texture is a special texture that allows you to draw textures, frames and most kind of Game Objects directly to it.
A Render Texture is essentially an Image holding a Dynamic Texture.