4. Events#
De meeste computerprogramma’s, en games in het bijzonder, reageren op handelingen van de gebruiker, bijvoorbeeld wanneer de gebruiker de muis beweegt of een toets op het toetsenbord indrukt. Een gebeurtenis waarop een computerprogramma kan reageren noemen we een event. Voorbeelden van events zijn:
de gebruiker klikt met de linker muisknop;
de gebruiker hovert (zweeft) met de muis ergens overheen;
de gebruiker drukt op de spatiebalk.
Je kunt je programma op events laten reageren door speciale functies te definiëren, zogenoemde event handler functies. De namen van dit soort functies beginnen altijd met het Engelse woord ‘on’. Voorbeelden van de in Pygame Zero beschikbare event handler functies zijn:
on_mouse_down()on_mouse_move()on_key_down()
We starten in dit hoofdstuk met de code die onze alien van links naar rechts door het venster laat bewegen:
1# Vensterafmetingen
2WIDTH = 600
3HEIGHT = 400
4
5# Roze alien Actor
6alien = Actor('alien_pink')
7alien.midleft = (0, HEIGHT / 2)
8alien.speed = 10
9
10# De draw() functie van de game
11def draw():
12 screen.clear()
13 alien.draw()
14
15# De update() functie van de game
16def update():
17 alien.left += alien.speed
18 if alien.left >= WIDTH:
19 alien.right = 0
4.1. Muisklikken#
Om het programma op een muisklik te laten reageren, voeg je de on_mouse_down() event handler toe:
Run deze code. Klik enkele keren met de muis in het game venster en zie dat onderin het Mu editor venster bij elke klik de tekst Muisklik! wordt afgedrukt.
We kunnen in de on_mouse_down() functie een variabele met de naam pos gebruiken om de positie van de muis te achterhalen. Pas de functie als volgt aan en bekijk het resultaat:
Ook is het mogelijk te detecteren met welke muisknop is geklikt. Probeer het volgende maar eens:
Met de positie van de muisklik is het mogelijk om te checken of de gebruiker óp of náást onze roze alien heeft geklikt. Daarvoor hebben we collision detection nodig.
4.2. Collision detection#
Het Engelse woord collision betekent botsing. Collision detection is een belangrijke techniek bij het programmeren van games, die we gebruiken om vast te stellen of twee objecten elkaar raken of zelfs overlappen. Wanneer je bijvoorbeeld een schietspel programmeert is het handig om te signaleren wanneer een granaat sprite de vijand sprite raakt, want waarschijnlijk moet er dan iets gebeuren (de vijand ontploft, er wordt een punt bij de score opgeteld, etcetera).
Actors in Pygame Zero beschikken over verschillende functies voor collision detection. Met bijvoorbeeld de functie colliderect() kun je checken of de twee rechthoeken die twee sprites innemen elkaar overlappen.
Voor onze muisklik event handler hebben we een andere functie nodig, namelijk een die checkt of een punt zich binnen de rechthoek van een sprite bevindt. Want wij willen weten of het punt van de muisklik zich binnen het gebied van de alien sprite bevindt.
De functie die wij nodig hebben is collidepoint(). Deze gebruiken we in het volgende if statement:
De regels 23 tot en met 26 kun je vertalen als: “Als de muispositie pos zich binnen de rechthoek van alien bevindt, druk dan "Au!" af en druk anders "Mis!" af.” Test de werking van deze code. Gaat de alien te snel om hem te kunnen raken, verlaag dan de snelheid in regel 8 van je code.
Met het printen van "Au!" en "Mis!" kun je snel testen of de collision detection goed werkt, maar het is natuurlijk leuker als een muisklik gevolgen heeft voor de alien. Je zou hem bijvoorbeeld met elke klik sneller kunnen laten bewegen:
Zet voordat je deze code uitvoert de startsnelheid in regel 8 op 1:
Extra: snelheid in het venster tonen
Misschien vind je het leuk om de snelheid van de alien in het venster te zien. Dit kun je doen door aan je draw() functie de volgende regel toe te voegen:
In regel 13 gebruiken we de functie screen.draw.text(text, pos, color) om een tekst op een bepaalde positie in een bepaalde kleur op het scherm te tonen. Het text argument ziet er een beetje ingewikkeld uit:
f"Snelheid: {alien.speed}."
De letter f geeft aan dat de tekst een formatted string, kortweg f-string, is. Met zo’n f-string kun je op een mooie manier de waarden van variabelen verwerken in een tekst door ze tussen accolades {...} te zetten.
In de paragraaf over muisklikken hierboven deden we bijvoorbeeld dit:
Maar je zou dit met een f-string als volgt kunnen doen:
Behalve de snelheid, zou je ook de positie van de alien op het scherm kunnen tonen, bijvoorbeeld op deze manier:
En om deze twee zinnen op twee regels af te drukken, kun je het newline karakter \n gebruiken:
Opdracht 01
Wijzig je programma zodat de alien van richting verandert zodra erop wordt geklikt. Ging de alien naar rechts, dan moet hij dus naar links en vice versa.
Hint
Je hoeft slechts één regel code te veranderen.
Oplossing
Zorg ervoor dat de alien weer aan de andere kant van het venster verschijnt nadat hij buiten beeld verdwijnt.
Hint
Hiervoor moet je het if statement in de update() functie uitbreiden met een elif.
Oplossing
Opdracht 02
Vervang je code door de onderstaande (kopiëren en plakken) en run de code om te zien wat er gebeurt.
1# Vensterafmetingen
2WIDTH = 600
3HEIGHT = 400
4
5# Roze alien Actor
6alien = Actor('alien_pink')
7alien.center = (WIDTH / 2, HEIGHT / 2)
8alien.speed = 1
9
10# De draw() functie van de game
11def draw():
12 screen.clear()
13 alien.draw()
14
15# De update() functie van de game
16def update():
17 alien.y += alien.speed
18 if alien.bottom > HEIGHT:
19 pass
20
21# Mouse down event handler
22def on_mouse_down(button, pos):
23 if alien.collidepoint(pos):
24 pass
De alien beweegt naar beneden en verdwijnt uit het venster. Vervang het keyword pass (wat in Python betekent ‘doe niets’) in de regels 19 en 24 door code die ervoor zorgt dat:
de alien stil blijft staan zodra hij de onderkant van het venster raakt;
de alien 50 pixels omhoog gaat zodra je er met de muis op klikt (en vervolgens weer naar beneden valt).
Oplossing
15# De update() functie van de game
16def update():
17 alien.y += alien.speed
18 if alien.bottom > HEIGHT:
19 alien.bottom = HEIGHT
20
21# Mouse down event handler
22def on_mouse_down(button, pos):
23 if alien.collidepoint(pos):
24 alien.y -= 50