In order to create a fun and interesting game, we need to add some elements that will challenge the player and make them do something. We’ll start by adding asteroids that move down the screen towards the player. Asteroids will form the main hazard in the first draft of our game.

Task Definition

Asteroids in Space Avengers should abide by the following rules;

  • A new asteroid should appear at the top of the screen every few seconds.
  • All asteroids will constantly move down the screen.
  • When an asteroid has disappeared off the bottom of the screen, you will need to delete it to prevent an infinite number of asteroids from appearing in the game!

Later on, we’ll add bullets and a way to destroy the asteroids - but for now we’ll just make the asteroids move down the screen. They will simply move through the player for now - but we’ll move onto making things collide later.

Walkthrough

1. Create a Timer that does ‘something’ every 2 seconds

We’re going to create a rudimentary timer using a variable in our game state. It will work like this;

  1. Create the variable this.asteroidTimer in your create method and set it to 2.0.
  2. In your update method, subtract the current frame time from the timer (see below) using game.time.physicsElapsed.
  3. If the timer is zero or less, print out “SPAWN ASTEROID” in your console and reset the timer back to the full time again.

Frame Time: “Frame Time” or “Delta Time” is a term often used in the games industry. It is the amount of time that has passed since the last time update was called. You can use the property game.time.physicsElapsed to get the amount of time (in fractions of a second) that has passed since the last time update was called. Normally, this will be exactly the same very frame (1/60th of a second - or 0.016).

Experiment: In your update method try calling console.log(game.time.physicsElapsed); and see what gets printed out.

mainGameState.create = function() {
    ...
    this.asteroidTimer = 2.0;
}

mainGameState.update = function() {
    ...

    this.asteroidTimer -= game.time.physicsElapsed;

    if ( this.asteroidTimer <= 0.0 ) {
        console.log("SPAWN ASTEROID");
        this.asteroidTimer = 2.0;
    }
}

At the end of this step, you should have a system which prints the words “SPAWN ASTEROID” in the developer console in Chrome every 2 seconds.

2. Spawn an Asteroid

Now that we have a timer system in place that triggers every couple of seconds, we can start spawning asteroids.

Tip: In order to keep your logic tidy, this is a good time to make an extra function on your mainGameState. Instead of constantly adding code to your update function, this is a good time to add a mainGameState.spawnAsteroid function and call it whenever you need to spawn an asteroid.

This stage should be completed in the following order. You should try to run the game periodically after completing most of these steps to check that there are no errors in the console and that the game is performing as you would expect.

  1. Don’t forget to add an image for the asteroid to the project folder.
  2. Create a mainGameState.spawnAsteroid() function.
  3. In your mainGameState.spawnAsteroid() function, create the asteroid like you did with the player ship.
  4. Set the “X” position to a random value using game.rnd.integerInRange(min, max); so that the asteroid spawns at a random point at the top of the screen.
  5. You can set the velocity of the asteroid at the point it is created to start moving down the screen.
  6. Don’t forget to call ‘this.spawnAsteroid()’ when the timer reaches zero!

mainGameState.preload = function() {
    ...
    game.load.image("asteroid-medium-01", "assets/images/asteroid-medium-01.png");  
}

mainGameState.create = function() {
    ...
    this.asteroidTimer = 2.0;    
}

mainGameState.update = function() {
    this.asteroidTimer -= game.time.physicsElapsed;

    if ( this.asteroidTimer <= 0.0 ) {
        this.spawnAsteroid();
        this.asteroidTimer = 2.0;
    }
}

mainGameState.spawnAsteroid = function() {
    // Setup and create our asteroid
    var x = game.rnd.integerInRange(0, game.width);
    var asteroid = game.add.sprite(x, 0, "asteroid-medium-01");
    asteroid.anchor.setTo(0.5, 0.5);
    game.physics.arcade.enable(asteroid);
    asteroid.body.velocity.setTo(0, 100);
}

3. Add the asteroids to a ‘group’

Thre is one big flaw in our problem at the moment - and that is that the asteroids that we create will live forever! That’s right - every single asteroid you create will keep moving down the screen long after you can no longer see them in the camera. This is probably okay for the first couple of minutes of playing your game - but if you leave it running for 10 minutes that means there will be 300 asteroids you can’t see!

Phaser provides the concept of ‘group’ which is very similar to an array but it is used to keep track of sprites in the game. We will create a group object to keep track of our asteroids so that we can check over all of our asteroids later to see which ones have moved off the screen.

You can create a group object using this.asteroids = game.add.group(); somewhere in your create function. You should create if after your game background. After you have setup the empty group, you should add all asteroids you spawn to this group at the end of your spawnAsteroid() function using this.asteroids.add(asteroid);. This is almost the same as pushing it on the end of an array.

4. Clean Up Old Asteroids

