Be sure that you completed Coding Steps 6-10 on the previous page.
IMPORTANT: Take the time to read each step, and try to understand how the code works.
Right now, our game is very unforgiving — if the spaceship collides with just one asteroid, the game is over.
Let's give the spaceship some "shields" that will be damaged every time the ship collides with an asteroid. Once all the shields are gone, then the ship will explode.
Many games have some kind of health bar for the player's character — when the health reaches zero, the player dies in the game. The shields that we're going to add to our game are just a health bar for the spaceship.
Phaser has built-in properties and methods to keep track of the health of a sprite. When a sprite's health reaches zero, Phaser will automatically kill()
the sprite.
health
is the property that represents a sprite's health value. You can set it to any value (but many game designers use 100
as the starting value for a sprite's health).
maxHealth
is a property that sets a maximum value for the sprite's health. You can set this to any value (but many game designers also use 100
for the maximum value). If your game has ways for the sprite's health to increase (e.g., by collecting health packs, resting, etc.), this will prevent the health from exceeding this limit.
damage()
is a method to decrease a sprite's health value. Inside the parentheses, you include a value representing the amount of damage.
heal()
is a method to increase a sprite's health value. Inside the parentheses, you include a value representing the amount of healing.
Add this Phaser code in your create()
function (after the command that set the angle of the player):
This will set the starting value of the player's health to 100 (and also set 100 as the maximum value).
Instead of killing the player
sprite when it collides with an asteroid, let's damage the player's health by 25. After 4 collisions, the player's health will be zero, and Phaser will automatically kill()
the player
sprite.
In your collideAsteriod()
function, replace the command that kills the player with this command instead:
Refresh your HTML preview to verify that it takes 4 collisions with asteroids before the spaceship explodes.
Now we just need to add a health bar, so the player has some visual feedback to track the amount of "shields" remaining for their spaceship.
Typically, a health bar is a rectangle that decreases (or increases) in width (or height) to represent the amount of health remaining. An easy way to do this in Phaser is to scale an image of a rectangle in one direction (either its width or its height).
We're going to use images of a red rectangle and a green rectangle to create our health bar:
Notice that these two bars are the exact same size. We're going to position them on top of each other as layers, so the red bar is behind the green bar.
The width of the green bar will represent the amount of health ("shields") remaining. When the shields are at maximum, the green bar will completely cover and hide the red bar.
When the player's health is damaged, we will scale down the width of the green bar, which will also reveal some of the red bar behind it. This will make it easier for the player to quickly see how much or how little health is remaining.
Let's first add a text label for the health bar (so it will be clear to the player what this bar represents):
Add a global variable for healthText
In your create()
function (after the code that added scoreText
), add healthText
as a text object at position 210, 20
. Set the text to display: 'Shields'
. Use the same font styling that you used for scoreText
(Arial, 20px, bold, #ffffff)
You do not need to set the text's anchor or add a text shadow.
Refresh your HTML preview to verify that the text label (Shields) appears at the top of the game to the right of the score.
We're going to add the red and green bars to the game as images instead of as sprites.
Add a global variable for healthBar
, which will represent the image of the green bar (we don't need to create a variable for the red bar)
Preload assets/images/health-red.png as the image for the red bar. Assign it a unique asset key name, such as red-bar
. (Hint: If you need help, look back at Step 4 to see how to preload an image.)
Preload assets/images/health-green.png as the image for the green bar. Assign it a unique asset key name, such as green-bar
.
Add this Phaser command in your create()
function (after the code that added healthText
):
This command does just what you think — it adds an image at position 300, 20
using the red-bar
asset. Because we're not going to scale or change the red bar in any way, we don't have to assign it to a variable — we can just add it to the game.
Refresh your HTML preview to verify that the red bar appears at the top of the game to the right of the "Shields" text.
Now add this Phaser command (immediately after the command that added the red bar):
This command adds the green bar at the exact same position and assigns it to the healthBar
variable (so that we can scale the green bar when the health value changes).
Because you added the red bar first and then added the green bar, the green bar will be layered on top of the red bar.
Refresh your HTML preview to verify that the green bar appears at the top of the game (and hides the red bar, which is actually behind it).
Now we just need to scale the width of the green bar, so it will shrink to represent the decrease in the player's health.
Phaser has a scale
property for game objects (such as: text, images, sprites, etc.) that allows you to scale the object's width and height to make the object larger or smaller.
To shrink the width or height, use a scale value that is between 0 and 1.
To enlarge the width or height, use a scale value that is greater than 1.
To keep the width or height the same size, use a scale value of exactly 1.
For our health bar, we only want to change the width of the green bar. We'll keep the height of the green bar the same size.
We can calculate the scale needed for the width of the healthBar
by using a simple fraction — the scale should be the player's current health value divided by its maximum possible health value.
For example, if the player's health is currently 25 and its maximum health value is 100, the scale for the width of the health bar should be 0.25 (25/100), which would look like this:
Add this Phaser command inside your collideAsteroid()
function (immediately after the command that damages the player):
This command sets the scale values for the width and height (in order) of the healthbar
image. The scale for the width will be calculated by dividing the player's health by its maximum health. The scale for the height will be kept at 1, so the height of the image doesn't change.
Refresh your HTML preview to verify that the width of the green health bar shrinks in proportion to the damage from each collision.
In our case, each collision should shrink the width of the health bar by 25% of its original width until it reaches zero (100 → 75 → 50 → 25 → 0). When the shields reach zero, the spaceship will explode.
Some games only give the player one life during the game — when the player's character is killed, the game is over. Other games give the player unlimited lives, allowing the player to restart the game again and again (often by sending the player back to a previous checkpoint in the game). Some games give the player a limited number of lives.
The original Asteroids game (like many video games from the 1970s and '80s) gave the player 3 lives at the start of the game. The player could also earn extra lives by reaching certain scores in the game.
We're going to add both of these features to our game. In this step, we'll give the player 3 lives (spaceships) at the start of the game. When the spaceship explodes, the player loses one life — but a new spaceship will appear as long as the player has at least one life left. When the player is out of lives, the game will be over.
Our game will also give the player a chance to earn an extra life as a bonus after every 10,000 score points (10,000 → 20,000 → 30,000 → 40,000, etc.). However, our game will also limit the total number of lives (spaceships) to a maximum of 5 lives.
Our game could just list the number of lives as text on the screen. Instead, we'll show spaceship icons to represent the number of lives. Visually, this will make it easier for the player to see at a glance how many lives remain. It will sort of be like a health bar for the number of lives left.
Here's the image for the number of lives remaining. It shows 5 spaceship icons because that's the maximum number of lives we decided to allow the player to have:
If we were to scale this image, we could make it look larger or smaller — but it would still show 5 spaceships.
So instead of scaling this image, we are going to hide part of it when the number of lives is less than 5.
Phaser has a method called crop()
that allows you to only show part of an image (and hide the rest). You can also change the "crop" later to show less (or more) of the original image. The "crop" can be changed or reversed whenever you need because it doesn't actually alter the original image.
Let's first add a text label for the spaceship icons (so it will be absolutely clear to the player what these icons represent):
Add a global variable for livesText
In your create()
function (after the code that added healthBar
), add livesText
as a text object at position 590, 20
. Set the text to display: 'Ships'
. Use the same font styling that you used for scoreText
and healthText
(Arial, 20px, bold, #ffffff)
You do not need to set the text's anchor or add a text shadow.
Refresh your HTML preview to verify that the text label (Ships) appears at the top of the game to the right of the Shields health bar.
Now you're going to add the spaceship icons to the game as an image:
Add a global variable for livesBar
Preload assets/images/ship-lives.png as the image for the spaceship icons. Assign it a unique asset key name, such as lives
.
Add the image to the game at position 655, 20
and assign it to the livesBar
variable.
Refresh your HTML preview to verify that the 5 spaceship icons appear at the top of the game to the right of the "Ships" text.
Next we're going to start the player with 3 lives and crop the livesBar
to only show 3 spaceships.
In order to crop an image, you create a rectangle of a specified width and height to represent the crop that you want to apply to an image. Then you can crop()
the image using this rectangle. Any part of the original image that is outside of the crop rectangle will be hidden.
The spaceship icons image is similar to a spritesheet containing frames. The image has 5 identical spaceship icons, which are each 25 pixels in width and 25 pixels in height (including the transparent area around each icon). The entire image is 125 pixels in width and 25 pixels in height.
So we can set the width of the crop rectangle based on how many lives the player has left. For example, if the player has 3 lives left, then the crop rectangle should be set to a width of 75 pixels (3×25).
We want the height of the crop rectangle to be the same as the height of the spaceship icons image (which is 25 pixels in height).
Add these variables to your code:
Add a global variable named shipLives
and assign it an initial value of 3
Add a global variable called livesCrop
to represent the crop rectangle
Add this Phaser code to your create()
function (after the command that added livesBar
):
Let's examine this code:
The first line of code creates a rectangle that you'll use for the crop. 0, 0
represent the position of the top-left corner of the crop rectangle (relative to the top-left corner of the image that it will crop). The next two numbers represent the width and height (in order) of the rectangle: shipLives * 25
is the width, and 25
is the height.
The second line applies the crop for the livesBar
image using the livesCrop
rectangle.
Refresh your HTML preview to verify that the only 3 spaceship icons appear at the top of the game.
Now we need to actually change the number of shipLives
every time the player's spaceship is destroyed. Then we will want to re-crop the livesBar
using a new width (based on how many lives remain).
As a reminder, in your create()
function, you added an event that will run a function whenever the player
is killed. This is where your game resets the explosion
sprite and plays its animation. Now you're going to add some more code inside this event function to change the number of lives remaining and adjust the crop for the livesBar
.
Add Phaser commands in your player.events.onKilled
function to do the following (in order):
Decrease the value of shipLives
by 1
Change the width of livesCrop
by calculating its new value: livesBar.width = shipLives * 25;
Apply the crop for livesBar
using the livesCrop
rectangle
Refresh your HTML preview to verify that only 2 spaceship icons will be shown after the spaceship is destroyed.
Now we need to respawn the player's spaceship if the player still has lives yet. We can use an if-else statement to determine if the number of lives left is greater than zero (otherwise the game is over).
Add this Phaser code in your player.events.onKilled
function (after the code that updated the crop for livesBar
):
If the player still has at least one life left, this code will:
position the player
sprite back at the center of the game with the spaceship pointing up (-90° angle)
sets the player
sprite's velocity and acceleration to zero
brings the player
sprite back to life with maximum health using the revive()
method (alternatively, we could have used the reset()
method)
fades the player
sprite into view using a to
tween on the sprite's alpha
property (2000
means the tween will take 2 seconds to complete)
Otherwise, the player has zero lives left, which means the game is over. In Step 14, we'll add some code to run when the game's over.
Refresh your HTML preview to verify that a new spaceship will appear after the spaceship is destroyed. After 3 spaceships have been destroyed, the game should be over.
Let's add some audio feedback to make it clear to the player that a new spaceship has appeared.
Add a sound effect that will play one time whenever a new spaceship appears:
Use teleportSound
as the name of the global variable for the sound.
Use assets/sounds/teleport.mp3 for the sound file. Assign a unique asset key name to the sound, such as teleport
.
Add teleportSound
to the game with a volume of 0.5
.
Add a Phaser command to play teleportSound
inside your player.events.onKilled
function (after the code for the tween that fades in the new spaceship).
Refresh your HTML preview to verify that the teleport sound plays whenever a new spaceship appears.
Let's reward the player with an extra life every 10,000 score points (10,000 → 20,000 → 30,000 → 40,000, etc.). However, we will set a limit of 5 lives that the player can have at any point.
If the player already has 5 lives, we'll reward the player by setting the shields (health) back to maximum.
Let's play a sound effect as feedback to the player when either reward is received. We'll also do a visual effect when a new life is awarded.
If the player already has 5 lives and maximum health, then no reward will be given, but the player will get another chance to earn a reward after another 10,000 points.
Add code to your game to do the following:
Add a global variable named maxLives
and assign it a value of 5
Add a global variable named newLife
and assign it an initial value of 10000
Add a global variable named lifeSound
for the sound effect
Preload assets/sounds/extra-life.wav and assign it a unique asset key name, such as life
Add lifeSound
to the game with a volume of 0.5
Now let's plan out the code that we'll need to check to see if the player has earned an extra life reward.
If the player's score
is greater than or equal to newLife
, then the player has earned a reward:
Next we need to check if the number of shipLives
is less than maxLives
. If that's true, we'll give the player an extra life.
Otherwise the player already has the maximum number of lives, so we'll check if the player's health
is less than its maxHealth
. If that's true, we'll set the health back to its maximum.
In either case, we need to increase newLife
by another 10000
points, so the player can earn another reward later.
Let's add the code for this check as a separate function in your game code.
Add a new custom function named checkNewLife()
(after your shootAsteroid()
function).
Add this code inside the curly braces { }
of your checkNewLife()
function:
As you can see, this code will perform the check that we planned out. However, there is some missing code that you'll need to add inside the if-else statements.
Add Phaser commands to award an extra life:
Increase the value of shipLives
by 1
Change the width of livesCrop
by calculating its new value based on shipLives
Set the crop for livesBar
using the livesCrop
rectangle
Update the crop for livesBar
Play lifeSound
Make the game screen flash a bright green color by using this command: game.camera.flash(0x00ff00, 500);
Add Phaser commands to replenish the player's health (if the maximum number of lives is already reached):
Change the value of player.health
to be equal to player.maxHealth
Scale the healthBar
Play lifeSound
Most importantly, we need to call the checkNewLife()
function, in order for it to actually run. We could call this function either inside the shootAsteroid()
function (after the code that increases the score
) OR inside the update()
function (after the collide()
commands is a good spot) — choose just one of those places to call the function with this command:
Refresh your HTML preview to verify that an extra life is awarded when the score reaches 10000 points. Another extra life should be awarded at 20000 points. If possible, verify that the shields will be replenished to maximum if you already have 5 ships when you reach the next new life score.
At this point, you have a working version of Asteroids with lots of features. Now we're going to add a simple "start screen" and "game over screen" to finish it.
At the start of the game, let's show an image of our game's title (Asteroids 2084).
Add code to do the following:
Add a global variable named gameTitle
for the title image.
Preload assets/images/asteroids-2084-title.png for the title image. Assign a unique asset key name to the image, such as title
.
At the end of your create()
function (after the code that added and cropped the livesBar
), add the title image 100 pixels above the game's center, and assign the image to the gameTitle
variable.
Set the title image's anchor to be its center.
Set the scale for the title image to be 0.75
for both its width and height.
Refresh your HTML preview to verify that the game title appears on the screen. Currently, it will remain on-screen during the game, but we'll fix that in a bit.
Let's add a way for the player to start the game when he or she is ready. We'll wait to show the spaceship until the player has pressed the fire key (spacebar). Once the fire key is pressed, we'll remove the game title (and a start instruction) from the screen, show the spaceship, and let the gameplay begin.
Add code to do the following:
Add a global variable named startText
for the start instruction text.
In your create()
function (after the code that added the gameTitle
), add startText
as a text object positioned 200 pixels below the game's center. Set the text to display: 'Press Fire to Start Mission'
. For the font style, use Arial, 30px, bold, #00ff00 (which will make the text slightly larger and bright green).
Set the text's anchor to be its center.
Refresh your HTML preview to verify that the start instruction text appears on the screen. (Just like the game title, it currently remains on-screen during the game, but we'll change that soon.)
Now let's hide the spaceship until the player actually presses the fire key to start the mission.
Add these Phaser commands (inside your create()
function after the code that added the player animation):
This code hides the player
sprite by removing it from the game. Later, your code will add the sprite back into the game by setting the exists
property back to true
.
Refresh your HTML preview to verify that the spaceship no longer appears on the screen.
You probably discovered that pressing the fire key (spacebar) doesn't do anything yet. We're about to change that.
You might have also discovered that pressing the up arrow key will cause the engineSound
to get louder (as if the spaceship were accelerating, except it doesn't exist yet).
Modify your existing if statement for the arrowKey.up
, so it will check whether the arrowKey.up
is being pressed AND the player exists.
Hint: Look at your if statement for the fireKey
as an example of how to do this
Refresh your HTML preview to verify that the engine sound will not get louder if you press the up arrow key when the spaceship is not visible.
Now we want to add a signal that will "start" the game when the player presses the fire key. However, we only want this signal to run one time. Once the game is "started", we want the fire key to fire the spaceship's laser.
Add this Phaser command in your create()
function (after the code that added the fireKey
as a keyboard input):
This command will add a one-time signal to the fireKey
: when this key is pressed down, it will call a custom function named startGame
(which you will need to create).
Add a new custom function named startGame()
(after your checkNewLife()
function).
Add this code inside the curly braces { }
of your startGame()
function:
As you can see, this code adds several to
tweens that change the startText
and gameTitle
. All these tweens use the Phaser.Easing.Cubic.Out
pattern, and true
means the tweens will start automatically (once the startGame()
function is called).
The startText
will fade out (to an alpha value of zero, which is transparent) over 0.25 seconds (250
milliseconds).
The gameTitle
will fade out over 3 seconds but only starts after a 0.25 second delay (the 250
after true
represents a delay value).
At the same time, the gameTitle
will also zoom out over 3 seconds (3000
) by changing the scale of the image to 3 in both directions. This will also only start after a 0.25 second delay.
Now you need to add some missing code in this function to fade in the player
sprite:
Play the teleportSound
(as audio feedback to the player)
Make the player
sprite exist (by changing its exists
property to true
)
Add a to
tween to make the player
sprite fade into view by changing its alpha value to 1
over 2 seconds. Use the Phaser.Easing.Cubic.Out
pattern, and set the tween to start automatically (with no delay).
Refresh your HTML preview to verify that pressing the fire key will "start" the game (fading out the start instruction, fading and zooming out the game title, fading in the spaceship and playing the teleport sound).
Now let's add a simple "game over" screen once the player is out of lives. We'll display some text and allow the player to restart a new game (by pressing the fire key).
Add code to do the following:
Add a global variable named gameOverText
In your create()
function (after the code that added the startText
), add gameOverText
as a text object positioned 100 pixels above the game's center. Set the text to display: 'Game Over'
. For the font style, use Arial, 48px, bold, #ff0000 (which will make the text red).
Set the text's anchor to be its center
Make the text invisible (i.e., transparent) by setting its visible
property to false
Now we need to display the gameOverText
and the startText
when the player has run out of lives.
Add Phaser code in your player.events.onKilled
function (inside the else
curly braces for when the player has no lives left) to do the following:
Make gameOverText
visible
Set the scale for gameOverText
to be 3
for both its width and height
Add a to
tween to make gameOverText
fade into view by changing its alpha value to 1
over 1 second. Use the Phaser.Easing.Cubic.Out
pattern, and set the tween to start automatically (with no delay).
Add a to
tween to make gameOverText.scale
zoom in by changing its value to 1
(for both directions) over 1 second. Use the Phaser.Easing.Cubic.Out
pattern, and set the tween to start automatically (with no delay).
Add a to
tween to make startText
fade into view by changing its alpha value to 1
over 0.5 seconds. Use the Phaser.Easing.Cubic.Out
pattern, and set the tween to start automatically after a 2 second delay.
Refresh your HTML preview to verify that the game over text and start instruction text appear on the screen when the player has run out of lives (game over text should fade and zoom in first, then start instruction should fade in).
Finally, when the game is over, we want to add a signal that will "restart" the game when the player presses the fire key again. However, we only want this signal to run one time.
Add a Phaser command in your player.events.onKilled
function (when the game is over) to create a one-time signal that will call a custom function named restartGame
when the firekey
is pressed.
Add a new custom function named restartGame()
(after your startGame
function).
The restartGame()
function needs to reset some of the game variables (such as: score
, shipLives
, etc.) back to their original values, and then restart the game.
Add code inside the curly braces { }
of your restartGame()
function to do the following:
Change the value of score
back to 0
Change the value of shipLives
back to 3
Change the value of newLife
back to 10000
Change the value of the asteroids' maxSpeed
back to 100
Restart the game state with this command:
Refresh your HTML preview to verify that a new game can be restarted after the current game is over.
Congratulations, you've completed your second practice game! Hopefully, the new Phaser commands made sense — you'll get the chance to use them again in the next practice game.
If you have the time and interest, you can add an enemy spaceship in Step 15. Be forewarned that it will require a lot of additional code, and only a small amount will be provided to you. Luckily, most of the necessary code is similar to things you've already done (so you'll be able to copy and modify portions of your existing game code).
The original Asteroids game had enemy spaceships that would periodically appear and shoot at the player, adding an extra challenge to the game — but rewarding the player with a large score point bonus if the player destroys the enemy.
In this step, you can add an enemy ship to your game. You'll add a timer event to make the enemy ship appear every 30 seconds and move across the screen in a random direction and speed. You'll also add a simple AI (artificial intelligence) to make the enemy aim and shoot at the player.
Adding this enemy ship will involve lots of sub-steps with lots of additional code (but most of it is similar to things you already have in your code). However, adding the enemy ship will be worth it because it really increases the excitement and challenge of the gameplay experience.
Add global variables for the following:
enemy
(enemy spaceship sprite)
enemyLaser
(enemy weapon)
enemyExplosion
(animated explosion sprite for enemy)
enemyFireSound
(sound played when enemy weapon is fired)
enemyAlarmSound
(sound played when enemy is alive)
In your preload()
function, load the following assets:
Load assets/images/enemy-ship.png as a spritesheet, and assign it a unique asset key name, such as enemy-ship
. Each animation frame in this spritesheet is 64 pixels in width and 64 pixels in height.
Load assets/images/enemy-laser.png as an image, and assign it a unique asset key name, such as enemy-bullet
Load assets/sounds/enemy-fire.wav as audio, and assign it a unique asset key name, such as enemy-fire
Load assets/images/alarm.mp3 as audio, and assign it a unique asset key name, such as enemy-alarm
The enemyExplosion
will just use the same spritesheet as the player explosion
does (so your code does not need to load it a second time).
In your create()
function (after the code that added the player
sprite), add code for the enemy
sprite:
Add the enemy
sprite at position 0, 0
(which is a temporary position) using the enemy-ship
asset
Set the sprite's anchor to its center
Enable Arcade Physics for the sprite
Set the sprite's body collision area to be a circle with a radius of 30 pixels that is offset 2 pixels from the left edge of the frame and 2 pixels from the top edge
Have the game automatically kill the sprite when it leaves the game world boundaries by adding this code:
Add an animation to the sprite to play all 3 frames (in order 0-2) at 10 frames per second in a continuous loop
Play the animation (so it will already be playing anytime the enemy
is on-screen)
Hide the sprite (until it is spawned) by setting its exists
property to false
In your create()
function (before the code that adds the enemy
sprite), add code for the enemyLaser
weapon:
Add the enemyLaser
weapon to the game with 5 bullets using the enemy-bullet
asset
Set the bullets to be killed automatically if they leave the camera boundaries
Set the bullet speed to 400
pixels per second
Set the fire rate to 750
(once every 0.75 seconds)
Set the bullet body collision area to be a rectangle 16 pixels in width and 16 pixels in height that is offset 4 pixels from the left edge and 4 pixels from the top edge
After the code that adds the enemy
sprite, add a command to:
Set the enemyLaser
weapon to track the enemy
sprite with no offset but don't track the sprite's rotation (set to false
)
In your create()
function (after the code that adds the explosion
sprite used for the player), add code for the enemyExplosion
sprite:
Add the enemyExplosion
sprite at position 0, 0
(which is a temporary position) using the explosion
asset (same one used for player's explosion)
Set the sprite's anchor to its center
Add an animation to the sprite to play all 16 frames (in order 0-15) at 30 frames per second (with no loop)
Hide the sprite (until it is needed) by setting its visible
property to false
In your create()
function, add code for enemyFireSound
:
Add enemyFireSound
to the game with a volume of 0.5
After the code that adds the enemyLaser
, add an enemyLaser.onFire
function containing a command to play the sound.
You're going to create a custom function to spawn (generate) an enemy spaceship. Later, you'll add a timer to call (run) this custom function every 30 seconds.
Every time a new enemy
is spawned, we want it to appear at a random location along one of the edges of the screen. The enemy
should then move across the screen at a random speed and in a random direction.
After your restartGame()
function, add a new custom function called spawnEnemy()
.
Add this Phaser code inside the curly braces { }
of the function:
The first line of this code checks to see whether the player
sprite exists. If the player hasn't started the game yet or the game is over, player.exists
will be false
. If that's the case, the function will simply return
(i.e., end) without performing the other code in this function.
The rest of the code in this function generates a random number between 1-4 to decide whether the enemy will be spawned from the top, right, bottom, or left of the game screen. Then it generates a random starting position to place the enemy
somewhere along the edge of the screen. It also generates a random velocity to move the enemy
across the screen towards the opposite side (in a straight line). The ranges for the random values have been chosen to keep the enemy
on-screen for several seconds.
The last command brings the enemy
sprite back to life.
In your create()
function, add enemyAlarmSound
to the game with a volume of 0.1
, and set the sound to loop continuously.
In your spawnEnemy()
function, play the sound when the enemy is brought back to life.
In your create()
function (after the code that adds the enemy
), add an enemy.events.onKilled
function containing a command to stop the sound.
We want to add a simple AI (artificial intelligence) to control the enemy
. The enemy
will automatically move across the screen based on the velocity it was given when it was spawned. However, as it moves, we want the enemy
to rotate to face towards the player
, so the enemy
can fire its laser at the player
.
Add this Phaser code in your update()
function (after the code that spawns new asteroids):
When the enemy
exists on-screen, this code will rotate the enemy
sprite to face towards the player
(by calculating the angle between these two sprites). Then it adds a small amount of error to the enemyLaser.fireAngle
. (Otherwise, the enemy is always a perfect shot, making it too difficult for the player to avoid being hit.) Then the enemyLaser
fires towards the direction of the player
. The enemyLaser.fireRate
(which you set in the create()
function) will automatically determine how frequently the enemy actually fires its weapon.
In your create()
function (after the code that adds the enemy
), add this Phaser command:
This command adds a timer event that will run in a loop: Every 30 seconds, it will call (run) the custom function named spawnEnemy
.
Refresh your HTML preview to verify that the enemy will appear once every 30 seconds (from a random edge location - top, right, bottom, or left). As the enemy flies across the screen, it should rotate to face towards the player and fire its weapon. The alarm sound and enemy fire sound should play.
However, at this point, the enemy and its laser bullets don't affect anything else in the game because you haven't added any collisions involving the enemy or its bullets.
In your update()
function, add a collide()
command for player
and enemy
(list in this order) that will call a custom function named collideEnemy
.
At the end of your code, add a new custom function called collideEnemy()
.
Inside the parentheses ( )
after the function's name, list these parameters (in order): player, enemy
Inside the curly braces { }
of the function, add Phaser commands to do the following:
Kill the enemy
Reset enemyExplosion
to the x and y position of the enemy
Play the enemyExplosion
animation
Play boomSound
Shake the game camera
Damage the player
by 25
health points
Scale the player's healthBar
Refresh your HTML preview to verify that the player's spaceship is damaged and the enemy spaceship explodes when they collide.
In your update()
function, add a collide()
command for laser.bullets
and enemy
(list in this order) that will call a custom function named shootEnemy
.
At the end of your code, add a new custom function called shootEnemy()
.
Inside the parentheses ()
after the function's name, list these parameters (in order): bullet, enemy
Inside the curly braces { }
of the function, add Phaser commands to do the following:
Kill the bullet
Kill the enemy
Reset enemyExplosion
to the x and y position of the enemy
Play the enemyExplosion
animation
Play boomSound
Add 2500
to the player's score
Update scoreText
to display the new score
value
Call the checkNewLife()
function (NOTE: This is not needed if a call to checkNewLife()
is already listed in your update()
function)
Refresh your HTML preview to verify that the player's laser can destroy the enemy spaceship, awarding the player 2500 score points.
In your update()
function, add an overlap()
command for player
and enemyLaser.bullets
(list in this order) that will call a custom function named shootPlayer
. As a reminder, overlap()
is similar to collide()
except overlap()
doesn't transfer momentum between the two objects. (If we used a collide()
function here, the enemy's bullets would slow down the player's spaceship or even push it backwards, which seems unnatural.)
At the end of your code, add a new custom function called shootPlayer()
.
Inside the parentheses ()
after the function's name, list these parameters (in order): player, bullet
Inside the curly braces { }
of the function, add Phaser commands to do the following:
Kill the bullet
Play boomSound
Shake the game camera
Damage the player
by 25
health points
Scale the player's healthBar
Refresh your HTML preview to verify that the enemy's laser can damage the player's spaceship.
In your update()
function, add a collide()
command for enemyLaser.bullets
and asteroidGroup
that will call a custom function named removeAsteroid
.
At the end of your code, add a new custom function called removeAsteroid()
.
Inside the parentheses ( )
after the function's name, list these parameters (in order): bullet, asteroid
Inside the curly braces { }
of the function, add Phaser commands to do the following:
Kill the bullet
Set the x and y positions of asteroidParticles
to the x and y positions of the asteroid
Kill the asteroid
Play the explode()
particle effect for asteroidParticles
Play boomSound
Refresh your HTML preview to verify that the enemy's laser will destroy an asteroid if hit.
You might have noticed that we did not add a collision between the enemy
and the asteroidGroup
. This was intentional, so that the player
has to either destroy or avoid the enemy
(rather than letting an asteroid randomly hit and destroy the enemy
). However, if you want, you could add this last type of collision to make the game slightly more realistic. It's your choice.
Congratulations, you've completed everything in Step 15! You should be feeling much more confident about your ability to use Phaser to code a video game.