Animations
The Animations Manager
We need to create a way to manage animations in the game — for this, we will use the Animations.ts file.
Step 1 — Add a Map to Give Access to Properties of the Various Objects in the Game
These will store the various animation configurations for use in the game as an object with further nested objects. These nested objects for each property should be left empty for now.
// Animations.ts
export class Animations {
map = {
spider: {
},
hero: {
},
elements: {
coin: {
},
},
};
}
Step 2 — Create the Constructor and Methods to Initialize Animations and Call Them
- constructor(scene: Phaser.Scene) {...} - this takes one argument, scene, which is an instance of Phaser.Scene. Inside the constructor, it calls the initAnimations method.
- getAnimations(key: string) {...} - This gets the animations for a specific game element.
- It takes one argument, key, which is a string that represents the name of a game element.
- Inside the method, it returns the value of the key property from the map object.
- initAnimations(scene: Phaser.Scene) {} - This method is used to initialize the animations for the game elements. It takes one argument, scene, which is an instance of Phaser.Scene. This will remain empty until we have a specific animation we want to include.
// Animations.ts
export class Animations {
map = {
spider: {
},
hero: {
},
elements: {
coin: {
},
},
};
constructor(scene: Phaser.Scene) {
this.initAnimations(scene);
}
getAnimations(key: string) {
return this.map[key];
}
initAnimations(scene: Phaser.Scene) {}
}
Step 3 — Create an Animation for the Coins

