Now we have a way of scoring points and showing off, but there’s one last element before this can really be called a game and that’s a bit of jeopardy. Without some danger and a way for the game to end. you’ll just be able to keep scoring points until you get tired of shooting asteroids. As such, we’re going to give the player a number of lives when the game starts and take one away every time they die.

Task Definition

  • When the game starts you should create a variable to store the players lives and initialize it to 3.
  • There should be a text label on the screen showing how many lives the user has remaining.
  • If the player is hit by an asteroid, they should lose one life.

Note. At this stage, we won’t stop the game when the player’s lives reach zero - we will do that in the next step.

Hints

The first part of this task is very similar to adding score to the game, like we did in the previous step. You will need to add a text object which is fixed to the camera, as well an internal variable to keep track of how many lives the player has.

After setting up the score label, you’ll need to make sure that the player ship and asteroids can collide. You might want to refer back to stage on Collisions for some reminders on how we did that for Asteroids and Bullets. This time, when an asteroid collides with the player - you should still destroy the asteroid, but you also want to reduce the number of lives the player has remaining.

Walkthrough

1. Add the Player Lives Variable

First up, you need to add a this.playerLives variable to the game state. This allows you to keep track of the player’s lives. You can initialize it as 3 (or whatever you like!).

mainGameState.create = function() {
    ...
    this.playerLives = 3;
}

2. Add the Text

Refer back to the previous lesson on adding labels to the screen. You will probably want to add the title label ‘LIVES’ and then a separate label containing the number of lives the user has remaining.

    var textStyle = {font: "16px Arial", fill: "#ffffff", align: "center"}

    this.livesTitle = game.add.text(game.width * 0.85, 30, "LIVES", textStyle);
    this.livesTitle.fixedToCamera = true;
    this.livesTitle.anchor.setTo(0.5, 0.5);

    this.livesValue = game.add.text(game.width * 0.75, 30, "0", textStyle);
    this.livesValue.fixedToCamera = true;
    this.livesValue.anchor.setTo(0.5, 0.5);

    this.playerLives = 3;

3. React to Collisions

You should refer back to the Collisions task for more details on how to do this, as this will be very similar. The main changes for this task are that you will need a separate callback function for when the player collides with an asteroid so that you can have separate logic for this event.

A rough outline of the steps required follow;

  1. Create a new callback function in your mainGameState object using something like mainGameState.onAsteroidPlayerCollision = function() { }.
  2. Call game.physics.arcade.collide(…); in your update loop to force phaser to check for collisions between the asteroids and the player.
  3. When a collision occurs - set pendingDestroy=true on the asteroid object and reduce the player’s lives by one.

Note. In the collision callback function, there is no guarantee from the game whether “object1” or “object2” is the asteroid or the player ship. Because of this, we will need to check both object1 and object2 to see if we can figure out which is the asteroid. Fortunately, every sprite keeps track of which image was used to create it in the sprite.key property. This will be exactly the same as the name of the image you used when you created the object. So, if your original image was “asteroid-small” you can simply check each of the two objects to see whether they their key includes the word “asteroid” - if it does, set “pendingDestroy” to true.

mainGameState.onPlayerAsteroidCollision = function(object1, object2) {
    // Check whether object1 or object2 is the asteroid and destroy just that object
    // Reduce the player's lives by 1
}

mainGameState.onPlayerAsteroidCollision = function(object1, object2) {
    if ( object1.key.includes("asteroid") ) {
        object1.pendingDestroy = true;
    } else {
        object2.pendingDestroy = true;
    }

    this.lives -= 1;
}

Extensions

  • Many games will make the player invulnerable for a few seconds after they have died. In order to do this you could add a timer like we did with the asteroids and the player bullets. Set that timer to be above zero when the player dies and count it down every update. If the player gets hit by an asteroid when that timer is above zero - you should let the player live but still destroy the asteroid.

Potential Solution(s)

Core Solution

The following solution fulfills the core requirements of this task, without adding an “invulnerable” period after the player dies.

mainGameState.create = function() {
    var textStyle = {font: "14px Arial", fill: "#ccddff", align: "center"}

    this.livesTitle = game.add.text(game.width * 0.25, 10, "SCORE");
    this.livesTitle.fixedToCamera = true;
    this.livesTitle.anchor.setTo(0.5, 0.5);

    this.livesValue = game.add.text(game.width * 0.25, 30, "0");
    this.livesValue.fixedToCamera = true;
    this.livesValue.anchor.setTo(0.5, 0.5);

    game.physics.arcade.enable(this.playerShip);

    this.lives = 3;
}

mainGameState.update = function() {
    game.physics.arcade.collide(this.playerShip, this.asteroids, onPlayerAsteroidCollision, null, this);

    this.livesValue.setText(this.lives);
}

mainGameState.onPlayerAsteroidCollision = function(object1, object2) {
    if ( object1.key.includes("asteroid") ) {
        object1.pendingDestroy = true;
    } else {
        object2.pendingDestroy = true;
    }

    this.lives -= 1;
}

Extension Solution

Adding this code to your solution will add a few seconds of invulnerability whenever the player dies.

mainGameState.create = function() {
    this.invulnerabilityTime = 0.0;
}

mainGameState.update = function() {
    if ( this.invulnerabilityTime > 0 ) {
        this.playerShip.alpha = 0.5;
        this.invulnerabilityTime -= game.time.elapsed;

        if ( this.invulnerabilityTime < 0 ) {
            this.playerShip.alpha = 1.0;
        }
    } 
}

mainGameState.onPlayerAsteroidCollision = function(objectA, objectB) {
    // If the invulnerability timer is above zero, the player is still invulnerable
    if ( this.invulnerabilityTime > 0 ) {
        return;
    }

    ...
    this.invulnerabilityTime = 3.0;
}