Now that we have all of the asteroids we’ve created in a group, we can actually get access from that group to an array containing all of the asteroid sprites.

  1. At the end of your update function, iterate over all of the asteroids by using this.asteroids.children - this is just an array of all of the asteroids that you have on the screen which are managed by the this.asteroids Phaser group.
  2. For each asteroid that is way off the bottom of the screen (it’s y co-ordinate is very high) - destroy it by calling the this.asteroids.children[i].destroy() function.

mainGameState.preload = function() {
    ...
    game.load.image("asteroid-medium-01", "assets/images/asteroid-medium-01.png");  
}

mainGameState.create = function() {
    ...
    this.asteroidTimer = 2.0;    
}

mainGameState.update = function() {
    this.asteroidTimer -= game.time.physicsElapsed;

    if ( this.asteroidTimer <= 0.0 ) {
        this.spawnAsteroid();
        this.asteroidTimer = 2.0;
    }

    // Clean up any asteroids that have moved off the bottom of the screen
    for( var i = 0; i < this.asteroids.children.length; i++ ) {
        if ( this.asteroids.children[i].y > (game.height + 200) ) {
            this.asteroids.children[i].destroy();
        }
    }    
}

mainGameState.spawnAsteroid = function() {
    // Setup and create our asteroid
    var x = game.rnd.integerInRange(0, game.width);
    var asteroid = game.add.sprite(x, 0, "asteroid-medium-01");
    asteroid.anchor.setTo(0.5, 0.5);
    game.physics.arcade.enable(asteroid);
    asteroid.body.velocity.setTo(0, 100);

    // Add to the 'asteroids' group
    this.asteroids.add(asteroid);
}

Extensions

  • If you’ve started going for an alternative theme for your game, now would be a good time to go online and find a different image instead of an asteroid for your game.
  • It’s a good idea to make the asteroid’s Y velocity a constant at the top of the file so that it’s easy to change.
  • Even better, you could add a random factor to the asteroid’s Y velocity to mix things up a bit.
  • You can make the asteroid spin while it moves down the screen setting some angular velocity on the sprite asteroid.body.angularVelocity. Try setting the angular velocity to a random value so that it spins at a random speed to mix things up.
  • There are lots of different images in the project asset bundle. You could add some variety to your game by selecting one at of those many images at random.
  • To add even more variation to the game, you could also consider changing the size of the asteroids a small amount by setting the asteroid’s scale factor.

Potential Solution

If you have been following the standard solution, your code should look something like this after this task.

var mainGameState = { } 

mainGameState.preload = function() {
    console.log("Pre-loading the game!");
    
    game.load.image("space-bg", "assets/images/space-bg.jpg");
    game.load.image("player-ship", "assets/images/player-ship.png");
    game.load.image("asteroid-medium-01", "assets/images/asteroid-medium-01.png");  
        
    game.load.audio("game-music", "assets/music/maingame.mp3");    
}

mainGameState.create = function() {
    game.physics.startSystem(Phaser.Physics.ARCADE);

    game.add.sprite(0, 0, "space-bg");

    var shipX = game.width * 0.5;
    var shipY = game.height * 0.8;

    this.cursors = game.input.keyboard.createCursorKeys();        

    this.playerShip = game.add.sprite(shipX, shipY, 'player-ship');
    this.playerShip.anchor.setTo(0.5, 0.5);
    game.physics.arcade.enable(this.playerShip);
    
    this.music = game.add.audio("game-music");
    this.music.play();
    this.music.volume = 0.5;
    this.music.loop = true;     
    
    this.asteroidTimer = 2.0;   
    this.asteroids = game.add.group();    
}

mainGameState.update = function() {
    if ( this.cursors.left.isDown ) {
        this.playerShip.body.velocity.x = -200;
    } else if ( this.cursors.right.isDown ) {
        this.playerShip.body.velocity.x = 200;
    } else {
        this.playerShip.body.velocity.x = 0;
    }
    
    this.asteroidTimer -= game.time.physicsElapsed;

    if ( this.asteroidTimer <= 0.0 ) {
        this.spawnAsteroid();
        this.asteroidTimer = 2.0;
    }    
    
    // Clean up any asteroids that have moved off the bottom of the screen
    for( var i = 0; i < this.asteroids.children.length; i++ ) {
        if ( this.asteroids.children[i].y > (game.height + 200) ) {
            this.asteroids.children[i].destroy();
        }
    }        
}

mainGameState.spawnAsteroid = function() {
    // Setup and create our asteroid
    var x = game.rnd.integerInRange(0, game.width);
    var asteroid = game.add.sprite(x, 0, "asteroid-medium-01");
    asteroid.anchor.setTo(0.5, 0.5);
    game.physics.arcade.enable(asteroid);
    asteroid.body.velocity.setTo(0, 100);

    // Add to the 'asteroids' group
    this.asteroids.add(asteroid);
}