In the animation map — create a key property called rotate and assign it the value 'coin.rotate'
// Animations.ts
export class Animations {
map = {
//...
elements: {
coin: {
rotate: 'coin:rotate',
},
},
};
//...
}
Create the actual animation for a rotating coin that uses the map value we just made.
-
Using the argument of (scene: Phaser.Scene) — we will create an anims property based on Phaser.Scene that is an instance of the Phaser framework Phaser.Animations.AnimationManager
-
The create method is used to create a new animation for the game.
-
We will use the key and a string value as an identifier to determine what the animation will be applied to.
-
The frames property will call scene.anims.generateFrameNumbers() determines the frames used by the animation and takes two arguments:
- The key of the texture
- An object to specify the frames
-
The key here will be 'coin:rotate' which we established in our map.
-
The object will be an array of frames set as numbers to represent the frame number in the order they should be played.
-
Another property is the frameRate which describes the rate of the animation (how many frames should be played per second).
-
repeat being set to -1 means that the animation should repeat indefinitely.
// Animations.ts
export class Animations {
map = {
//...
elements: {
coin: {
rotate: 'coin:rotate',
},
},
};
//...
initAnimations(scene: Phaser.Scene) {
scene.anims.create({
key: 'coin:rotate',
frames: scene.anims.generateFrameNumbers('coin', {
frames: [0, 1, 2, 1],
}),
frameRate: 6,
repeat: -1,
});
}
}
Step 4 — Incorporate the Animations in Play.ts
Create a property for the Animations class.
// Play.ts
import { Animations } from './Animations';
import { Hero } from './Hero';
import { Level } from './Level';
import { Spider } from './Spider';
export class Play extends Phaser.Scene {
hero!: Hero;
spiders!: Spider[];
level!: Level;
currentLevel: integer = 2;
groups!: { [key: string]: Phaser.Physics.Arcade.Group };
animations!: Animations;
constructor() {
super('Play');
}
//...
}
Set up methods to create, initialize, and get the animations — so they can run within the gameplay.
- getAnimations() — gets the animations for a specific game element.
- It takes the argument of a key that represents the name of the game element it is acting on.
- It then calls the method on the animations property and passes the key (which is a reference to the the stored animation configurations on the map object within the Animations class.
- initAnimations() {...} — initializes the animations for the game by creating new instances of the Animations class and assigning it to the animations property.
- This process connects the animations being set in the Animations.ts file with the game play initialization in the Play.ts file.
Finally, include the initAnimations() method within the create() method.
// Play.ts
export class Play extends Phaser.Scene {
//...
create() {
console.log('Play.create()');
this.initAnimations();
this.initLevel();
this.initPhysics();
}
initAnimations() {
this.animations = new Animations(this);
}
getAnimations(key: string) {
return this.animations.getAnimations(key);
}
}
Step 5 — Incorporate the Animations in Level.ts
Instantiate an animations property — with a required (non-null) assertion. This will be set to any meaning it can be of any type.
- Then, initialize the animations in the constructor using a reference to the animations property in the scope of the class and assign it to the getAnimations() method on the scene property.
- This will take an argument of ('elements') to refer to various elements that can be accessed as animations.
// Level.ts
export class Level {
//...
platforms!: Phaser.Physics.Arcade.StaticGroup;
groups!: { [key: string]: Phaser.Physics.Arcade.Group };
animations!: any;
constructor(private scene: Play) {
this.animations = this.scene.getAnimations('elements');
this.platforms = this.scene.physics.add.staticGroup();
//...
}
//...
}
Step 6 — Apply the Animations to the Coins Within the spawnCoin(coin) Method
In this method, add _coin.anims.play(this.animations.coin.rotate, true);
- This will call the play() method of the anims() property with the coin sprite to play the animation.
- This uses the arguments of:
- The key of the animation
- A boolean that indicates whether the animation should be played immediately or not.
- The key of the animation is:
- this.animations.coin.rotate — which refers to the map created in the Animations class.
// Level.ts
export class Level {
//...
spawnCoin(coin) {
const _coin = this.scene.add.sprite(coin.x, coin.y, 'coin');
_coin.setOrigin(0.5, 0.5);
_coin.anims.play(this.animations.coin.rotate, true);
return _coin;
}
//...
}
Step 7 — Create the Animation for the Spiders

In the Animations.ts file, add a property key to the spider object called crawl with a value of spider:crawl
// Animations.ts
export class Animations {
map = {
spider: {
crawl: 'spider:crawl',
},
elements: {
coin: {
rotate: 'coin:rotate',
},
},
};
//...
}
Initialize and create the animation in the initAnimations() method.
- Similar to the coin, we need to use scene.anims.create({...}); to set the key, frames, frameRate, and repeat values.
// Animations.ts
export class Animations {
//...
initAnimations(scene: Phaser.Scene) {
scene.anims.create({
key: 'spider:crawl',
frames: scene.anims.generateFrameNumbers('spider', {
frames: [0, 1, 2],
}),
frameRate: 8,
repeat: -1,
});
//...
}
}
Step 8 — Add an Animation Property to the Spider Class in Spider.ts
// Spider.ts
export class Spider extends Phaser.Physics.Arcade.Sprite {
direction = Directions.right;
animations: any;
//...
}
Update the constructor to initialize the animations property with the spider-specific animations.
- Use a local reference to animations — this.animations
- Use the getAnimations() method on the scene property and pass in the argument for ('spider').
// Spider.ts
export class Spider extends Phaser.Physics.Arcade.Sprite {
direction = Directions.right;
animations: any;
constructor(scene: Play, x, y) {
super(scene, x, y, 'spider');
this.animations = scene.getAnimations('spider');
this.setOrigin(0.5, 0.5);
}
//...
}
In the crawl() method, connect the animation to play using the same process as the coin animation:
// Spider.ts
export class Spider extends Phaser.Physics.Arcade.Sprite {
//...
crawl(direction) {
const velocity = this.getVelocity(direction);
this.setVelocityX(velocity);
this.anims.play(this.animations.crawl, true);
}
//...
}
Step 9 — Animate the Hero

Begin in the Animation.ts file and update the map object’s hero section to include various animations to set on the hero character.
// Animations.ts
export class Animations {
map = {
//...
hero: {
stop: 'hero:stop',
run: 'hero:run',
jump: 'hero:jump',
fall: 'hero:fall',
},
//...
};
initAnimations(scene: Phaser.Scene) {
//...
}
}
Create the animations using the scene.anims property for each of the animation types just created.
- Each animation will need to use scene.anims.create({...}); to set the key, frames, frameRate, and repeat values. Not every animation will require all four value fields to be set.
- These “static” animations will only have a frame reference with one number instead of a frames array with multiple numbers.
// Animations.ts
export class Animations {
//...
initAnimations(scene: Phaser.Scene) {
//...
scene.anims.create({
key: 'hero:stop',
frames: [{ key: 'hero', frame: 0 }],
});
scene.anims.create({
key: 'hero:run',
frames: scene.anims.generateFrameNumbers('hero', { start: 1, end: 2 }),
frameRate: 8,
repeat: -1,
});
scene.anims.create({
key: 'hero:jump',
frames: [{ key: 'hero', frame: 3 }],
});
scene.anims.create({
key: 'hero:fall',
frames: [{ key: 'hero', frame: 4 }],
});
}
}
Include these animations in the Hero class (Hero.ts) by adding an animations property and setting the local reference to the animations in the constructor (using the same process as the spider)
// Hero.ts
export class Hero extends Phaser.Physics.Arcade.Sprite {
keys!: Phaser.Types.Input.Keyboard.CursorKeys;
animations!: any;
constructor(scene: Play, x, y) {
super(scene, x, y, 'hero');
this.animations = scene.getAnimations('hero');
this.setOrigin(0.5, 0.5);
this.initKeys(scene);
}
//...
}
In the update() method of the Hero class, add the animation to the hero’s actions that are associated with cursor commands to move the hero.
- This function updates the state of the hero character in each frame of the game.
- Adding let animationName = this.getAnimationName(); will call a method to the get the name of the current animation by checking the state of the hero character. This will determine which animation should occur.
- The conditional logic is:
- If the current animation is not the same as the animation that should be played — it calls the play property to change the animation.
// Hero.ts
export class Hero extends Phaser.Physics.Arcade.Sprite {
//...
update() {
if (this.keys.up.isDown && this.body.touching.down) {
this.jump();
} else if (this.keys.left.isDown) {
this.runLeft();
} else if (this.keys.right.isDown) {
this.runRight();
} else {
this.halt();
}
let animationName = this.getAnimationName();
if (this.anims.getName() !== animationName) {
this.anims.play(animationName);
}
}
//...
}
Create the logic for the getAnimationName() method that will determine the name of the animation that should be played based on the current state of the hero character.
-
This should check the state of the body property and the animations property to determine which animation name should be used.
-
A name variable should be declared using let and assign this.animations.stop to it.
- This initializes the name variable with the value of stop — making it the default animation that can now be changed based on the state of the hero character.
-
Create conditional logic to determine if the animation should change:
- If the body’s y-velocity is greater than 0 (moving upwards) — the name value is changed to jump.
- If the y-velocity is less than or equal to 0 and the character is not touching the ground (falling) — the name value is changed to fall.
- If the x-velocity is not 0 and the character is touching the ground (running) — the name value is changed to run.
-
End by returning the name variable which now returns the name of the animation that should be active based on the current state of the hero character.
// Hero.ts
export class Hero extends Phaser.Physics.Arcade.Sprite {
//...
update() {
//...
let animationName = this.getAnimationName();
if (this.anims.getName() !== animationName) {
this.anims.play(animationName);
}
}
getAnimationName() {
let name = this.animations.stop; // default animation
if (this.body.velocity.y > 0) {
name = this.animations.jump;
} else if (this.body.velocity.y <= 0 && !this.body.touching.down) {
name = this.animations.fall;
} else if (this.body.velocity.x !== 0 && this.body.touching.down) {
name = this.animations.run;
}
return name;
}
//...
}
Checkpoint
- The coins should be spinning.
- The spiders should have the appearance of their legs moving while they “crawl”
- The hero character should change appearance during different movements.