Textures - samme/phaser3-faq Wiki

Textures have a key, a first frame name, a map of frames, one or more source images, and zero or more data source images (normal maps). There are two texture classes, Texture and CanvasTexture.

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).

List texture keys in the manager

const keys = this.textures.getTextureKeys(); // → ['mummy', 'bat', 'torch', …]

Get a texture from the manager

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;

List the frame names for a texture

const frameNames = this.textures.get('mummy').getFrameNames(); // → [0, 1, 2, …]

Get a frame from a texture

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');

Set a texture's filter mode

// 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);

Working from a game object

You can use the same methods on a game object's texture and frame.

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); 

Textures from loaded images

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 from 0, plus __BASE.
  • load.atlas() 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.

Textures from complete images

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 use a different frame set:

this.textures.addImage('nileCopy', this.textures.get('nile').getSourceImage());

Adding frames

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:

const aspFrame = this.textures.cloneFrame('asp', 0);
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 image into a spritesheet:

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 Render Texture (see below).

Canvas Texture

A Canvas Texture is the only way to do per-pixel modifications.

You can create a blank canvas texture with createCanvas():

const texture = this.textures.createCanvas('key', width, height);

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);

You can use the Canvas 2D API 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();

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().

Render Texture

A Render Texture is actually a game object (like Sprite) holding a Canvas Texture and rendering with a FrameBuffer. It has a canvas property but you should leave that alone.

If you want to use the texture separately from the game object, create the Render Texture off the scene display list:

const rt = this.make.renderTexture({ width: 100, height: 100 }, false);

and then save the texture to access it by key:

const texture = rt.saveTexture('bubbles');

then you can use the texture by the saved key:

this.add.tileSprite(0, 0, 1000, 1000, 'bubbles');

You should remove saved textures from the manager later if you don't need them any longer.

You can also read the texture directly off the game object, without saving it:

this.add.tileSprite(0, 0, 1000, 1000, rt.texture);

Render Texture drawing is a lot more sophisticated than Canvas Texture. You can draw one or multiple game objects, including all of their transforms.

Use the drawing methods of the Render Texture itself, not its texture:

rt.draw(gameObject);
rt.drawFrame(textureKey, frameName, x, y, alpha, tint);

// WRONG
rt.texture.draw(gameObject);

rt.erase(gameObject);
rt.erase(textureFrame);
rt.erase(textureKey);

If you're drawing a lot of frames at once you should batch them:

rt.beginDraw();
rt.batchDraw(/*…*/); // etc.
rt.batchDrawFrame(/*…*/); // etc.
rt.endDraw();

To erase a batch finish with endDraw(true) instead.