Goals and Rewards¶
In this lesson we will learn
- how to give the player a clear goal and show their progress
- how to reward the player for reaching the goal
- how to make the game harder as the player gets closer to the goal
- how to use an f-string to build text from variables
Terminology
- f-string – a Python string with an
fbefore the quotes that puts the values of variables inside{ }into the text. - robust – describes code that still works correctly when something unexpected happens.
In Game Design we found that Space Rescue has no goal: the player just collects astronauts forever. That means there's no what-if effect and no reason to keep trying. Let's fix that.
Planning¶
Here's what we decided in Game Design:
| The problem | The solution |
|---|---|
| The player doesn't have a goal | set a goal for the number of astronauts rescued |
| The player doesn't know what the goal is | show the number of astronauts to rescue |
| The player doesn't know how close they are | show the number of astronauts rescued |
| The player might reach the goal too quickly | spawn astronauts less often as more are rescued |
| No reward for reaching the goal | give big bonus points for reaching the goal |
So we need:
- two new variables in Globals.py: the goal (
rescue_goal) and the number rescued so far (rescued) - a new HUD item that shows
Rescued: 3 / 10 - code in the Astronaut's ship collision that adds to
rescued, updates the HUD, and checks if the goal is reached - a reward when the goal is reached: 500 bonus points and a sound, then the game ends
- Zork's astronaut timer gets longer as more astronauts are rescued
| Input | Process | Output |
|---|---|---|
| the ship rescues an astronaut | add 1 to rescued and update the HUD; if rescued has reached rescue_goal, add 500 points, play the bonus sound and end the game |
the HUD shows the new count; the player wins when they reach the goal |
Add the goal¶
Open GameFrame/Globals.py, add the highlighted code below at the bottom and save it.
| GameFrame/Globals.py | |
|---|---|
Code explanation
- line 51 → sets the goal: rescue 10 astronauts.
- line 52 → counts the astronauts rescued so far, starting at
0.
Show the progress¶
We'll add a Rescued class to the HUD. It's a TextObject, like the Score. Open Objects/Hud.py, add the highlighted code below to the bottom and save it.
Code explanation
- line 53 → defines the
Rescuedclass as a subclass ofTextObject. - lines 54–56 → a docstring that explains what the class is for.
- line 57 → defines the
__init__method. UnlikeScore, it doesn't take any text, because it builds its own. - lines 58–60 → a docstring that explains what the method does.
- line 61 → runs
TextObject's__init__method. - lines 64–66 → set the font size, font and colour.
- line 67 → calls
update_rescuedto draw the text for the first time. - line 69 → defines the
update_rescuedmethod. - lines 70–72 → a docstring that explains what the method does.
- line 73 → builds the text with an f-string, which puts the values of
Globals.rescuedandGlobals.rescue_goalinside the{ }, for exampleRescued: 3 / 10. - line 74 → redraws the text on the screen.
Open Objects/__init__.py, change the highlighted code below and save it.
| Objects/__init__.py | |
|---|---|
Code explanation
- line 7 → imports the
Rescuedclass as well asScoreandLives.
Open Rooms/GamePlay.py, add the highlighted code below and save it.
Code explanation
- line 4 → imports the
Rescuedclass. - line 24 → creates a Rescued counter in the bottom-left corner of the screen, and stores it in
self.rescuedso the astronauts can update it. - line 25 → adds the counter to the Room.
- line 33 → loads the bonus sound for reaching the goal.
Count rescues and reward the goal¶
Open Objects/Astronaut.py, add the highlighted code below and save it.
Code explanation
- line 1 → imports
Globals, so the astronaut can update the rescued count. - line 41 → adds 1 to the number of astronauts rescued.
- line 42 → updates the counter on the screen.
- line 43 → checks if the player has reached the goal…
- line 44 → …plays the bonus sound…
- line 45 → …adds 500 bonus points…
- line 46 → …and ends the GamePlay Room, so the game goes back to the welcome screen.
Why >= and not ==?
Globals.rescued should never jump past the goal, so == would work too. But using >= means the game still ends if something unexpected pushes the count past the goal. It's a small habit that makes code more robust.
The rescued count needs to start at 0 in every new game, just like the score and lives. Open Objects/Title.py, add the highlighted code below and save it.
| Objects/Title.py | |
|---|---|
Code explanation
- line 27 → resets the rescued count to
0when a new game starts.
PRIMM
- Predict what will happen when you rescue the tenth astronaut.
- Run MainController.py and rescue ten astronauts.
- Investigate: change
rescue_goalto3to test it faster. Change it back when you're done.
Make the goal harder to reach¶
To make the what-if effect stronger, astronauts should appear less often as the player gets closer to the goal. We'll add 20 ticks to Zork's astronaut timer for every astronaut rescued. Open Objects/Zork.py, change the highlighted code below and save it.
Code explanation
- line 29 → adds
Globals.rescued * 20ticks to the first astronaut's timer. At the start of a gamerescuedis0, so nothing changes. - line 66 → adds the same extra time when choosing when the next astronaut appears. After 9 rescues, astronauts take up to 180 ticks (6 seconds) longer to appear.
PRIMM
- Predict how the game will feel near the end now.
- Run MainController.py and play a whole game.
- Modify: is 20 ticks too much or too little? Change it until the end of the game feels tense but fair.
Commit and push¶
- In GitHub Desktop, type Added rescue goal in the Summary box.
- Click Commit to main.
- Click Push origin.