Session 7: Bug Zapper
Bugs fall down from the top. You shoot up to hit them. In this session you learn OOP: you write your first class of your own (Bug), and then two subclasses: one that swings and one that dives at you. Classes are the building blocks of almost every big program.
What you’ll learn today
- Writing a class with
__init__and your own methods - Inheritance: a subclass that extends an existing class
- Keeping track of bullets in a list
- Collision detection between bullets and bugs
Step 0: Setup
- Open Thonny.
- Download the starter via this link, unpack the ZIP and open
main.pyin Thonny. - Click Run. You see a screen with a player at the bottom, but no bugs and no bullets yet.
- Problems? Ask a coach.
Step 1: Spawning bugs and shooting
The Bug class
Find the # STEP 1 — BUG CLASS comment and write:
class Bug:
def __init__(self, x, y):
self.x = x
self.y = y
self.alive = True
def update(self):
self.y += 2 # falls downwards
def draw(self, screen):
pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 15)
# Eyes
pygame.draw.circle(screen, BLACK, (int(self.x) - 5, int(self.y) - 4), 3)
pygame.draw.circle(screen, BLACK, (int(self.x) + 5, int(self.y) - 4), 3)Spawning bugs: the starter already has a timer. Find # SPAWN BUG:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))Shooting: find # SHOOT (this is in the event loop at K_SPACE):
bullets.append(pygame.Rect(player_x - 3, player_y - 20, 6, 12))Update the bullets every frame (find # UPDATE BULLETS):
for b in bullets[:]:
b.y -= 10
if b.y < 0:
bullets.remove(b)
pygame.draw.rect(screen, YELLOW, b) # this is already thereStep 2: ✅ Basic: hitting bugs
Now you write the collision detection: when a bullet hits a bug, the bug dies.
Find # STEP 2 — COLLISION:
for bug in bugs[:]:
bug.update()
bug.draw(screen)
if bug.y > HEIGHT + 20:
bugs.remove(bug)
continue
bug_rect = pygame.Rect(bug.x - 15, bug.y - 15, 30, 30)
for bullet in bullets[:]:
if bullet.colliderect(bug_rect):
bug.alive = False
bullets.remove(bullet)
score += 1
break
if not bug.alive:
bugs.remove(bug)Click Run. Shoot at the bugs: they disappear when you hit them!
Step 3: ⭐ Stretch: SlingerBug
Now you make a subclass: a Bug that swings back and forth.
import math
class SlingerBug(Bug):
def __init__(self, x, y):
super().__init__(x, y)
self.start_x = x
self.timer = 0
def update(self):
self.timer += 0.05
self.x = self.start_x + math.sin(self.timer) * 60
self.y += 1.5 # a bit slower, but harder to hit
def draw(self, screen):
super().draw(screen)
# Orange circle around it as a visual cue
pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), 18, 2)Spawning SlingerBugs: add this to the spawn code (for example every 3rd bug):
if random.random() < 0.3:
bugs.append(SlingerBug(random.randint(30, WIDTH - 30), -20))
else:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))super().__init__(x, y) calls the __init__ of the parent class (Bug), so you don’t have to write self.x, self.y and self.alive again.
Step 4: 🔥 Expert: DuikBug
The DuikBug detects the position of the player and dives straight at it.
class DuikBug(Bug):
def __init__(self, x, y, player_x_ref):
super().__init__(x, y)
self.player_x_ref = player_x_ref # function that gives the current player x
self.speed_x = 0
self.speed_y = 1
def update(self):
target_x = self.player_x_ref()
dx = target_x - self.x
dist = max(abs(dx), 1)
self.x += dx / dist * 2
self.y += 2.5
def draw(self, screen):
super().draw(screen)
pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), 18, 2)Spawning: use a lambda to pass the player x:
bugs.append(DuikBug(random.randint(30, WIDTH - 30), -20, lambda: player_x))Bonus: Draw an HP bar. Start with lives = 3 and take one off when a bug reaches the bottom.
Showcase
Show your game to a coach and a buddy. How many bugs can you zap before your lives run out?
See you next time!
“Next time: an endless highway in the sky, and everything SCROLLS past.”
Take it home
Try one of these extensions at home:
- Easy: make the bugs bigger or faster as the score goes up.
- Medium: add a
livessystem with 3 lives, and when a bug reaches the bottom you lose one. - Hard: write a
PantserbBugthat needs 3 hits before it dies (use anhpattribute). - Very hard: add mouse control: the player moves to the mouse position and shoots automatically every 0.5 seconds.
Stuck? Ask a coach at the next dojo, or just try something else. Programming is doing.
Dojo Defender: Boss
In this session you also keep building on Dojo Defender. You add a boss that shows up every 5 waves with 3 phases.
View the Dojo Defender session 6 for the instructions.
The starter and solution are ready for you.