Skip to main content

Snake copy

0 Wat gaan we leren

We gaan nog een projectje maken met Thonny (uit de vorige les) en bij dit project gaan we gebruik maken van de standaard Python library:

pgzero

Weet je nog hoe je een pacakge installeert in Thonny?

Yep, Tools - Manage Packages en dan pgzero zoeken en installeren.

1 Snake – Les 1: Teken de slangkop

In deze les gaan we beginnen met het maken van een eigen versie van Snake in Python met Pygame Zero.

We gaan eerst de kop van de slang tekenen op het scherm. Je ziet dan een vierkantje dat straks kan gaan bewegen.

Wat gaan we doen?

We maken een slangkop als vierkant met een bepaalde positie en grootte, en tekenen die in de draw()-functie.

📦 Benodigdheden

  • Een werkende Python-omgeving met Pygame Zero (zoals Thonny)
  • Geen plaatjes nodig – we tekenen de slang met blokken

🔰 Startercode

# importeer library
import pgzrun

# Spelgrootte
WIDTH = 600
HEIGHT = 400

# Startpositie van de slangkop
snake_x = 100
snake_y = 100
tile_size = 20

def draw():
    screen.clear()
    screen.draw.filled_rect(Rect((snake_x, snake_y), (tile_size, tile_size)), "green")
    
#start programma
pgzrun.go()

ℹ️ Uitleg

  • WIDTH en HEIGHT: grootte van het spelvenster
  • snake_x en snake_y: positie van de slangkop
  • tile_size: grootte van het blokje
  • screen.draw.filled_rect(...): tekent een gevuld vierkantje op het scherm

🛠️ Opdracht

  • Pas de waarde van snake_x en snake_y aan – wat gebeurt er?
  • Maak het vierkant groter of kleiner door tile_size te wijzigen
  • Verander de kleur van het vierkant in bijvoorbeeld "blue" of "orange"

💡 Extra uitdaging

Teken een tweede blokje naast de slangkop alsof er al een stukje staart is. Gebruik nog een screen.draw.filled_rect().

📤 Inleveren

  1. Maak een screenshot van je 'slangkop' op het scherm waarbij je de 'slangkop'op een andere positie heb gezet.

2 Snake – Les 2: Beweeg de slang

In deze les gaan we de slangkop laten bewegen met de pijltjestoetsen.

We gebruiken daarvoor de update()-functie van Pygame Zero en de toetsenbordinput.

Wat gaan we doen?

We maken een richting-variabele en passen de positie van de slang aan op basis van de pijltjes die je indrukt.

🔰 Code

Dit is een deel van de code, je moet jouw bestaande code aanpassen aan de hand van deze nieuwe code.

# Startpositie van de slangkop
snake_x = 200
snake_y = 200
tile_size = 10
step = 1

def draw():
    screen.clear()
    screen.draw.filled_rect(Rect((snake_x, snake_y), (tile_size, tile_size)), "green")
    
def update():
    global snake_x, snake_y

    if keyboard.left:
        snake_x -= step
    if keyboard.right:
        snake_x += step
    if keyboard.up:
        snake_y -= step
    if keyboard.down:
        snake_y += step  

ℹ️ Uitleg

  • update() wordt automatisch meerdere keren per seconde uitgevoerd
  • keyboard.left controleert of de linkerpijl is ingedrukt
  • Telkens als je een toets indrukt, verandert de positie van de slang
  • step bepaalt hoe ver de slang per stap beweegt

🛠️ Opdracht

  • Beweeg de slang door het scherm met de pijltjes
  • Pas step aan naar een andere waarde – wat merk je?
  • Laat de slang sneller of langzamer bewegen door minder of meer pixels per keer te verplaatsen

💡 Extra uitdaging

Laat de slang automatisch blijven bewegen in de laatst gekozen richting:

  • Gebruik een variabele richting die je bijwerkt met on_key_down()
  • Laat de slang dan elke update in die richting verder bewegen

📤 Inleveren

  1. Leg uit wat de variable step doet.
  2. Welke waarde heb je gekozen, waarom?

(je kunt dit inleveren in het tekst veld of in een .txt. bestandje)

