Steps

Win Condition


The win condition will be based on accessing a key in the game. We need to create the key object and also an icon to show whether or not we have achieved this condition.

Step 1 — In the Boot.ts File, Create the Object Settings for a Win Scenario

Use the preload() method to:

  1. Load an image of a key — this is for displaying at the top of the screen to show whether or not the character has captured the key.
  2. Create the key’s spritesheet — this is for displaying the key in the level that the character needs to capture.
  3. Load audio for the key — for when the key is captured.
// Boot.ts

export class Boot extends Phaser.Scene {
//...

preload() {
//...
this.load.image('key', 'images/key.png');

//...
this.load.spritesheet('icon:key', 'images/key_icon.png', {
frameWidth: 34,
frameHeight: 30,
});

//...
this.load.audio('sfx:key', 'audio/key.wav');
}
}

Step 2 — In the Level.ts File, Add a Utility Method to Add Physics to Objects in the Current Game Scene

The method addPhysics() can go at the bottom of the class and should take two parameters:

  • gameObject — a reference to the object we want to update.
  • isStatic — an optional, boolean parameter to determine whether the object should be static or dynamic. A static game object would not be affected by physics in Phaser.

Include logic to add physics to an existing game object.

// Level.ts

export class Level {
//...

addPhysics(gameObject, isStatic?) {
this.scene.physics.add.existing(gameObject, isStatic);
}
}

Add a keyIcon and key property to the Level class with the type of any.

// Level.ts

export class Level {
hero!: Hero;
spiders: Spider[] = [];
coinIcon: any;
keyIcon: any;
key: any;

//...
}

Update the constructor with a new group called bgDecoration and make it a part of the physics group of the game.

// Level.ts

export class Level {
//...

constructor(private scene: Play) {
this.animations = this.scene.getAnimations('elements');
this.platforms = this.scene.physics.add.staticGroup();
this.groups = {
//...
hud: this.scene.physics.add.group({ allowGravity: false }),
bgDecoration: this.scene.physics.add.group(),
};
}

//...
}

Add the key to the game scene using the method spawnKey().

  • This method should take key as a parameter and use a local reference to the key property to create an instance of the key in the bgDecoration group with parameters setting the coordinates and image reference.
  • this.key.setOrigin(0.5, 0.5); — makes the origin of the object be the center (as opposed to the top left).
  • The allowGravity property should be set to false.
  • Add a setting to make the key move.
    • Using this.key.y we can access the y coordinate plane and set a value. By setting the value to -= 3 we will incrementally move the key up by 3 pixels.
  • Create a new “tween” for the key object (a tween is a way to change a property of an object over time). These settings will allow the key to move up and down in a sine wave pattern.
  • Finally, use the addPhysics() method to instantiate the physics of the key.

Once created, add this method to the loadLevel() method.

// Level.ts

export class Level {
//...

loadLevel(data) {
//...
this.spawnKey(data.key);
}

spawnKey(key) {
this.key = this.groups.bgDecoration.create(key.x, key.y, 'key');
this.key.setOrigin(0.5, 0.5);
this.key.body.allowGravity = false;
this.key.y -= 3;

this.scene.tweens.add({
targets: this.key,
y: this.key.y + 6,
duration: 500,
yoyo: true,
loop: -1,
ease: 'Sine.easeInOut',
delay: 1000,
});

this.addPhysics(this.key);
}

//...
}

Create a method to spawn the key icon in the “score” area using the key that we just set up.

  • The spawnKeyIcon() method should include adding the image, setting the origin, setting the position of the key on the screen, and adding the key to the hud group.

This method should then be included in the spawnHUD() method (which is already included in the loadLevel() method and should, therefore, be set in the game as a part of the heads-up-display). Make sure to put the spawnKeyIcon() as the first method reference in spawnHUD() as shown below.

// Level.ts

export class Level {
//...

loadLevel(data) {
//...
this.spawnKey(data.key);
this.spawnHUD();
}

spawnHUD() {
this.spawnKeyIcon();
this.spawnCoinIcon();
//...
}

spawnKeyIcon() {
this.keyIcon = this.scene.add.image(0, 0, 'icon:key');
this.keyIcon.setOrigin(0, 0);
this.keyIcon.setPosition(5, 15);
this.groups.hud.add(this.keyIcon);
}

spawnCoinIcon() {
this.coinIcon = this.scene.add.image(0, 0, 'icon:coin');
this.coinIcon.setOrigin(0, 0);
this.coinIcon.setPosition(this.keyIcon.x + this.keyIcon.width + 10, 10);
this.groups.hud.add(this.coinIcon);
}

//...
}

Step 3 — Incorporate Winning Conditions in the Play.ts File

Add properties that will be used to make the key part of the gameplay to implement winning conditions.

  • The key and keyIcon properties should be set to any.
  • Create a hasKey property of type boolean that is assigned an initial value of false.
// Play.ts

export class Play extends Phaser.Scene {
//...
key: any
keyIcon: any;
hasKey: boolean = false;

//...
}

Update the mapProps() method to include these new properties.

// Play.ts

export class Play extends Phaser.Scene {
//...

private mapProps() {
const props = [
'hero',
'groups',
'spiders',
'coinIcon',
'keyIcon',
'key',
];

props.forEach((prop) => (this[prop] = this.level[prop]));
}

//...
}

Add a new overlap() that allows the hero character to access the key in the initPhysics() method.

  • Then, add a collectKey() method so that the key is destroyed from the game when collected and the sfx:key sound plays.
  • This should also set the hasKey property to true so that we continue to track the state of the key.
// Play.ts

export class Play extends Phaser.Scene {
//...
initPhysics() {
//...
this.physics.add.overlap(this.hero, this.key, this.collectKey, undefined, this);
}

collectKey(hero, key) {
key.destroy();
this.sound.play('sfx:key');
this.hasKey = true;
}

//...
}

In the update() method of the Play class, change the keyIcon display based on the hasKey property.

  • Using a ternary, set the keyIcon frame to 1 if the hasKey property is true.
  • Otherwise, set the frame to 0.
// Play.ts

export class Play extends Phaser.Scene {
//...

update() {
this.hero.update();
this.spiders.forEach((spider) => spider.update());

const frame = this.hasKey ? 1 : 0;
this.keyIcon.setFrame(frame);
}

//...
}

Account for the hasKey property if the hero character is destroyed.

  • In the reset() method, set the local reference of the hasKey property to false.
// Play.ts

export class Play extends Phaser.Scene {
//...

reset() {
this.score = 0;
this.hasKey = false;
}

gameOver() {
this.reset();
this.hero.die();
this.cameras.main.fade(1000);
this.cameras.main.on('camerafadeoutcomplete', (camera, effect) => {
this.scene.restart();
});
}

//...
}

Checkpoint

  1. There should be a key icon in the upper left corner with a white fill color.
  2. There should be a key in the game that moves slightly.
  3. When the hero character overlaps with the key, the key should disappear and the the key icon should turn red. You should also hear a sound.
< Back Home