2. De basket#

Je beschikt over de benodigde assets voor Fruitcatcher en je hebt een leeg codebestand, dus je bent klaar om te gaan programmeren. Laten we beginnen met het programmeren van het mandje. Dat moet onderin het venster heen en weer bewegen wanneer de speler op de pijltjestoetsen drukt.

../_images/basket.png

Vensterinstellingen#

Zoals je eerder zag, begint het maken van een spel in Python met het instellen van de vensterafmetingen. Voor Fruitcatcher heb je een venster nodig van 600 pixels breed en 400 pixels hoog.

Opdracht 01

Typ drie regels in je codebestand. Begin met een commentaarregel waarin je aangeeft dat je de vensterinstellingen gaat programmeren. Geef op de volgende twee regels de Pygame Zero constanten WIDTH en HEIGHT de juiste waarden, opdat je een venster krijgt van 600 bij 400 pixels.

Commentaar

Commentaar is belangrijk! Dit programma gaat uiteindelijk vele coderegels bevatten en commentaar zorgt ervoor dat je straks zelf nog de weg kunt vinden in je code. Ook maakt het je code beter leesbaar voor anderen.

Oplossing
fruitcatcher.py#
1# Vensterinstellingen
2WIDTH = 600
3HEIGHT = 400

Als je opdracht 01 goed hebt gedaan en je code runt, verschijnt het lege venster. Hoewel, leeg? In de titelbalk staat Pygame Zero Game.

../_images/window_title.png

Het is natuurlijk mooier als daar de naam van je spel staat. Ook dit is een vensterinstelling. Door de Pygame Zero constante TITLE een waarde te geven, kun je de tekst in de titelbalk aanpassen.

Opdracht 02

Voeg een regel aan je code toe waarin je de constante TITLE de waarde Fruit Catcher geeft. Run je code om te testen of het werkt.

De basket sprite#

Voor de basket sprite maak je een Actor variabele aan:

fruitcatcher.py#
1# Vensterinstellingen
2WIDTH = 600
3HEIGHT = 400
4TITLE = 'Fruit Catcher'
5
6# Sprite voor het mandje
7basket = Actor('basket')

Voor het tekenwerk hebben we weer een draw() functie nodig en voor de beweging een update() functie. Omdat we de update() functie pas later gaan invullen en Python geen lege functies accepteert, gebruiken we het keyword pass. Dat betekent ‘doe niets’. Hieronder zie je de code.

fruitcatcher.py#
 1# Vensterinstellingen
 2WIDTH = 600
 3HEIGHT = 400
 4TITLE = 'Fruit Catcher'
 5
 6# Sprite voor het mandje
 7basket = Actor('basket')
 8
 9# Draw() functie
10def draw():
11    basket.draw()
12
13# Update() functie
14def update():
15    pass
Copy paste?

Natuurlijk kun je de code hierboven kopiëren naar je eigen programma, maar het is beter om het over te typen. Door zelf te typen denk je automatisch na over de code en begrijp je beter wat je doet.

Startpositie#

Bij aanvang van het spel moet de mand midden onderin het venster staan. Wanneer de speler tijdens het spel een leven verliest, moet de mand ook weer terug naar het midden. Daarom is het handig voor deze startpositie een aparte functie te maken. Deze noemen we init_basket(). De term init komt van initialiseren, wat betekent gereed maken voor een eerste gebruik.

Voeg de volgende regels aan je programma toe:

fruitcatcher.py#
 1# Vensterinstellingen
 2WIDTH = 600
 3HEIGHT = 400
 4TITLE = 'Fruit Catcher'
 5
 6# Sprite voor het mandje
 7basket = Actor('basket')
 8
 9# Initialisatie mandje
10def init_basket():
11    pass
12
13# Draw() functie
14def draw():
15    basket.draw()
16
17# Update() functie
18def update():
19    pass
20
21# HOOFDPROGRAMMA
22init_basket()

Op regel 11 zie je wederom het keyword pass omdat de functie nu nog leeg is. Op regel 22 wordt in het hoofdprogramma de functie init_basket() aangeroepen. Nu heeft dat nog geen enkel effect maar zodra je de functie van code voorziet, verandert dat.

Opdracht 03

Vervang het pass keyword in de init_basket() functie door code die ervoor zorgt dat de mand midden onderin het venster wordt gepositioneerd. De onderkant van het mandje moet precies de onderkant van het venster raken.
Let op: je mag in deze code slechts één getal gebruiken!

Hint 1

Gebruik twee regels code: één om de horizontale positie van de mand in te stellen en één voor de verticale positie.

Hint 2

Gebruik de constanten WIDTH en HEIGHT in je code.

Als je opdracht 03 goed hebt uitgevoerd, staat de mand nu precies midden onderin het venster:

../_images/init_basket.png
Functieaanroepen