3 Snake – Les 3: Slang groeit

In deze les gaan we de slang laten groeien. De slang bestaat dan uit meerdere blokjes in plaats van alleen de kop.

Als de slang eten raakt, groeit zijn lichaam één blokje langer.

Wat gaan we doen?

We werken met een list waarin we alle segmenten van de slang opslaan. Bij elke stap schuift de slang een blokje op, en als hij iets eet voegen we er een nieuw blokje aan toe.

🔰 Startercode

import random

WIDTH = 600
HEIGHT = 400
tile_size = 20

# Startpositie en richting
snake = [(100, 100)]
richting = "rechts"

# Plaats van het eten
food_x = 300
food_y = 200

def draw():
    screen.clear()
    for segment in snake:
        screen.draw.filled_rect(Rect(segment, (tile_size, tile_size)), "green")
    screen.draw.filled_rect(Rect((food_x, food_y), (tile_size, tile_size)), "red")

def update():
    global food_x, food_y

    # Huidige koppositie
    head_x, head_y = snake[0]

    # Nieuwe positie bepalen
    if keyboard.left:
        new_head = (head_x - tile_size, head_y)
    elif keyboard.right:
        new_head = (head_x + tile_size, head_y)
    elif keyboard.up:
        new_head = (head_x, head_y - tile_size)
    elif keyboard.down:
        new_head = (head_x, head_y + tile_size)
    else:
        return  # Geen toets ingedrukt

    # Nieuwe kop toevoegen aan de slang
    snake.insert(0, new_head)

    # Controleren op eten
    if new_head[0] == food_x and new_head[1] == food_y:
        food_x = random.randint(0, (WIDTH // tile_size) - 1) * tile_size
        food_y = random.randint(0, (HEIGHT // tile_size) - 1) * tile_size
        # slang groeit: we verwijderen geen staart
    else:
        # Verwijder het laatste segment van de staart
        snake.pop()

ℹ️ Uitleg

  • snake is een lijst met alle blokjes van de slang (als coördinaten)
  • Elke keer als je beweegt voeg je een nieuw blokje toe aan het begin
  • Als je geen eten raakt, verwijder je het laatste blokje
  • Als je wél eten raakt, blijft het hele lichaam staan → de slang groeit!

🛠️ Opdracht

  • Speel het spel en probeer de slang langer te maken door eten op te pakken
  • Bekijk hoe de slang groeit – hoeveel blokjes zie je na 3 stukjes eten?
  • Verander de kleur van het eten of maak het iets groter

💡 Extra uitdaging

  • Laat het eten op een andere plek verschijnen als je de slang start
  • Maak het eten een ander soort vorm, bijvoorbeeld met een `screen.draw.circle()`

📤 Inleveren

Maak een screenshot van je slang die gegroeid is (minimaal 4 segmenten lang).

Schrijf in 1 zin uit hoe het komt dat de slang groeit.

4 Snake – Les 4: Eten op random plek

In deze les gaan we ervoor zorgen dat het eten steeds op een andere plek verschijnt als de slang het opeet.

We zorgen er ook voor dat het eten netjes op de “grid” ligt, zodat het altijd op een blokje van de slang past.

Wat gaan we doen?

We gebruiken de functie random.randint() om een willekeurige x- en y-coördinaat te kiezen.

We leggen uit waarom we moeten vermenigvuldigen met tile_size.

🔰 Startercode

import random

WIDTH = 600
HEIGHT = 400
tile_size = 20

snake = [(100, 100)]
richting = "rechts"

# Eten verschijnt op een random plek
def nieuwe_eten_plek():
    x = random.randint(0, (WIDTH // tile_size) - 1) * tile_size
    y = random.randint(0, (HEIGHT // tile_size) - 1) * tile_size
    return x, y

food_x, food_y = nieuwe_eten_plek()

def draw():
    screen.clear()
    for segment in snake:
        screen.draw.filled_rect(Rect(segment, (tile_size, tile_size)), "green")
    screen.draw.filled_rect(Rect((food_x, food_y), (tile_size, tile_size)), "red")

def update():
    global food_x, food_y

    head_x, head_y = snake[0]

    if keyboard.left:
        new_head = (head_x - tile_size, head_y)
    elif keyboard.right:
        new_head = (head_x + tile_size, head_y)
    elif keyboard.up:
        new_head = (head_x, head_y - tile_size)
    elif keyboard.down:
        new_head = (head_x, head_y + tile_size)
    else:
        return

    snake.insert(0, new_head)

    if new_head == (food_x, food_y):
        food_x, food_y = nieuwe_eten_plek()
    else:
        snake.pop()

ℹ️ Uitleg

  • WIDTH // tile_size berekent hoeveel blokjes er in de breedte passen
  • random.randint(...) kiest een willekeurig blokje
  • Door daarna te vermenigvuldigen met tile_size, krijg je een echte pixelpositie
  • We zorgen dat het eten altijd op een logische plek verschijnt

🛠️ Opdracht

  • Test of het eten steeds op een andere plek verschijnt als je het pakt
  • Wat gebeurt er als je het eten net niet raakt?
  • Probeer ook een keer het spel opnieuw te starten en zie hoe het eten telkens ergens anders staat

💡 Extra uitdaging

  • Laat het eten een andere kleur krijgen elke keer dat het verspringt
  • Laat meerdere stukken eten tegelijk op het scherm verschijnen

📤 Inleveren

Maak een screenshot van een moment waarop het eten net op een nieuwe plek is verschenen.

Beschrijf in 1 zin wat de functie nieuwe_eten_plek() doet.

5 Snake – Les 5: Game Over bij botsing

In deze les leren we hoe het spel stopt als de slang zichzelf raakt of tegen de rand van het scherm botst.

We voegen een “Game Over”-scherm toe zodat je ziet wanneer je verloren hebt.

Wat gaan we doen?

We controleren of de kop van de slang buiten het scherm komt of of hij in zijn eigen lichaam bijt.

Als dat gebeurt, zetten we de variabele game_over op True en stoppen we het spel.

🔰 Startercode

import random

WIDTH = 600
HEIGHT = 400
tile_size = 20

snake = [(100, 100)]
richting = "rechts"
game_over = False

def nieuwe_eten_plek():
    x = random.randint(0, (WIDTH // tile_size) - 1) * tile_size
    y = random.randint(0, (HEIGHT // tile_size) - 1) * tile_size
    return x, y

food_x, food_y = nieuwe_eten_plek()

def draw():
    screen.clear()
    if game_over:
        screen.draw.text("GAME OVER", center=(WIDTH // 2, HEIGHT // 2), fontsize=60, color="red")
        return
    for segment in snake:
        screen.draw.filled_rect(Rect(segment, (tile_size, tile_size)), "green")
    screen.draw.filled_rect(Rect((food_x, food_y), (tile_size, tile_size)), "red")

def update():
    global food_x, food_y, game_over

    if game_over:
        return

    head_x, head_y = snake[0]

    if keyboard.left:
        new_head = (head_x - tile_size, head_y)
    elif keyboard.right:
        new_head = (head_x + tile_size, head_y)
    elif keyboard.up:
        new_head = (head_x, head_y - tile_size)
    elif keyboard.down:
        new_head = (head_x, head_y + tile_size)
    else:
        return

    # Check voor botsing met rand
    if new_head[0] < 0 or new_head[0] >= WIDTH or new_head[1] < 0 or new_head[1] >= HEIGHT:
        game_over = True
        return

    # Check voor botsing met eigen lichaam
    if new_head in snake:
        game_over = True
        return

    snake.insert(0, new_head)

    if new_head == (food_x, food_y):
        food_x, food_y = nieuwe_eten_plek()
    else:
        snake.pop()

ℹ️ Uitleg

  • game_over is een variabele die bepaalt of het spel nog bezig is
  • Als de slang buiten het scherm gaat of zichzelf raakt, stopt de update-functie
  • In draw() tonen we dan een rode “GAME OVER”-tekst

🛠️ Opdracht

  • Speel het spel en probeer expres tegen jezelf of de rand te botsen
  • Controleer of “GAME OVER” verschijnt en het spel stopt
  • Verander de tekst of kleur van de “Game Over”-melding

💡 Extra uitdaging

  • Laat de speler opnieuw beginnen met de R-toets
  • Speel een geluid af als het spel voorbij is (bijv. sounds.crash.play())

📤 Inleveren

Maak een screenshot waarop de slang tegen zichzelf of de rand is gebotst en “GAME OVER” verschijnt.

Leg in een paar zinnen uit wat de code doet om te controleren of je verloren hebt.

6 Snake – Les 6: Score bijhouden

In deze les gaan we een score bijhouden. Elke keer dat de slang eten opeet, telt de score één punt op.

We tonen deze score linksboven op het scherm, zolang het spel bezig is.

Wat gaan we doen?

We maken een score-variabele en verhogen deze telkens als de slang het eten raakt. In draw() tekenen we de score op het scherm.

🔰 Startercode

import random

WIDTH = 600
HEIGHT = 400
tile_size = 20

snake = [(100, 100)]
richting = "rechts"
game_over = False
score = 0

def nieuwe_eten_plek():
    x = random.randint(0, (WIDTH // tile_size) - 1) * tile_size
    y = random.randint(0, (HEIGHT // tile_size) - 1) * tile_size
    return x, y

food_x, food_y = nieuwe_eten_plek()

def draw():
    screen.clear()
    if game_over:
        screen.draw.text("GAME OVER", center=(WIDTH // 2, HEIGHT // 2), fontsize=60, color="red")
        screen.draw.text(f"Score: {score}", center=(WIDTH // 2, HEIGHT // 2 + 50), fontsize=40, color="black")
        return
    for segment in snake:
        screen.draw.filled_rect(Rect(segment, (tile_size, tile_size)), "green")
    screen.draw.filled_rect(Rect((food_x, food_y), (tile_size, tile_size)), "red")
    screen.draw.text(f"Score: {score}", (10, 10), fontsize=40, color="black")

def update():
    global food_x, food_y, game_over, score

    if game_over:
        return

    head_x, head_y = snake[0]

    if keyboard.left:
        new_head = (head_x - tile_size, head_y)
    elif keyboard.right:
        new_head = (head_x + tile_size, head_y)
    elif keyboard.up:
        new_head = (head_x, head_y - tile_size)
    elif keyboard.down:
        new_head = (head_x, head_y + tile_size)
    else:
        return

    # Check voor botsing met rand
    if new_head[0] < 0 or new_head[0] >= WIDTH or new_head[1] < 0 or new_head[1] >= HEIGHT:
        game_over = True
        return

    # Check voor botsing met eigen lichaam
    if new_head in snake:
        game_over = True
        return

    snake.insert(0, new_head)

    if new_head == (food_x, food_y):
        food_x, food_y = nieuwe_eten_plek()
        score += 1
    else:
        snake.pop()

ℹ️ Uitleg

  • score = 0: we starten met een lege score
  • Bij een botsing met eten doen we score += 1
  • Met screen.draw.text(...) tonen we de score op het scherm
  • Bij Game Over tonen we ook de score onder de tekst

🛠️ Opdracht

  • Speel het spel en probeer een score van minimaal 5 te halen
  • Verander de kleur of het lettertype van de score
  • Laat de tekst op een andere plek op het scherm zien (bijvoorbeeld rechtsboven)

💡 Extra uitdaging

  • Laat de kleur van de score veranderen bij elke 5 punten
  • Toon de hoogste score ooit behaald (highscore bijhouden)

📤 Inleveren

Maak een screenshot van je spel met een zichtbare score van minimaal 5 punten.

Leg in één zin uit wat de regel score += 1 doet in jouw spel.

7 Snake – Reflectie & Uitbreiding

In deze laatste les ga je terugkijken op wat je hebt geleerd en krijg je de kans om zelf iets toe te voegen aan jouw Snake-spel.

Je beslist zelf wat je wilt verbeteren, uitbreiden of mooier maken.

🧠 Reflectie

Beantwoord de volgende vragen in een apart document of als commentaar onderaan je code:

  • Wat vond je het leukste om te maken aan het Snake-spel?
  • Wat vond je lastig? Hoe heb je dat opgelost?
  • Wat heb je geleerd over Python en programmeren?
  • Waar ben je trots op?

🎮 Eindopdracht: Uitbreiding

Kies één van de onderstaande uitbreidingen en voeg die toe aan je spel. Je mag ook je eigen idee uitvoeren!

  • 🐍 Toon het volledige lichaam van de slang met een andere kleur voor de kop
  • 🧱 Voeg muren toe waar je niet doorheen mag (botsing = Game Over)
  • 🔁 Laat de slang automatisch blijven bewegen in de huidige richting
  • 🕹️ Laat het spel moeilijker worden (bv. door sneller te gaan naarmate je groeit)
  • 🎨 Maak je eigen kleuren of achtergrond
  • 📊 Laat een highscore zien die blijft staan zolang je speelt

💡 Eigen idee?

Bedenk zelf een uitbreiding en beschrijf wat je van plan bent. Probeer het daarna te maken!

📤 Inleveren

  • Lever een screenshot of filmpje in van jouw aangepaste versie van het spel
  • Vertel in 1 of 2 zinnen wat jij hebt toegevoegd of verbeterd
  • Lever je reflectie in met de antwoorden op de 4 vragen hierboven

###

# Docenten

🎓 Docentenhandleiding

📘 Overzicht

  • Doelgroep: Leerlingen van 13-16 jaar met basiskennis Python
  • Duur: 6 lessen van ±45-60 minuten
  • Software: Thonny + Pygame Zero
  • Spelconcept: Maak een klassieke Snake-game waarbij de slang groeit als hij voedsel eet

🎯 Leerdoelen

  • Werken met coördinaten en rasters
  • Gebruik van draw() en update() voor game loop
  • Toetsenbordinput met keyboard.left/right/up/down
  • Werken met lijsten (snake = [(x, y), ...])
  • Gebruik van if-statements voor botsing en logica
  • Gebruik van functies zoals random.randint()
  • Reflecteren en uitbreiden van bestaande code

📚 Lesoverzicht

Les Onderwerp Nieuwe concepten
1 Tekenen van slangkop draw(), coördinaten, screen.draw.filled_rect()
2 Besturen met pijltjestoetsen update(), keyboard input
3 Slang groeit bij eten Lists, insert, pop
4 Eten op random plek random.randint, grid-alignment
5 Botsing met muur/lichaam if-logica, in-controle
6 Score, Reflectie & Uitbreiding draw.text(), variabelen bijhouden

⚠️ Valkuilen

  • Slang beweegt niet goed → positie niet geüpdatet met vaste stappen
  • Eten verschijnt buiten raster → tile_size vergeten bij randomizing
  • Slang groeit te veel of niet → vergeten snake.pop() uit te voeren
  • Game Over werkt niet → koppositie niet correct gecheckt tegen eigen lichaam

🧠 Differentiatie

Voor snelle leerlingen

  • Voeg muren toe of maak levels met obstakels
  • Voeg een tweede speler toe (WASD)
  • Maak het spel sneller bij hogere score
  • Laat de slang automatisch bewegen in huidige richting

Voor langzamere leerlingen

  • Werk alleen met een kop zonder lichaam
  • Laat beweging alleen per toetsdruk toe (geen auto-move)
  • Gebruik visueel grid of help bij rasteruitlijning

📊 Beoordeling (optioneel)

Criterium Omschrijving Score (1-5)
Werkt het spel Spel is speelbaar, slang groeit en game over werkt 🟩
Codekwaliteit Code is leesbaar en logisch gestructureerd 🟩
Creativiteit Leerling heeft uitbreiding of verbetering toegevoegd 🟩
Reflectie Vragen zijn volledig beantwoord met inzicht 🟩

💡 Lesaanpak & tips

  • Gebruik bij elke les een klassikale “test en speel”-fase
  • Laat leerlingen fouten tonen op het bord (met uitleg!)
  • Bespreek hoe je problemen oplost met print-debuggen
  • Geef tijd voor zelfstandig uitbreiden in les 6
  • Laat leerlingen elkaars spel testen in tweetallen

🧰 Benodigdheden

  • Thonny met Pygame Zero (pip install pgzero)
  • Werkende computer met toetsenbord
  • Basiskennis van Python: if, def, variabelen