Subgoals¶
In this lesson we will learn
- how subgoals give players short-term and optional challenges
- how to track a streak and reset it when something goes wrong
- how to use
count_objectto limit how many objects are in a Room - how to write a method that returns a value
- how to make a mistake cost the player progress
Terminology
- return value – the value a method or function sends back to the code that called it.
In Game Design we planned two subgoals for Space Rescue:
| Subgoal | How it works |
|---|---|
| Shoot asteroids without taking damage | - count the asteroids shot in a row (the streak) - reset the streak when the ship loses a life - limit the number of lasers on the screen by the streak |
| Try not to shoot the astronauts | each astronaut we shoot takes one off our rescued count |
Planning¶
The streak¶
The streak is the number of asteroids shot in a row without losing a life. To make the streak worth chasing, it also controls how many lasers can be on the screen at once:
| Streak | Lasers on screen |
|---|---|
| 0 | 1 |
| 1 | 2 |
| 2 | 3 |
| 3 | 4 |
| 4 or more | 5 |
So the rule is: lasers = 1 + streak, but never more than 5.
| Event | Input | Process | Output |
|---|---|---|---|
| Shoot an asteroid | a laser hits an asteroid | add 1 to the streak, play a sound if the laser limit went up | the HUD shows the new streak and laser limit |
| Lose a life | an asteroid hits the unshielded ship | reset the streak to 0 |
the HUD shows a streak of 0 and 1 laser |
| Shoot | the player presses space | count the lasers in the Room; only fire if there are fewer than the limit | a laser fires, or nothing happens |
GameFrame's count_object method counts how many objects of a class are in the Room, so self.room.count_object("Laser") tells us how many lasers are on the screen.
Shooting astronauts¶
Shooting an astronaut already costs 10 points. Now it will also take one off the rescued count, which pushes the player further from the goal. The count can't go below 0.
Track the streak¶
Open GameFrame/Globals.py, add the highlighted code below at the bottom and save it.
| GameFrame/Globals.py | |
|---|---|
Code explanation
- line 55 → creates the
streakcounter, starting at0.
Now we'll add a Streak HUD item that shows the streak and the laser limit. Open Objects/Hud.py, add the highlighted code below at the bottom and save it.
Code explanation
- line 77 → defines the
Streakclass as a subclass ofTextObject. - lines 78–80 → a docstring that explains what the class is for.
- line 81 → defines the
__init__method. - lines 82–84 → a docstring that explains what the method does.
- line 85 → runs
TextObject's__init__method. - lines 88–90 → set the font size, font and colour.
- line 91 → draws the text for the first time.
- line 93 → defines the
max_lasersmethod. - lines 94–96 → a docstring that explains what the method does.
- line 97 → returns the laser limit:
1 + Globals.streak, butminpicks the smaller of that and5, so it never goes above 5. - line 99 → defines the
update_streakmethod. - lines 100–102 → a docstring that explains what the method does.
- line 103 → builds the text with an f-string, calling
max_lasersto get the laser limit. - line 104 → redraws the text on the screen.
Methods that return a value
Most of our methods do something, like moving or deleting an object. max_lasers returns a value instead, so other code can ask for it: self.room.streak.max_lasers(). Keeping the rule in one method means the HUD and the Ship always agree about the limit.
Open Objects/__init__.py, change the highlighted code below and save it.
Code explanation
- line 7 → imports the
Streakclass as well.
Open Rooms/GamePlay.py, add the highlighted code below and save it.
Code explanation
- line 4 → imports the
Streakclass. - line 26 → creates a Streak counter in the bottom-right corner, and stores it in
self.streakso other objects can use it. - line 27 → adds the counter to the Room.
- line 38 → loads the sound for the laser limit going up.
Use the streak¶
Limit the lasers¶
Open Objects/Ship.py, change the highlighted code below in shoot_laser and save it.
Code explanation
- line 60 → asks the Streak counter for the current laser limit.
- line 61 → only fires if the ship can shoot and there are fewer lasers in the Room than the limit.
Build the streak¶
Open Objects/Laser.py, add the highlighted code below and save it.
Code explanation
- line 48 → adds 1 to the streak when a laser hits an asteroid.
- line 49 → updates the Streak counter on the screen.
- line 50 → checks if the streak is 4 or less, which means the laser limit just went up…
- line 51 → …and plays a sound to tell the player.
Lose the streak¶
Open Objects/Asteroid.py, add the highlighted code below and save it.
Code explanation
- line 65 → resets the streak to
0when the ship loses a life. - line 66 → updates the Streak counter on the screen.
PRIMM
- Predict how many lasers you can fire at the start of a game, and after shooting three asteroids.
- Run MainController.py and test it. Then let an asteroid hit you.
- Investigate: what happens to the streak when an asteroid hits you while you're shielded? Why?
Don't shoot the astronauts¶
Go back to Objects/Laser.py, add the highlighted code below and save it.
| Objects/Laser.py | |
|---|---|
Code explanation
- line 56 → checks that at least one astronaut has been rescued, so the count can't go below
0… - line 57 → …takes one off the rescued count…
- line 58 → …and updates the Rescued counter on the screen.
Finally, the streak needs to start at 0 in each new game. Open Objects/Title.py, add the highlighted code below and save it.
| Objects/Title.py | |
|---|---|
Code explanation
- line 28 → resets the streak when a new game starts.
PRIMM
- Predict what will happen to the Rescued counter when you shoot an astronaut.
- Run MainController.py and test both subgoals with a testing table.
- Modify: is a maximum of 5 lasers right? Try changing the rule in
max_lasers.
Commit and push¶
- In GitHub Desktop, type Added subgoals in the Summary box.
- Click Commit to main.
- Click Push origin.