CS 105 - Exercise Fifteen
Goals
- Incorporate a lot of what you have learned into a simple game
- Practice abstraction, list manipulation, conditionals, loops, message passing, and sound handling
Prerequisite
For this exercise, I have set you up with a starter file that contains the assets for the game.
Objective
You are going to write a little game I am calling Castle Runner.
The game belongs to a genre known as "side scrollers". It is a classic form, where the view scrolls to follow the player's point of view. In our game the scenery will scroll from right to left, and our character will stay centered in our view, providing the appearance that it is running to the right.
Gameplay is very simple. The character is constantly running to the right along the stone walls. As gaps appear, the character has to jump over them. The game is over when the character slips into one of the holes. The score is the number of seconds the character has lasted.
The Runner
When you open the project, you will see there are three sprites: Runner
, Ground
, and Score
. We will start with the Runner
.
We will be making use of another classic game technique: sprite graphics (this is where the "sprites" of Snap! actually come from). The basic idea was that drawing pictures out computationally all the time was time consuming. It is much easier to have a pre-drawn image that is just shown on the screen. However, we usually don't just want a static image, we want our characters to move. So, the solution is to draw the character in lots of different poses, and then flip between them (this should remind you of flip-book animation)
If you open the costume table, you will see that I have added a number of different costumes. If you quickly click through them, you will see that each one is a different running pose. If you click fast enough, it will look like the character is running.
As a side note, I must give credit to "irmirx", who posted these to the OpenGameArt.org forum. If you look around online, you will find a lot of sprite sets. Note that not all of them are copyright free. They are also often in sheets (all in a single image), which is great for how many video games are made, but not so great for us.
Animate the runner
To animate our runner, we just need to cycle through the costumes.
Put inside of a
.
Our little runner really books. Let's slow it down. Add a .1 second wait to the loop. This looks better, but it is doing a weird little stutter because we have images for jump up and come back down in the mix as well. So, we need to do a little refining.
Refinement
To fix this, we want the runner to switch back to the first run pose after the sixth pose, rather than moving on to the jump pose.
We can query the current costume number with from the Sensing palette.
Use the . If the current costume number is 6, then use
to switch to costume 'run1'. Otherwise, advance to the next costume.
Add another above the loop to make sure we start in the right pose.
The runner should be back in business now.
Abstract
Let's add a little abstraction. If you look in the Motion palette, you will find some custom blocks waiting for you. Open up . Drag the blocks you just created out of the
, and into
. Add the
to the
so your script looks like this:
Make sure that the runner is still running away.
Add a to your script so the runner will take off when the
is clicked.
The Ground
Let's turn our attention to the Ground
sprite now.
The idea here is for the walls to steadily move from right to left, with occasional gaps. If you look at the costumes for this sprite, you will see there are three of them, of different sizes.
Here is the algorithm we are going to use
- Place the
Ground
sprite just off-stage on the right so we can't see it - Switch to a random costume
- Create a clone, which will move to the left
- Wait for the clone to get fully on screen, plus some additional amount (for the gap), and repeat the process
Position the sprite
The walls are all set up so that their "position" refers to the upper left hand corner.
Start with a so this script runs when we start.
Use to place the sprite 5 beyond the right edge of the stage. Set the
y
coordinate at -100.
Set the clone behavior
Before we finish with the main script, let's talk about the clones. The clones should drift to the left until they disappear off stage. At which point they should delete themselves.
Pull out the .
Use the .
Inside of the repeat, use to drift the clone to the left. I found -4 to be a good speed.
For the predicate on the loop, check if the right side of the clone (use ) is less than the left side of the stage.
Add after the loop to clean up.
You can test this by clicking the right in the palette. You should see a ground piece sail across the stage and disappear on the other side.
Spawning clones
Now that we have the clone behavior sorted, we can return to the main Ground
script and add some blocks to spawn new clones.
Create a new script variable called clone
(we will want this in a moment).
Add a .
Inside of the loop, set the clone
variable to . Note that unlike
, this block is a reporter. This allows us to refer to this particular clone in our script.
Next, add a . This allows us to pause a script until some condition has been met.
Our condition will be that the right of the clone
is less than the left of "my" left. In other words, the clone is no long overlapping.
If you run the script now, you will see an endless number of blocks emerging from the right and drifting to the left. There is a slight gap between them caused by some vagaries in how the size is determined, but it isn't quite the gap we want. We want something that our runner would have to jump over.
Change the condition so that rather than just being , it is the sprite's left minus a random number between 100 and 150 (use
). You should now see a more significant gap between each sprite.
Switching costumes
To add some more interest, let's switch the costume of the Ground
sprite at random. Add the following to your loop (it doesn't really matter where).
.
Putting it together
If you drag the Runner
down on top of the ground, and click the , the runner will look like it is running along the top of the walls (though it also runs across the gaps -- we will have to fix that).
Jumping and falling
Now it is time to start transforming this into a game.
We want to the runner to run when it is on the ground, and fall when it is not on the ground.
Test if we are on the ground
You will find that there is another custom block in the Operators palette: .
This new block is a reporter that will report either True or False depending on whether or not the runner is "on the ground".
So, how do we tell if the runner is "on the ground"?
We could use to determine if the sprite is on the ground. However, this isn't quite enough. If our character falls between the walls, then it might touch the sides as it goes past, which is not quite the same as being on the ground.
We could also compare the location of the bottom of the runner and the top of the ground. This would avoid the "hitting the sides of the walls on the way down" problem, but would ignore the difference between ground and gaps.
The truth is we need both of these, combined with an .
That extra 20 in the equation is to handle slight variations where the bottom of the sprite is "close enough".
Add an to the loop for the runner. If it is "on the ground", it should step, otherwise do nothing.
Click the and position the sprite so it is just barely overlapping the top of the ground.
It should run when on the wall pieces and pause in the gaps.
Falling
What we want is for the sprite to fall down in the holes.
Go back to the Motion palette and find the .
The behavior for the fall block is pretty simple.
First, switch the costume to "fall".
Second, we want to move down a bit. We will use the this time. Set the secs to .01. Set the x position to
. Finally, set the y position to
- 5.
Add the new block into the else slot in the conditional.
Now, if start the program, the runner should start falling.
Add a and start the sprite at (-100, 200). This should be high enough that the ground should have emerged fall enough to catch it.
You should now see the sprite fall, land on the ground and start running, and then fall again when it reaches the next gap.
Jumping
To keep the sprite out of the pits, we need to be able to jump over them.
Time to implement the .
The is very similar to the
.
First, switch to the 'jump' costume.
Then use the to move up. This time, set the secs to .5 and the y position to
+ 100.
We want the sprite to jump when the user types the Space key.
Add another where the
currently is.
For the condition, use . If the Space bar is pressed, jump, otherwise step.
Adding polish
At this point, we have a playable game... but we can do a little better.
Stopping
Currently, the runner will fall through the gap and disappear, but the game keeps running (we even get a weird effect where the ground speeds over the runner). Let's stop everything when the runner has failed.
Swap out the main for a
.
For the condition, we want to stop the loop when the bottom of the sprite is less than the top of the ground -30 (note the similarity to our detection of when we are on the ground). In other words, if the runner has gotten sufficiently below the top of the ground, it must have fallen off.
Of course, this will just freeze the runner in mid-air.
Why not let the sprite get off screen before we stop? Well, we also want to handle the fact that ground keeps rumbling along even though our runner isn't running any more. So, we need to let the Ground
clones to know that they should stop moving.
So, we will broadcast the message 'stop'.
Then the runner can resume falling. Add another and have the runner keep falling until the top is below the bottom of the stage.
Stop the clones
Of course, we still need to stop the clones.
Return to the Ground
scripts.
Add a to the
Ground
sprite to catch the 'stop' message.
When the 'stop' message is received, the sprite should run the . Set this to stop 'other scripts in sprite'.
Sound
What kind of game doesn't make sounds?
Let's add some. If you look in the Sounds tab of the Runner
, you will see that I have included some sounds (which my son had a lot of fun making).
Step sound
The step sound is the most involved to add.
The sound is designed to approximate the sound of someone in a suit of armor running along a stone wall.
If you look closely at the different costumes, there are only two foot falls, in the first and the fourth poses.
Go back into the . Right before the
, add an
.
If the current costume number is a 1 or it is a 4, play the 'step' sound.
Jump sound
The jump sound is easy. Open up the and play the sound at the start.
Fall sound
The fall sound is similarly easy, but this time we don't want to add it to the . The fall sound isn't for every time the runner is falling, just when it has fallen into a pit. So play this sound right before you broadcast 'stop'.
Scoring
For scoring, we are just counting the number of seconds the runner managed to stay out of the pits. here is what that looks like:
You will also want to add a receiver that stops all scripts when the 'stop' message is received.
What I will be looking for
You made it! That was the longest exercise that we have had, but hopefully one that was worth it.
Here is what we will be looking for:
- The
,
,
, and
are all implemented correctly
- The runner wears the appropriate costume for each activity
- The runner runs on the ground and otherwise falls
- The space bar makes the runner jump
- The ground rolls across continuously
- Everything stops when the runner falls in a pit
- The sounds play at the right time
Submitting
Share the project using the instructions from exercise 1.
Visit the exercise page on Canvas to submit the URL (or the XML file if you saved it locally).