Steps

Keeping Score


The score will be based on collecting coins. We need to create the graphics on the screen for tracking how many coins have been collected and implement the functionality for increasing the score number when a player collects a coin.

Step 1 — Add Images for a font:numbers and icon:coin to the Boot.ts File

// Boot.ts

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

preload() {
//...
this.load.image('invisible-wall', 'images/invisible_wall.png');
this.load.image('font:numbers', 'images/numbers.png');
this.load.image('icon:coin', 'images/coin_icon.png');

//...
}
}

Step 2 — In the Play.ts File, Create Properties for Score Indicators

The three properties are:

  • score — it will be of the type integer with an initial value of 0.
  • coinIcon — it will be of type any and will be used to reference the game object in scoring.
  • scoreText — this will have a non-null assertion operator (!) so that it always has value and state (i.e., cannot be null or undefined). This has a specific type referring to Phaser that creates bitmap text objects to display a score on the screen.
// Play.ts

export class Play extends Phaser.Scene {
hero!: Hero;
spiders!: Spider[];
level!: Level;
currentLevel: integer = 2;
score: integer = 0;
coinIcon: any;

scoreText!: Phaser.GameObjects.BitmapText;

//...
}

Step 3 — In the Level.ts File, Add Elements for Scoring

Add the coinIcon property.

// Level.ts

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

//...
}

In the constructor, add a hud (short for “heads up display”) physics group that is not affected by gravity by giving the group’s object the allowGravity property and assigning it false.

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

//...
}

Create a method to show the HUD and add a local reference to that method in the loadLevel() method.

  • The spawnHUD() method should include two method references:
    1. this.spawnCoinIcon()
    2. this.spawnScoreText()
    • Create these methods in the file, as well — leaving them empty for now.
// Level.ts

export class Level {
//...

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

spawnHUD() {
this.spawnCoinIcon();
this.spawnScoreText();
}

spawnCoinIcon() { }

spawnScoreText() { }

//...
}

Use the spawnCoinIcon() method to create a coin icon in the game and add it to the HUD group with the following:

  1. this.coinIcon = this.scene.add.image(0, 0, 'icon:coin'); - creates a new image game object in the scene at the coordinates (0, 0). The image uses the asset key 'icon:coin' to determine what image to display. The created image object is then stored in the this.coinIcon property.
  2. this.coinIcon.setOrigin(0, 0); - sets the origin of the coinIcon image object to (0, 0). The origin is the point in the object to which all transformations are relative. Setting the origin to (0, 0) means the transformations will be relative to the top-left corner of the object.
  3. this.coinIcon.setPosition(10, 10); - sets the position of the coinIcon image object to the coordinates (10, 10). This means the top-left corner of the coinIcon will be at (10, 10) in the game world.
  4. this.groups.hud.add(this.coinIcon); - adds the coinIcon image object to the hud group that holds game objects related to the heads-up display (HUD).
// Level.ts

export class Level {
//...

spawnHUD() {
this.spawnCoinIcon();
this.spawnScoreText();
}

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



//...
}

Configure the score display as a bitmap font. This should be called spawnScoreText() and should include:

  1. const config = {...}; - which creates a configuration object for a bitmap font.
    1. The properties of this object define the characteristics of the font, such as the image to use ('font:numbers' that we loaded in the Boot.ts file), the dimensions of each character (width: 20, height: 26), the characters included in the font (chars: '0123456789X ' meaning that only be numbers 0-9 and an “x” are allowed), the number of characters per row in the font image (charsPerRow: 6), and various spacing options.
  2. this.scene.cache.bitmapFont.add(...); - adds a new bitmap font to the scene's font cache. The first argument is the key that will be used to refer to this font in the future ('font:numbers').
    1. Phaser.GameObjects.RetroFont.Parse(this.scene, config) - is the second argument to the add method. It's calling the Parse method of  Phaser.GameObjects.RetroFont to create a new bitmap font from the provided configuration.
    2. The created font is then added to the cache.
// Level.ts

export class Level {
//...

spawnHUD() {
this.spawnCoinIcon();
this.spawnScoreText();
}

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

spawnScoreText() {
const config = {
image: 'font:numbers',
width: 20,
height: 26,
chars: '0123456789X ',
'offset.x': 0,
'offset.y': 0,
charsPerRow: 6,
'spacing.x': 0,
'spacing.y': 0,
lineSpacing: 1,
};

this.scene.cache.bitmapFont.add(
'font:numbers',
Phaser.GameObjects.RetroFont.Parse(this.scene, config)
);
}

//...
}

Step 4 — In the Play.ts File, Add the coinIcon Reference to the mapProps() Method as a Prop in the Array

// Play.ts

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

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

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

//...
}

Create a method for establishing the bitmap text to display the score during gameplay. This method will be called initScore() and should include:

  1. this.scoreText = this.add.bitmapText(...); - This line is creating a new bitmap text object and assigning it to the this.scoreText property that we previously made.
  2. this.coinIcon.x + this.coinIcon.width + 5, 15, - These are the x and y coordinates where the bitmap text object will be placed.
    1. The x coordinate is calculated as the x position of the coinIcon plus its width plus 5. This means the text will be placed just to the right of the coinIcon.
    2. The y coordinate is simply 15, so the text will be placed 15 pixels down from the top of the game world.
  3. 'font:numbers', - This is the key of the bitmap font that was previously established in Boot.ts
  4. X${this.score} - This is the initial text that the bitmap text object will display. It's a template literal that will result in a string like "X0", where 0 is the current value of this.score. The "X" stands for "times", as in "times the number of coins collected". As coins are collected, the score variable will increase which will increase the number displayed here.

Once the initScore() method has been created, add it as a local reference in the create() method of the Play class.

// Play.ts

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

create() {
//...
this.initScore();
}

initScore() {
this.scoreText = this.add.bitmapText(
this.coinIcon.x + this.coinIcon.width + 5,
15,
'font:numbers',
**X${this.score}**
);
}

//...
}

Step 5 — In the collectCoin() Method, Add a Way to Calculate the Score and Update the Score Text

  • Use a reference to the score property to increment it by 1 every time a coin is collected.
  • Also update the scoreText property based on the new score.
// Play.ts

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

collectCoin(hero, coin) {
coin.destroy();
this.sound.play('sfx:coin');
this.score += 1;
this.scoreText.text = **X${this.score}**;
}

//...


}

Account for resetting the score when the player loses by adding a reset() method to the gameOver() method.

  • Create the reset() method with the logic of assigning 0 to the score property.
// Play.ts

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

collectCoin(hero, coin) {
coin.destroy();
this.sound.play('sfx:coin');
this.score += 1;
this.scoreText.text = **X${this.score}**;
}

//...

reset() {
this.score = 0;
}

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 coin icon in the top left corner with a x0 text.
  2. The text should increase with every coin the player collects.
  3. If the player “dies”, the score should reset to “0”.
< Back Home