Zoals je eerder hebt geleerd, wordt een functie pas uitgevoerd wanneer je hem aanroept. Verwijder de aanroep van init_basket() maar eens uit het hoofdprogramma (of beter: maak er commentaar van door er een # voor te zetten). Je ziet dan dat het mandje weer op de standaardpositie linksboven wordt gezet.

Maar hoe zit het dan met de draw() en de update() functies? Die worden in het hoofdprogramma niet aangeroepen, maar tóch wordt de mand getekend. Dat komt doordat deze twee functies bijzonder zijn. Ze worden automatisch door Pygame aangeroepen; de update() functie 60 keer per seconde en de draw() functie wanneer Pygame merkt dat het nodig is.

Besturing#

We willen dat het mandje beweegt wanneer de speler een pijltjestoets indrukt. Het indrukken van een toets is een event. Bij het Alien spel gebruikte je de on_mouse_down() functie om te reageren op muisklik events. Pygame Zero beschikt ook over een on_key_down() functie waarmee je keyboard events kunt afhandelen. Deze heeft echter als nadeel dat het gedurende langere tijd ingedrukt houden van een toets niet wordt gedetecteerd. Daarom gebruiken we voor Fruitcatcher een andere manier: de update() functie. Deze wordt 60 keer per seconde uitgevoerd. Als we in de update() functie checken of de speler op dat moment een pijltjestoets ingedrukt houdt, kunnen we de mand laten bewegen.

Vervang het pass keyword in de update() functie door de volgende code:

fruitcatcher.py#
# Update() functie
def update():
    # Keyboard events
    if keyboard.left:
        pass
    elif keyboard.right:
        pass
Opdracht 04

Vervang de pass keywords in de zojuist toegevoegde regels door code die ervoor zorgt dat de basket sprite naar links of naar rechts beweegt.

Hint

Om de horizontale positie van de mand te wijzigen, kun je het beste de basket.x variabele gebruiken.

Opdracht 05

Je loopt nu tegen hetzelfde probleem aan als bij het Alien spel: de mand beweegt, maar ‘oude versies’ van de mand blijven zichtbaar.

../_images/basket_no_clear.png

Los dit op zoals je ook bij het Alien spel deed.

Opdracht 06

Het is mogelijk om de mand uit het venster te laten verdwijnen. Voeg aan je if statement in de update() functie code toe die ervoor zorgt dat dat niet gebeurt. Je kunt dit op meerdere manieren doen.

Hint manier 1

Je zou na het huidige if statement een nieuw if statement kunnen toevoegen dat checkt of de rechterkant van de mand zich rechts van de rechterzijde van het venster bevindt. Als dat het geval is, zorgt het statement ervoor dat de recherzijde van de mand precies gelijk wordt aan de rechterzijde van het scherm.

../_images/basket_right_out_of_bounds.png

../_images/basket_right_on_bounds.png
if basket.right > WIDTH:
    basket.right = WIDTH

Je update() functie bevat dan dus twee if statements:

  • Het eerste checkt of er toetsen zijn ingedrukt en verandert overeenkomstig de positie van de mand.

  • Het tweede checkt of die positie wel is toegestaan en past zo nodig de positie aan.

Iets soortgelijks kun je doen om te voorkomen dat de mand aan de linkerkant buiten het venster komt.

Hint manier 2

Je zou het huidige if statement met behulp van het and keyword kunnen uitbreiden met extra voorwaarden. Bijvoorbeeld om ervoor te zorgen dat de mand alleen naar links beweegt als de linker pijltjestoets is ingedrukt én als de linkerkant zich nog rechts van de linkerrand bevindt.

if keyboard.left and basket.left > 0:
    # beweeg de mand naar links

Iets soortgelijks kun je doen voor de beweging naar rechts.

Deze manier kan soms een minder mooi resultaat opleveren dan manier 1. Misschien kun je zelf bedenken waarom?

Snelheid#

Hoe heb je de beweging van de mand geprogrammeerd? Om de mand naar links te laten bewegen, zou je basket.x -= 1 kunnen gebruiken. En om hem sneller te laten bewegen, kun je bijvoorbeeld basket.x -= 5 gebruiken. Dit hard-coden van de snelheid met een getal is echter niet slim; een echte programmeur zou dat nooit doen. Het is veel beter om hiervoor een variabele te gebruiken. Voeg direct na het aanmaken van de basket variabele de volgende regel toe:

fruitcatcher.py#
6# Sprite voor het mandje
7basket = Actor('basket')
8basket.speed = 5

Met basket.speed geven we aan dat de speed variabele onderdeel is van de basket variabele. Het is een notatie die hoort bij object-geörienteerd programmeren, een onderwerp waarin we ons nu niet verder zullen verdiepen.

Opdracht 07

Gebruik de basket.speed variabele in je code die de mand laat bewegen.

Het voordeel van deze manier van werken mag duidelijk zijn. Als je de snelheid van de mand wilt veranderen hoef je slechts regel 8 aan te passen. Bovendien is het nu ook mogelijk om de snelheid van de mand nog tijdens het spel te variëren. Je zou bijvoorbeeld de mand steeds sneller kunnen laten bewegen naarmate de pijltjestoets langer wordt ingedrukt.