The primary means of animation in Phaser is by using 'frame' based animations. As mentioned previously, Phaser maintains a Texture class, which contains as many Frames as may exist on that Texture. The Animation systen allows you to play a sequence of these Frames, one after the other, at a given frame rate. This is how you create the illusion of animation on Sprites in your game. To achieve this, you often see texture image files divided into a 'grid' of frames, where each frame is a different animation frame. This is known as a Sprite Sheet or Texture Atlas.
Animations are created via the Animation Manager. Each Scene has its own instance of the Animation Manager. You can create as many animations as you like, and each animation can have as many frames as you like. You can also create multiple animations that all use the same frames, if you wish. For example, you could have a 'walk' animation that uses frames 1 to 4, and a 'run' animation that uses frames 1 to 8. Both animations would use overlapping frames, but play them at different speeds.
Not all Game Objects can be animated. The main one you'll use is the Sprite Game Object. This carries its own Animation State component with it, allowing you to create and play animations directly on a Sprite instance.
Animations can be either global or local. A global animation is one that is created via the Animation Manager and is available to all Game Objects in your game. A local animation is one that is created directly on a Game Object, such as a Sprite. Local animations are only available to that Game Object and cannot be used by any other Game Object.
It's worth mentioning that animation can also be achieved by tweening objects, if you just need a blend of motion + subtle changes (like scale or alpha), and that Phaser 3 also has a plugin available for Spine animations, which is a bone-based animation software package published by Esoteric Software.
Animation manager
Add animation
var animationConfig = {
key: "",
frames: [],
sortFrames: true,
defaultTextureKey: null,
skipMissedFrames: true,
randomFrame: false,
// time
delay: 0,
duration: null,
frameRate: null,
timeScale: 1,
// repeat
repeat: 0, // set to (-1) to repeat forever
repeatDelay: 0,
yoyo: false,
// visible
showBeforeDelay: false,
showOnStart: false,
hideOnComplete: false,
};
this.anims.create(animationConfig);
-
key
: Unique key of this animation data -
frames
: An array of{key, frame}
-
Properties
{ key: '', frame: '', // string, or number duration: 0 }
duration
: The duration, in ms, of this frame of the animation.
-
A string : Texture key.
-
Every frame in the atlas
this.anims.generateFrameNames(key);
-
Frame sequence indexing from start to end
var config = ; this.anims.generateFrameNames(key, { prefix: '', start: 0, end: 0, suffix: '', zeroPad: 0, // outputArray: [], // Append frames into this array });
prefix + Pad(i, zeroPad, '0', 1) + suffix
, i: start ~ end
-
Custom frame sequence
var config = ; this.anims.generateFrameNames(key, { prefix: '', suffix: '', zeroPad: 0, frames: [ ... ] // outputArray: [], // Append frames into this array });
prefix + Pad(frames[i], zeroPad, '0', 1) + suffix
-
-
sortFrames
: Frame names numerically sorted. Default value istrue
. -
defaultTextureKey
: The key of the texture all frames of the animation will use. Can be overridden on a per frame basis. -
skipMissedFrames
: Skip frames if the time lags, or always advanced anyway? Default value istrue
. -
randomFrame
: Start playback of this animation from a randomly selected frame? Default value isfalse
. -
delay
: Delay before starting playback. Value given in milliseconds. -
duration
: How long the animation should play for in milliseconds. If not given its derived fromframeRate
. -
frameRate
: The frame rate of playback in frames per second. Default value is24
. -
timeScale
: The time scale to be applied to playback of this animation. Default value is1
. -
repeat
: Number of times to repeat the animation. Default value is0
.-1
: Infinity
-
repeatDelay
: Delay before the animation repeats. Value given in milliseconds. -
yoyo
: Should the animation yoyo? (reverse back down to the start) before repeating? Default value isfalse
. -
showBeforeDelay
: If this animation has a delay, should it show the first frame immediately (true
), or only after the delay (false
) -
showOnStart
: Shouldsprite.visible = true
when the animation starts to play? This happens after any delay, if set. Default value isfalse
. -
hideOnComplete
: Should sprite.visible = false when the animation finishes? Default value isfalse
.
Use every frame in a texture
// Create animation 'mummyWalk' from every frame in texture 'mummy':
this.anims.create({
key: "mummyWalk",
frames: "mummy",
});
Choosing texture frames
You will usually need to know the texture frame names. To get the frame names:
console.assert(this.texture.exists("mummy"));
console.log(this.textures.get("mummy").getFrameNames());
// Create animation 'mummyWalk' from frames 0, 1, 2 of texture 'mummy':
this.anims.create({
key: "mummyWalk",
frames: [
{ key: "mummy", frame: 0 },
{ key: "mummy", frame: 1 },
{ key: "mummy", frame: 2 },
],
});
You can of course create animations using any technique.
// We have 3 textures with identical frame patterns.
const textureKeys = ["giant", "elf", "goblin"];
// We will create 9 animations from 3 sequences.
const anims = {
idle: [0],
walk: [1, 2],
attack: [3, 4],
};
for (const textureKey of textureKeys) {
for (const animName of anims) {
this.anims.create({
// 'giant:idle', 'giant:walk', etc.
key: `${textureKey}:${animName}`,
frames: anims[animName],
});
}
}
Frame timing
You can give either frameRate
(default 24 fps) or a duration
for the whole animation. The frame duration is calculated as 1000 / frameRate
or duration / frames.length
.
If you set per-frame durations, these are added to the calculated frame durations. So if you want to set only frame durations, use an animation duration of 1ms.
this.anims.create({
key: "spikes",
repeat: -1,
defaultTextureKey: "spikes",
duration: 1, // 1 ms, close enough to 0
frames: [
{ frame: 0, duration: 3000 },
{ frame: 1, duration: 250 },
{ frame: 2, duration: 250 },
{ frame: 3, duration: 3000 },
{ frame: 2, duration: 250 },
{ frame: 1, duration: 250 },
],
});
generateFrameNumbers() and generateFrameNames()
The helper methods generateFrameNumbers() and generateFrameNames() both select frame names from a texture according to a pattern and then generate an array of AnimationFrame objects that can be passed as the frames
property. generateFrameNumbers()
selects spritesheet-style frame names (indexes) and generateFrameNames()
selects atlas-style frame names. They never select frame names that don't exist in the texture.
For example,
this.anims.generateFrameNumbers("mummy", { frames: [0, 1, 2] });
or
this.anims.generateFrameNumbers("mummy", { start: 0, end: 2 });
would produce an array of the 3 frame configs that we wrote above.
The generateFrameNames()
config has all the options of generateFrameNumbers()
, plus prefix
, suffix
, and zeroPad
.
Log the output of these methods if you run into trouble.
Add from Aseprite
Aseprite is a powerful animation sprite editor and pixel art tool. Create one, or more animations from a loaded Aseprite JSON file.
this.anims.createFromAseprite(key);
// this.anims.createFromAseprite(key, tags, target);
key
: The key of the loaded Aseprite atlas.tags
:undefined
: Load all tags.- Array of string tag : Load these tags.
target
: Create the animations on this target Sprite.undefined
: Created globally in this Animation Manager. Default behavior.
Remove animation
this.anims.remove(key);
Mixing and delaying between two animations
-
Add
this.anims.addMix(animA, animB, delay);
animA
,animB
: String key of an animation, or an instance of animation.
-
Remove
this.anims.removeMix(animA, animB); // this.anims.removeMix(animA);
-
Get
var delay = this.anims.getMix(animA, animB);
-
Example of an animation mix for transitioning from one animation to another.
this.anims.create({ key: "animA" /* etc. */ }); this.anims.create({ key: "animB" /* etc. */ }); this.anims.addMix("animA", "animB", 200);
The delay is applied automatically if you play the second animation while the first is playing.
sprite.play("animA"); // Later: sprite.play("animB");
It's very similar to
if (sprite.anims.isPlaying && sprite.anims.getName() === "animA") { sprite.anims.playAfterDelay("animB", 200); }
Play animation
-
Play
this.anims.play(key, children);
-
Stagger play (delay play)
this.anims.staggerPlay(key, children, stagger, staggerFirst);
children
: An array of Game Objects to play the animation onstagger
: The amount of time, in milliseconds, to offset each play time bystaggerFirst
: Settrue
to apply delay on 1st child
-
Playing an animation when an event is triggered
sprite.on(event, function () { sprite.play(key); }
Example:
sprite.on('pointerdown', function () { sprite.play('smile'); }
-
Ignore playing an animation if it is already playing
sprite.play(key, ignoreIfPlaying);
ignoreIfPlaying
: Set totrue
to ignore restarting an animation.
Example:
sprite.play("run", true); // only plays the "run" animation if it is not already playing
-
Chaining animation
chain()
schedules an animation to play once the current one completes or stops. Repeated chaining adds to the end of the queue. If an animation is repeating, only stop()
will advance the queue. If you want a final stop, do
sprite.chain().stop();
Be careful of chaining too many animations by mistake.
function update() {
// Choose a reasonable maximum.
if (sprite.anims.nextAnimsQueue.length > 10) {
throw new Error("Too many chained animations");
}
}
Internally, the next chained animation is in nextAnim
and any additional ones are in nextAnimsQueue
.
-
Play animation after delay or repeat count
-
playAfterDelay()
sprite.playAfterDelay(key, delay);
key
: The string-based key of the animation to play.delay
: The delay, in milliseconds, to wait before playing the animation.
-
playAfterRepeat()
sprite.playAfterRepeat(key, repeatCount);
key
: The string-based key of the animation to play.repeatCount
: Optional argument that defaults to 1. Number of current animation repeats before next animation plays.
-
Pause all animations
this.anims.pauseAll();
Resume all animations
this.anims.resumeAll();
Global time scale
The global time scale of the Animation Manager. This scales the time delta between two frames, thus influencing the speed of time for the Animation Manager.
-
Get
var timeScale = this.anims.globalTimeScale;
-
Set
this.anims.globalTimeScale = timeScale;
Has animation
var hasAnim = this.anims.exists(key);
Export/load
-
Export JSON
var json = this.anims.toJSON();
-
Load from JSON
this.anims.fromJSON(json); // this.anims.fromJSON(json, clearCurrentAnimations);
-
Load JSON in preload stage
scene.load.json(key, url);
-
Load animation in preload stage
scene.load.animation(key, url);
-
Events
-
On add animation
this.anims.on("add", function (key, anim) {});
-
On remove animation
this.anims.on("remove", function (key, anim) {});
-
On pause all animations
this.anims.on("pauseall", function () {});
-
On resume all animations
this.anims.on("resumeall", function () {});
Animation object
var anim = this.anims.get(key);
Example:
const mummyWalkAnim = this.anims.get("mummyWalk");
Add frame
-
Append frames
anim.addFrame(frame);
frame
:this.anims.generateFrameNames(key, config)
-
Insert frames at index
anim.addFrameAt(index, frame);
frame
:this.anims.generateFrameNames(key, config)
Remove frame
-
Remove frame at
anim.removeFrameAt(index);
-
Remove frame
anim.removeFrame(frame);
Get frame
-
Has frame index
var HasFrameAt = anim.checkFrame(index);
-
Get frame at index
var frame = anim.getFrameAt(index);
Example:
const mummyWalkFrame1 = this.anims.get("mummyWalk").getFrameAt(1);
-
Get last frame
var frame = anim.getLastFrame();
Export
-
Export JSON
var json = anim.toJSON();
or
var jsonString = JSON.stringify(anim);
Common errors
TypeError: undefined is not an object (evaluating 'animationFrame.frame.texture')
in setCurrentFrame(). Usually you created an animation with a bad texture key.
TypeError: undefined is not an object (evaluating 'state.currentFrame.duration')
in getFirstTick(). You're playing an empty animation (no frames), or you're playing a startFrame
that's out of range. If the animation has no frames, this is usually because generateFrameNames()
or generateFrameNumbers()
couldn't select any; look for preceding warnings in the console.
TypeError: undefined is not an object (evaluating 'this.anims.play')
You're playing on a destroyed Sprite or a non-Sprite game object (lacking anims
).
TypeError: sprite.play is not a function
You're playing on a non-Sprite game object.
Author Credits
Content on this page includes work by: