P3: Steps 6-10
Be sure that you completed Coding Steps 1-5 on the previous page.
IMPORTANT: Take the time to read each step, and try to understand how the code works.
Step 6: Add Enemy and Health Bar
This game will feature a group of cats as an "enemy". Cats are normally great companions, but these cats don't want to be your friend. If the player touches a cat, the player's health will be reduced.
Add Group for Cats
Declare a global variable named:
catGroup
(will contain all the cat objects)
In your preload()
function, load the spritesheet for the cats:
Load assets/images/cat.png as a spritesheet. Use
'cat'
as the asset key. The image contains 4 animation frames in a single row. The entire image is 128 pixels in width and 32 pixels in height. Use this information to determine the width and height of each frame.
In your create()
function, add code to do the following (after the code that adds the coins, but before the code that adds the player sprite):
Add
catGroup
to the gameEnable physics for all members of
catGroup
Add Cats to Group using For Loop
Rather than placing the cats at specific locations, we're just going to space the cats evenly across the top of the game world, give them a random velocity, and let them drop down onto the platforms.
An easy way to do this is to just use a for
loop (similar to how you added the coins but without using JSON data for the positions).
Add this code to your create()
function (after the command that enabled physics for catGroup
):
This for
loop will create 25 cats in the catGroup
. There is some missing code that you'll add in a bit.
The x-position for each cat will be calculated as: i * 200 + 100
. This will place the cats 200 pixels apart, with the first cat positioned at 100:
The x-position for the first cat (
i = 0
) will be 100 because0 * 200 + 100 = 100
The x-position for the next cat (
i = 1
) will be 300 because1 * 200 + 100 = 300
The x-position for the next cat (
i = 2
) will be 500 because2 * 200 + 100 = 500
The x-position for the next cat (
i = 3
) will be 700 because3 * 200 + 100 = 700
and so on...
The y-position for each cat will be 0
(the top of the game display).
Refresh your HTML preview to verify that the 25 cats appear evenly spaced apart along the top of the game.
Add Physics Properties and Animation to Cats
Now you'll add the missing code inside the for
loop to give each cat some physics properties and an animation.
Inside your for
loop (after the command that creates the cat in the catGroup
), add code to do the following for each cat
:
Set the anchor for
cat
to be its center (0.5, 0.5
)Set its
body.gravity.y
to300
Set its
body.bounce.x
to1
Set its
body.collideWorldBounds
totrue
Add an animation named
'left'
that will play frames 0-1 (in order) at 10 frames per second in a loopAdd an animation named
'right'
that will play frames 2-3 (in order) at 10 frames per second in a loopAdd this code to give each cat a random velocity (and a 50% chance of having its direction reversed):
Next, you need to make sure the cats collide with the platforms and walls, similar to what you did for the player and coins.
In your update()
function (after the collide()
statements for the player
), add code to do the following:
Make
catGroup
andplatformGroup
collide with each otherMake
catGroup
andwallGroup
collide with each other
You'll also add some code to make sure each cat plays the correct animation based on its direction of movement (which will change as the cats bounce off the walls and game boundaries).
Add this code in your update()
function (after the code that added the background parallax):
This function will check the velocity of each cat in the catGroup
. If the cat's velocity is less than zero, that means the cat is moving to the left. Otherwise, the cat is moving to the right.
Refresh your HTML preview to verify that the cats fall down. The cats should move at different speeds and should collide with the platforms and walls. If a cat collides with a wall or a game boundary, the cat should reverse direction. The cats should play the correct animation as they move and change direction.
Add Patrol Behavior for Cats on Platforms
For this game, we're going to add a simple AI (artificial intelligence) for the cats: if a cat is on a platform, then it will patrol back and forth on the platform (instead of running off the edge).
We'll add this behavior using a custom function that will run whenever a cat is on top of a platform (i.e., colliding with the platform).
Modify your existing collide()
command for the catGroup
and platformGroup
:
When a collision occurs, it should call a custom function named
patrolPlatform
.
Add this code after your update()
function to create the custom function :
The patrolPlatform()
function checks for two possible conditions:
The
enemy
is moving to the right (velocity.x > 0
) AND the right edge of theenemy
sprite is hanging over the right edge of theplatform
spriteOR
The
enemy
is moving to the left (velocity.x < 0
) AND the left edge of theenemy
sprite is hanging over the left edge of theplatform
sprite
If either of those conditions is true, then the function simply reverses the direction of the enemy
by multiplying its velocity.x
by -1
. For example, if the velocity.x
was -125 (moving to the left), it would become 125 (moving to the right).
Refresh your HTML preview to verify that any cats landing on a platform will patrol back and forth on the platform. Even cats on the ground (which is also a platform) should patrol back and forth.
Add Player Health Bar
If the player's character touches a cat, the player will have its health reduced slightly. So let's first add a health bar for the player.
Declare a global variable named:
healthBar
(green bar that will be scaled to represent health value)
In your preload()
function, load these images for the health bar:
Load assets/images/bar-red.png with
'red-bar'
as its asset keyLoad assets/images/bar-green.png with
'green-bar'
as its asset keyLoad assets/images/bar-outline.png with
'bar-outline'
as its asset key
In your create()
function (after the code that adds the player
sprite), add commands to do the following:
Set the
health
property for theplayer
to100
Set the
maxHealth
property for theplayer
to100
In your create()
function (after the code that adds scoreText
), add code to do the following:
Declare a local variable named
healthText
that adds text to the game with these properties:To declare a local variable, just list
var
in front of the variable nameThe text should be positioned at:
325, 20
The text should display:
'Health'
The text should use this style:
{ fontSize: '20px', fill: '#222222' }
Make
healthText
stay fixed to the camera (so it doesn't move when the game world scrolls)Declare local variables named
barBackground
andbarOutline
, like this:var barBackground, barOutline;
Add an image assigned to
barBackground
at position400, 20
using the'red-bar'
assetMake
barBackground
stay fixed to the cameraAdd an image assigned to
healthBar
at position400, 20
using the'green-bar'
assetMake
healthBar
stay fixed to the cameraAdd an image assigned to
barOutline
at position400, 20
using the'bar-outline'
assetMake
barOutline
stay fixed to the camera
Refresh your HTML preview to verify that the health bar appears at the top center of the game. The bar should be green with a dark gray outline. (Remember that the red bar background is currently hidden because it is covered by the green bar.)
Add Cat Sound
Let's add a sound for the cats that will play whenever the player touches a cat.
Declare a global variable named:
catSound
In your preload()
function, load the audio file for the sound:
Load assets/sounds/meow.wav with
'cat-sound'
as its asset key
In your create()
function, add the sound to the game:
Add
catSound
to the game as audio using the'cat-sound'
asset with a volume of0.2
Add Custom Function When Player Touches Cat
Now let's detect when the player touches a cat. Besides reducing the player's health, we'll play the cat sound and also make the cat jump away from the player.
Rather than using a collide()
method to detect when the player touches a cat, we'll use an overlap()
method. They both detect when objects touch. However, collide()
also allows moving objects to transfer momentum, so if we used a collide()
method, then the cats would speed up every time they touch the player.
In your update()
function (after the collide()
method between the catGroup
and platformGroup
), add the following:
Add a
overlap()
method betweenplayer
andcatGroup
(list in this order) that will call a custom function namedtouchCat
After your update()
function, add the following:
Add a new custom function named
touchCat()
. Inside the parentheses( )
, listplayer, cat
as parameters.
Inside the curly braces { }
of your touchCat()
function, add code to do the following:
Reverse the direction of the
cat
by multiplying itsbody.velocity.x
by-1
Make the
cat
jump by setting itsbody.velocity.y
to-150
Move the cat away from the player by changing its x-position with this code:
Play the
catSound
Reduce the
player
health by5
using thedamage()
methodScale the width of the
healthBar
to be:player.health / player.maxHealth
(keep the scale for the height as1
).
If you need help with the code for scaling the health bar, look back at Step 11 of Practice 2.
Refresh your HTML preview to verify that the player's health bar is reduced when the player touches one of the cats. The cat should reverse direction and jump away from the player. You should hear the cat sound play when this happens.
Reset Player to Start When Killed
If the player runs out of health, Phaser will automatically kill()
the sprite. When that happens, let's reset the player's character back at the beginning of the level.
In your create()
function (after the code that adds the player
), add code to do the following:
Add an
onKilled
event for theplayer
that will run a function.
If you need help with the code for adding an onKilled
event, look back at Step 6 of Practice 2.
Inside the curly braces { }
of the onKilled
event function, add commands to do the following:
Reset the
player
back to position25, 300
with a health value of100
using this command:Scale the width of the
healthBar
Refresh your HTML preview to verify that when the character's health runs out, the player is reset back to the start of the level with full health.
Step 7: Add Power-Up with Timer
Next we're going to add some "power-up" objects to the game that will temporarily boost the player's running and jumping speeds. We'll use a star as the power-up object. We'll set a timer to control how long the power-up works.
Add Power-Up Group
Declare a global variable named:
powerUpGroup
(will contain all the power-up objects)powerUpActive
and assign it an initial value offalse
In your preload()
function, load this image for the power-up:
Load assets/images/star.png with
'star'
as its asset key
In your create()
function (after the code that adds the coinGroup
), add commands to do the following:
Add
powerUpGroup
to the game as a groupEnable physics for the members of
powerUpGroup
Create a member of
powerUpGroup
at position1000, 200
using the'star'
assetCreate a member of
powerUpGroup
at position3000, 400
using the'star'
assetSet all the members of
powerUpGroup
to have their'anchor.set'
property set to a value of0.5
Refresh your HTML preview to verify that the star objects appear in the game at correct positions. They should be floating in mid-air (since you didn't add any gravity to them).
Add Message Text
When the player collects a star, we'll display a message on the screen while the power boost is active (and then hide the message after the power-up timer has run out).
So let's add a blank text object to the game that we can use later to display a message to the player. We'll also use this same text object for a different message in Step 8.
Declare a global variable named:
messageText
(will be used to display text)
In your create()
function, add code to the following:
Add
messageText
to the game as text with these properties:Position the text at:
500, 100
Have the text display nothing for now (use empty quotes):
''
Style the text using:
{ fontSize: '48px' }
Set the text anchor position to be its center:
(0.5)
Set a shadow for the text using these properties:
(2, 2, '#000000', 2)
Make the text stay fixed to the camera
Hide the text by setting its
visible
property tofalse
Add Custom Function With Timer When Player Collects Power-Up
Now let's detect when the player touches a star. This is when we'll start the power boost. We'll display a message on the screen, change the player's character to a green color, and start a 10-second timer. While the power-up is active, we'll increase the player's running and jumping speeds. When the timer runs out, we'll change everything back to normal.
In your update()
function (after the collide()
method between the player
and coinGroup
), add the following:
Add a
collide()
method betweenplayer
andpowerUpGroup
(list in this order) that will call a custom function namedcollectPowerUp
After your update()
function, add the following:
Add a new custom function named
collectPowerUp()
. Inside the parentheses( )
, listplayer, powerUp
as parameters.
Inside the curly braces { }
of your collectPowerUp()
function, add code to do the following:
Remove the
powerUp
object (the star) using thekill()
methodChange the value of
powerUpActive
totrue
Set the
text
property ofmessageText
to display'Power Boost'
Set the
fill
color formessageText
to be green using:'#00ff00'
Make
messageText
visibleChange the
player
sprite to a green color by setting itstint
property to0x00ff00
Use this command to start a timer event that will run a custom function named
stopPowerUp
after 10 seconds have elapsed:
Before we forget, let's add this custom function that will stop the power-up.
Add another new custom function named stopPowerUp()
. Inside the curly braces { }
of this function, add code to do the following:
Change
powerUpActive
tofalse
Hide
messageText
by changing itsvisible
propertyRemove the green color from the
player
by setting itstint
to0xffffff
(represents no tint)
We haven't added the code to change the player's speed yet, but let's test out what we've added so far.
Refresh your HTML preview to verify that the "Power Boost" message appears when the player collects a power-up star. The player should turn a green tint. The player's speed will still be normal (because we haven't added that code yet). After 10 seconds, the message should disappear and the player should turn back to normal.
Increase Player's Speed While Power-Up is Active
Now we're ready to add the code to increase the player's running and jumping speeds while the power-up is active.
We'll use the value of powerUpActive
to detect when the power-up is supposed to be active. If powerUpActive
is true
, we'll use a larger value for the velocity that makes the player run or jump. Let's increase the velocity by 50% (e.g., if the normal running speed is 200
, we'll boost to 300
).
So we'll modify the existing code in the update()
function that detect the player's input. Inside those if-else statements , we'll add local variables to represent the normal values for runSpeed
and jumpSpeed
. If powerUpActive
is true
, we'll increase the values of these variables.
Modify your existing if-else statements in the update()
function that check the player input, so the code looks like this:
Refresh your HTML preview to verify that the player's running and jumping speeds are boosted while the power-up is active.
Step 8: Add Countdown Timer for Game Over
Next let's add to the challenge of the game by adding a countdown timer for the player to complete the level. Instead of displaying the time as text, we'll add a timer bar that decreases to show the amount of time remaining. Let's give the player 2 minutes (120 seconds) to complete the level.
Add Time Bar
Declare a global variable named:
timeBar
(yellow bar that will be scaled to represent amount of time remnaining)timeUp
and assign it an initial value offalse
timeLimit
and assign it an initial value of120
(which represents the number of seconds)
In your preload()
function, load these images for the health bar:
Load assets/images/bar-black.png with
'black-bar'
as its asset keyLoad assets/images/bar-yellow.png with
'yellow-bar'
as its asset key
In your create()
function (after the code that adds barBackground
, healthBar
, and barOutline
), add code to do the following:
Declare a local variable named
timeText
that adds text to the game with these properties:To declare a local variable, just list
var
in front of the variable nameThe text should be positioned at:
720, 20
The text should display:
'Time'
The text should use this style:
{ fontSize: '20px', fill: '#222222' }
Make
timeText
stay fixed to the cameraAdd an image assigned to
barBackground
at position780, 20
using the'black-bar'
assetMake
'barBackground
stay fixed to the cameraAdd an image assigned to
timeBar
at position780, 20
using the'yellow-bar'
assetMake
'timeBar
stay fixed to the cameraAdd an image assigned to
barOutline
at position780, 20
using the'bar-outline'
assetMake
'barOutline
stay fixed to the camera
Refresh your HTML preview to verify that the time bar appears at the top center of the game. The bar should be yellow with a dark gray outline. (The black bar background is currently hidden because it is covered by the yellow bar.)
Add Custom Function to Update Time Bar
Now let's add a custom function to determine how much time has elapsed in the game and use that to update the time bar to show how much time is remaining.
Luckily, Phaser has a built-in method called game.time.totalElapsedSeconds()
to calculate how much time (in seconds) has elapsed since the game started.
So we can just subtract the game's elapsed time from the timeLimit
to determine how much time is left over. We can then use this result to scale the timeBar
.
In your update()
function, add this as the first line of code inside the curly braces (before any of the collide()
methods):
This will run a custom function named displayTimeLeft()
as the first step every time the update()
loop occurs.
After your update()
function, add this code to create the custom function:
Notice that we had to detect if the value of timeLeft
was less than zero. If so, we set to be exactly zero. Otherwise, if we didn't do that, the timeBar
would scale to show negative timeLeft
(the yellow bar would actually start expanding outside of its outline). We also use this to detect when to set the value of timeUp
to true
.
Also notice that you scale the timeBar
similar to how you scale the healthBar
. For the timeBar
, you divide the timeLeft
by the timeLimit
to get the proportion of time remaining. For example, if only 30 seconds remain out of a 120-second time limit, then the timeBar
should be scaled to 0.25 of its original width (30 / 120 = 0.25).
Refresh your HTML preview to verify that the yellow time bar decreases in width to show the time remaining in the game until it reaches zero (time bar will be completely black).
Add Custom Function for Game Over When Time Runs Out
Now let's add a "game over" function that will run when the time limit for the game is over. We can use the value of timeUp
to detect when this has occurred.
When timeUp
is true
, we want to display a game over message to the player, and make the player
sprite disappear (so the game is effectively over).
Modify the first line of code inside your update()
function, so it looks like this instead:
Now if timeUp
is true
, it will run the custom function named gameOver()
. Otherwise (when timeUp
is false
), it will run the custom function displayTimeLeft()
.
Next you need to add the gameOver()
function.
After your update()
function, add a new custom function named gameOver()
. Inside the curly braces { }
of this function, add code to do the following:
Set the
text
property ofmessageText
to display'Time Up'
Set the
fill
color formessageText
to be red using:'#ff0000'
Make
messageText
visibleMake the
player
sprite disappear by setting itsexists
property tofalse
Notice that instead of using the kill()
method to remove the player
sprite, we simply set its exists
property to false
. The reason for this is because we previously added an onKilled
event for the player
(when its health runs out) that resets the sprite back to the beginning of the game with full health. However, when the time limit runs out, we want the game to be completely over, so that's why we used the exists
property instead of the kill()
method. Both of them remove the player, but we want to avoid triggering the onKilled
event in this situation.
Refresh your HTML preview to verify that "Time Up" message appears and the player disappears when time runs out.
Step 9: Create Your Own Design for Rest of Level
What you’ve made so far is a partial game. Now it's up to you to design and build the rest of the level.
In this step, you’ll create of a map of your design for the complete level. In Steps 10-15, you’ll implement your design and playtest it.
Use this graph paper to create a scale map of the complete game level showing the size and location of all the objects (including new objects you’ll add in Steps 10-12), such as platforms, walls, coins, etc.
A recommended scale for the graph is to have each square represent either 20 or 25 pixels (choose one). Use the same scale for both the horizontal and vertical axes of the graph.
You will probably need to split up your level map into multiple sections (either on the same graph sheet or across multiple sheets).
Mark and label your horizontal and vertical scales for your game world on the graph. Unless you've changed it, your game world is 5000 pixels in width and 600 pixels in height.
The x-positions start with 0 as the left edge of the game world, and they increase as you move towards the right edge.
The y-positions start with 0 as the top edge of the game world, and they increase as you move towards the bottom edge.
OPTIONAL: If desired, you can reduce the width of the game world from 5000 pixels to a smaller size (but make it at least 3000 pixels wide). The existing platforms are placed within the first 1500 pixels of the game world.
Include the size and locations of the existing platforms, walls, and other objects (coins, etc.) in your level map. (If desired, you can change the size and/or locations of these existing objects.)
For the platforms and walls, the position at which they were created represents their top-left corner (since we didn't change the default anchor position for these objects).
As a reminder, all the platforms are 25 pixels in height. The width of the platforms range from 50 pixels to 500 pixels (depending on which platform asset is used).
As a reminder, all the walls are 25 pixels in width. The height of the walls range from 50 pixels to 250 pixels (depending on which wall asset is used).
You do not necessarily need to include the locations of moving objects (cats, etc.) unless it is helpful to you. For example, if you want the player to encounter a "boss" enemy at a certain location, it may help to include that on the map.
Be sure to include the size and locations of the new objects that you plan to add in Steps 10-12.
Partial scale map of level (first 2500 pixels of width) showing starting position of player, size and location of existing platforms and walls, locations of coins (after falling), and location of power-up (star). Next step would be to add new objects, and create rest of map.
RECOMMENDED: Preview the instructions in Steps 10-15 to see more details about what you’ll need to do to complete this practice. Here’s a brief summary:
In Step 10, you’ll add more platforms (and walls) throughout the rest of the level. You need to add at least 10 more platforms. You can modify the size and/or location of any existing platforms or walls (but you don’t have to).
In Step 11, you’ll add a new obstacle that hinders the player in some way, such as a spike, new enemy, etc. You can add an individual obstacle or a group of obstacles.
In Step 12, you’ll add a new resource that helps the player in some way, such as a diamond, health pack, weapon, etc. You can add an individual resource or a group of resources. You'll also add more coins for the player to collect.
In Step 13, you’ll add more sound effects to the game. You’ll use existing sounds from Practice 1 to play a sound effect when the player collects a coin and when the player collects a power-up. Optionally, you create your own sound effects using a web app called ChipTone.
In Step 14, you’ll have the option to create an animated sprite using a web app called Piskel.
In Step 15, you’ll have someone else playtest your game to provide feedback.
Step 10: Add Rest of Platforms and Walls
Add additional platforms (and walls) throughout the rest of the level:
Add at least 10 more platforms to the game. You decide the size and location of the additional platforms (and any additional walls).
OPTIONAL: You can change the size and/or location of any existing platforms or walls.
OPTIONAL: If desired, you can reduce the width of the game world from 5000 pixels to a smaller size (at least 3000 pixels). Refer back to Step 3 to see how to make this change in your code.
OPTIONAL: If desired, you can also reduce the width of the game display from 1000 pixels back to 800 pixels. Refer back to Step 3 for help with the code. However, if you do this, be sure to also:
Change the width of
#my-game
in your CSS file to800px
Adjust the locations of the health bar and time bar to fit within the narrower game display.
IMPORTANT: After adding the rest of the platforms (and walls), playtest your game to ensure the player
can navigate through the platforms and walls to complete the level. If it's not possible to navigate the level, you'll need to do one or both of the following (and then retest your game):
Modify the size and/or location of specific platforms (or walls).
AND / OR
Modify certain properties of the
player
, such as its running speed, jumping speed, gravity, etc.
Steps 11-15 continue on next page
Last updated