Switching Levels
Introduce the ability to end a level and begin a new one within the game play.
Step 1 — In the Boot.ts File, Create a New ‘Door’ Object
Load the spritesheet and audio for the door in the preload() method.
// Boot.ts
export class Boot extends Phaser.Scene {
//...
preload() {
//...
this.load.spritesheet('door', 'images/door.png', {
frameWidth: 42,
frameHeight: 66,
});
//...
this.load.audio('sfx:door', 'audio/door.wav');
}
//...
}
Step 2 — Incorporate the ‘Door’ in Level.ts
Create a property in the Level class for a door.
- This should be of type any.
// Level.ts
export class Level {
hero!: Hero;
spiders: Spider[] = [];
coinIcon: any;
keyIcon: any;
key: any;
door: any;
//...
}
Add a method to spawn the door as a part of the bgDecoration group.
- Implement this method within the loadLevel() method.
// Level.ts
export class Level {
//...
loadLevel(data) {
this.spawnBG();
this.spawnDoor(data.door);
this.spawnPlatforms(data.platforms);
//...
}
spawnDoor(door) {
this.door = this.groups.bgDecoration.create(door.x, door.y, 'door');
this.door.setOrigin(0.5, 1);
this.door.body.allowGravity = false;
this.addPhysics(this.door);
}
//...
}
Step 3 — In the Play.ts File, Set Conditions for a Level to Change
Add a property outside of the class for the level count, add a door property to the class (of the type any), and change the currentLevel property to 1.
// Play.ts
const LEVEL_COUNT = 2;
export class Play extends Phaser.Scene {
hero!: Hero;
spiders!: Spider[];
level!: Level;
currentLevel: integer = 1;
score: integer = 0;
key: any;
door: any;
coinIcon: any;
keyIcon: any;
hasKey: boolean = false;
//...
}
Add the door to the mapProps() method.
// Play.ts
export class Play extends Phaser.Scene {
//...
private mapProps() {
const props = [
'hero',
'groups',
'spiders',
'coinIcon',
'keyIcon',
'key',
'door',
];
props.forEach((prop) => (this[prop] = this.level[prop]));
}
}
Create a method called exitThroughDoor() that responds to the hero character moving over the door and plays a sound. This should also trigger another method: gotoNextLevel().
- Once the exitThroughDoor() method is created, add it to the initPhysics() method as an overlap scenario between the hero and door objects.
// Play.ts
export class Play extends Phaser.Scene {
//...
initPhysics() {
//...
this.physics.add.overlap(
this.hero,
this.door,
this.exitThroughDoor,
(hero, door) => this.hasKey && hero.body.touching.down,
this
);
}
exitThroughDoor(hero, door) {
this.sound.play('sfx:door');
this.gotoNextLevel();
}
//...
}
Setup the logic for the gotoNextLevel() method.
- This should access the currentLevel and check to see if it is less than the LEVEL_COUNT property.
- If it is, then currentLevel should increment by 1.
- If it is not, then currentLevel should be set to 1 so that the player goes back to the first level of the game.
The method should end by calling this.reset() to enact the camera animations.
// Play.ts
export class Play extends Phaser.Scene {
//...
gotoNextLevel() {
this.currentLevel =
this.currentLevel < LEVEL_COUNT ? ++this.currentLevel : 1;
this.reset();
}
//...
}
Step 4 — Change the Dynamics for How a Level Ends
In the Play.ts file, change the gameOver() method so that it no longer has the camera animations and move the camera animations to the reset() method.
- Also, add a call to the gotoLevel() method in the reset() method.
The gotoLevel() method accesses the loadLevel() method where data is retrieved from the cache with a key referring to JSON data.
// Play.ts
export class Play extends Phaser.Scene {
//...
reset() {
this.score = 0;
this.hasKey = false;
this.cameras.main.fade(1000);
this.cameras.main.on('camerafadeoutcomplete', (camera, effect) => {
this.scene.start('Play');
this.gotoLevel(this.currentLevel);
});
}
gameOver() {
this.hero.die();
this.reset();
}
gotoLevel(level) {
this.level.loadLevel(this.cache.json.get(**level:${level}**));
}
//...
}
Essentially, we have changed the way a level ends so that:
- When any reset() occurs, the score is set to 0, the player does not have a key, the camera fades out for one second, it restarts the Play dynamics, and goes to the currentLevel (which could be different based on what has happened in the game).
- If gameOver() is triggered, the die mechanics occur and the reset() method is called.
Checkpoint
- There should now be a door on the screen.
- When the player passes the door without the key, nothing should happen.
- When the player passes the door with the key, the level should end and take the player to the next level.
- If the player completes the final level, it should take the player back to level one.
Note: If you would like to see the game without the physics debugging, return to the Config.ts file and comment out the debug key.
import Phaser from "phaser";
import { Boot } from './Boot';
import { Play } from './Play';
export const gameConfig = {
type: Phaser.AUTO,
width: 960,
height: 600,
roundPixels: true,
backgroundColor: 0x000000,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
// debug: true,
},
},
scene: [Boot, Play],
};