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

  1. Open Thonny.
  2. Download the starter via this link, unpack the ZIP and open main.py in Thonny.
  3. Click Run. You see a screen with a player at the bottom, but no bugs and no bullets yet.
  4. 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 there

Step 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:

  1. Easy: make the bugs bigger or faster as the score goes up.
  2. Medium: add a lives system with 3 lives, and when a bug reaches the bottom you lose one.
  3. Hard: write a PantserbBug that needs 3 hits before it dies (use an hp attribute).
  4. 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.


View the cheatsheet for this session