Dojo Defender: Sessie 3

Vandaag verhuist Dojo Defender van pgzero naar echte pygame. Geen pgzrun.go() meer — jij schrijft de game loop zelf. Het spel blijft hetzelfde, maar de motor eronder is anders. En aan het einde voeg je GELUID toe.

Wat je vandaag leert

  • Het verschil tussen pgzero en raw pygame
  • De game loop zelf programmeren: while running: clock.tick(60)
  • Actors omzetten naar Surface + Rect
  • Geluid laden en afspelen met pygame.mixer
  • Achtergrondmuziek laten loepen

Stap 0: Download de starter

De starter voor vandaag is een volledige port van Dojo Defender Sessie 2 naar raw pygame. Geen pgzero meer, maar het speelt hetzelfde.

  1. Download de Dojo Defender starter voor vandaag, pak uit en open main.py.
  2. Was je er vorige keer niet bij? Download de oplossing van sessie 2 en probeer die te porten.
  3. Klik op Run. Het spel werkt zoals je gewend bent: schip, asteroïden, kogels, vijanden, waves, explosies.

Wat is er veranderd?

In pgzero schreef je draw() en update() en pgzrun deed de rest. In raw pygame doe je alles zelf:

pgzero (vroeger):

import pgzrun

def draw():
    screen.fill((10, 10, 30))
    ship.draw()

def update():
    if keyboard.left:
        ship.x -= 5

pgzrun.go()

raw pygame (nu):

import pygame, sys
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()

running = True
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        ship.rect.centerx -= 5

    screen.fill((10, 10, 30))
    ship.draw(screen)
    pygame.display.flip()

De belangrijkste verschillen:

pgzeroraw pygame
Actor('plaatje')GameObject('plaatje.png', x, y)
keyboard.leftkeys[pygame.K_LEFT]
on_key_down(key)event.type == pygame.KEYDOWN
screen.draw.text(...)font.render() + screen.blit()
rock.colliderect(ship)rock.rect.colliderect(ship.rect)
pgzrun.go()while running: ... clock.tick(60)

Stap 1: Verken de code

Open main.py en vergelijk met de oude pgzero-code van sessie 2. Zoek deze onderdelen:

  1. Game loop — Zoek de while running:-lus. Zie je clock.tick(60), pygame.display.flip()?
  2. GameObject — Zoek de class GameObject. Hoe wordt een afbeelding geladen? Wat is rect?
  3. Input — Zoek pygame.key.get_pressed() en pygame.KEYDOWN. Hoe werkt de spatiebalk?

Verander de WIDTH naar 1024. Wat gebeurt er? (Alles wordt breder — de game werkt nog steeds.)

Stap 2: ✅ Basic — Voeg restart toe met de R-toets

In de pgzero-versie kon je niet herstarten na game over. Voeg dat nu toe:

# in de event loop, bij KEYDOWN:
if event.key == pygame.K_r and game_over:
    # reset alles
    ship.rect.center = (WIDTH / 2, HEIGHT - 50)
    ship.visible = True
    asteroids.clear()
    bullets.clear()
    enemies.clear()
    lives = 3
    score = 0
    wave = 1
    enemies_destroyed = 0
    spawn_counter = 0
    spawn_interval = 120
    wave_display_timer = 0
    game_over = False
    invincible = False
    ship.visible = True

Toon ook een hint op het game-over scherm: druk op R om opnieuw te spelen.

Stap 3: ⭐ Stretch — Voeg geluid toe

De starter heeft nog geen geluid. Voeg sounds toe!

Maak een sounds/ map naast images/ en kopieer de geluidsbestanden uit dojo-defender-assets/sounds/ (vraag de coach). Of download de oplossing die ze al bevat.

Voeg bovenaan toe:

pygame.mixer.init()  # na pygame.init()

shoot_sound = pygame.mixer.Sound('sounds/shoot.wav')
explode_sound = pygame.mixer.Sound('sounds/explode.wav')
hit_sound = pygame.mixer.Sound('sounds/hit.wav')
pygame.mixer.music.load('sounds/bg_music.wav')
pygame.mixer.music.play(-1)  # -1 = blijven herhalen

Let op: het pad moet kloppen. Gebruik os.path.join(_DIR, 'sounds/shoot.wav') zoals de starter ook met afbeeldingen doet.

Speel de geluiden af op de juiste momenten:

  • shoot_sound.play() — als je schiet
  • explode_sound.play() — als een vijand of asteroïde ontploft
  • hit_sound.play() — als je schip geraakt wordt

Stap 4: 🔥 Expert — Mute-knop en volume

Voeg een M-toets toe die het geluid aan/uit zet:

muted = False

# in KEYDOWN:
if event.key == pygame.K_m:
    muted = not muted
    pygame.mixer.music.set_volume(0 if muted else 1)

Elk geluid moet dan gecheckt worden:

if not muted:
    shoot_sound.play()

Volume per geluid: Laat het schietgeluid zachter dan de explosie:

shoot_sound.set_volume(0.3)
explode_sound.set_volume(0.7)

Showcase

Laat aan een coach zien dat:

  • Je spel werkt in echte pygame zonder pgzero
  • Je geluid hebt toegevoegd (shoot, explode, hit, bg music)
  • Bonus: restart met R of mute met M

Tot de volgende keer!

“Volgende keer: POWER-UPS. Schilden, speed-boosts en spread-shots. En je schip wordt sterker naarmate je langer overleeft.”

Neem mee naar huis

Probeer thuis één van deze uitbreidingen:

  1. Health bar — Vervang de tekst “Lives: 3” door een visuele balk: teken drie rechthoekjes bovenaan.
  2. Pauze — Voeg een P-toets toe die het spel pauzeert. Zet running = False is niet genoeg — gebruik een aparte paused variabele.
  3. Particle-effect — Laat kleine witte stipjes rondspatten bij een explosie (gebruik een lijst met deeltjes die steeds kleiner worden).
  4. Eigen skin — Vervang player_ship.png door een eigen ontwerp.

Download Dojo Defender