Ein Unterprogramm stellt einen wiederverwendbaren Code-Block dar. Es kann durch übergebene Argumente mit verschiedenen Situationen umgehen. Zudem kann es einen Wert berechnen und diesen als Rückgabewert an den Aufrufenden zurückliefern
# Game-Loop
In einem sogenannten Game-Loop wird in Pygame-Zero automatisch das Spiel neu berechnet. Dabei wird immer wieder das Folgende erledigt:
- Checke Auftreten von Ereignissen – Z.B. Tastendruck oder Mausklick zur Steuerung der Spielfigur. (siehe Ereignisse im Kapitel «Verzweigungen»)
- Berechne den neuen Spielstand – Hat sich der Spieler seit dem letzten Aufruf bewegt? Haben sich andere Figuren bewegt? Dann müssen neue Positionen berechnet werden. Oder hat es eine Kollision gegeben? Dann verliert der Spieler ein Leben. (siehe Animation)
- Stelle den neuen Spielstand dar – Wenn sich etwas verändert hat, so muss das Spiel neu gezeichnet werden.
"""
Autor: S. Forster
Datum: 3.12.2020
Beschreibung: einfache Animation
"""
import pgzrun
TITLE = "Alien bewegt sich"
WIDTH = 800
HEIGHT = 200
zorg = Actor('alien')
zorg.x = 100
zorg.y = 100
zorg.vx = 10
def draw():
screen.clear()
zorg.draw()
def update(dt):
delta_x = dt * zorg.vx
zorg.x = zorg.x + delta_x
pgzrun.go()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Aufruf eines Unterprogrammes
Wir haben bereits Unterprogramme verwendet: Z.B. zorg.draw()
ruft das Unterprogramm draw
des Actors
mit dem Namen zorg
auf. Oder auch screen.fill(MINT_CREAM)
ruft das Unterprogramm fill
von screen
auf und übergibt ihm eine Farbe namens MINT_CREAM
. (Die Farbe muss vorher definiert werden!)
Nach dem gleichen Schema ruft der Game-Loop das von uns definierte Unterprogramm draw
auf!
Im Allgemeinen ruft man ein Unterprogramm auf, indem man seinen Namen, gefolgt von runden Klammern mit – falls vorhanden – durch Kommas getrennte Werte, sogenannte Argumente, schreibt.
# Definition eines Unterprogrammes
Wenn wir ein eigenes Unterprogramm definieren, so verlassen wir die eigentliche Haupt-Sequenz des Programms. Dies kennzeichnen wir durch Einrücken:
def hallo():
print("Hallo Welt")
print("Hallo Zorg")
print("hi")
hallo()
2
3
4
5
6
- Zeile 1
- definiert ein Unterprogramm
name
mit Argumentenargs
- Zeilen 2-3
- gehören zur Sequenz des Unterprogramms, werden also erst aufgerufen wenn irgendwo das Unterprogramm aufgerufen wird
- Zeile 5
- gehört nicht mehr zum Unterprogramm
- Zeile 6
- ruft das Unterprogramm auf
Das Unterprogramm hallo
wird zwar definiert, aber erst am Schluss aufgerufen. Der Output wäre also:
hi
Hallo Welt
Hallo Zorg
Achtung
Bevor ein Unterprogramm aufgerufen werden kann, muss es definiert sein!
# Beispiel
def zorg_hurt():
# Setzt das Bild von Zorg auf "verletzt"
zorg.image = "alien_hurt"
def zorg_happy():
# Setzt das Bild von Zorg auf "normal"
zorg.image = "alien"
2
3
4
5
6
7
- Zeile 1
- wir definieren das Unterprogramm
hurt
- Zeile 3
- das Unterprogramm besteht aus einem Befehl: es ändert das Bild des Aliens in «alien_hurt»
Hinweis
Wenn wir ein Unterprogramm definieren, dann dokumentieren wir es gerade mit einem Kommentar. Der Kommentar kommt gleich nach nach der Definitions-Zeile und wird – wie der Rest des Unterprogramm – eingerückt.
# Argumente
Ein Unterprogramm kann kein, ein oder mehrere Argumente entgegennehmen. Damit wir ein Unterprogramm mit den korrekten Argumenten «füttern» können, müssen wir aber wissen, was es tut und was es als Argument(e) erwartet.
# Übergeben von Argumenten beim Aufruf
Um das Fenster farbig zu füllen, müssen wir eine Farbe angeben. Das Zeichnungs-Unterprogramm des Actors
hingegen benötigt kein Argument:
MINT_CREAM = (245,255,250)
screen.fill(MINT_CREAM)
zorg.draw()
2
3
Die folgenden Aufrufe von Unterprogrammen ergeben keinen Sinn und führen zu Error-Meldungen:
MINT_CREAM = (245,255,250)
screen.fill() # fill erwartet als Argument eine Farbe
zorg.draw(MINT_CREAM) # draw hat kein Argument
2
3
Ebenso spielt die Reihenfolge der Argumente eine Rolle: Das screen.circle
-Unterprogramm erwartet als erstes Argument den Mittelpunkt als Koordinaten-Paar, dann den Radius und als drittes die Farbe.
BLACK = (255,255,255)
screen.draw.circle((200, 100), 60, BLACK)
2
# Entgegennehmen von Argumenten bei der Definition
Wenn wir uns die Definition des Unterprogrammes update
im obersten Beispiels anschauen, so sehen wir dort, dass das Unterprogramm genau ein Argument erhält: def update(dt):
sagt eigentlich:
Definiere Unterprogramm mit Namen
update
und Argumentdt
Im eingerückten Teil der folgt, kann nun der Wert des Argumentes dt
wie eine Variable verwendet werden:
def update(dt):
delta_x = dt * zorg.vx
zorg.x = zorg.x + delta_x
2
3
# Rückgabewerte
Gewisse Unterprogramme berechnen etwas und liefern den Wert zurück.
# mit Rückgabewerten arbeiten
Wir können z.B. die Distanz und den Winkel zwischen zwei Actors
bestimmen:
"""
Autor: S. Forster
Datum: 3.12.2020
Beschreibung: Distanz und Winkel zweier Actors
"""
import pgzrun
WIDTH = 600
HEIGHT = 500
zorg = Actor('alien')
zorg.x = 100
zorg.y = 100
zira = Actor('alien')
zira.x = 500
zira.y = 400
def draw():
screen.clear()
zorg.draw()
zira.draw()
distance = zorg.distance_to(zira)
print("Distanz :", distance)
zorg.angle = zorg.angle_to(zira)
pgzrun.go()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- Zeile 24 & 25
- mit
distance_to
berechnen wir die Distanz zwischenzorg
undzira
und geben diese aus – laut Pythagoras:
- Zeile 27
- Wir berechnen den Winkel zwischen
zorg
undzira
mitangle_to
und verwenden den Rückgabewert sofort, umzorg
in Richtungzira
blicken zu lassen.
# Wert als Rückgabewert zurückliefern
Dies geschieht mit dem Schlüsselwort return
gefolgt von dem zurückzugebenden Wert. return
ist immer die letzte Anweisung eines Unterprogramms!
def is_zorg_hurt():
return zorg.image == "alien_hurt"
2
Das Doppelgleich ==
vergleicht zwei Werte. Sind sie identisch ergibt der Vergleich True
, sonst False
.
# Animation
Der Game-Loop ruft das Unterprogramm update
immer wieder auf. Dabei übergibt der Game-Loop die verstrichene Zeit seit dem letzten Aufruf als Argument dt
. Damit kann im Unterprogramm an Hand der Geschwindigkeit der Objekte ihr in der Zwischenzeit zurückgelegter Weg berechnet werden:
zorg.vx = 10
def update(dt):
delta_x = dt * zorg.vx
zorg.x = zorg.x + delta_x
2
3
4
5
- Zeile 1
- Zorgs Startgeschwindigkeit in x-Richtung
- Zeile 4
- der in der Zeit
dt
zurückgelegte Weg wird berechnet - Zeile 5
- Zorg wird um den zurückgelegten Weg verschoben
Aufgabe «vertikale Bewegung»
Schaffst du es den Alien vertikal zu Bewegen?
Und diagonal? und leicht diagonal?
Zusatzaufgabe «Freier Fall»
Kannst du den Alien runterfallen lassen, inklusive Beschleunigung?
Im obigen Beispiel hat der Alien eine konstante Geschwindigkeit nach rechts. Nun müsste er eine vertikale Geschwindigkeit erhalten, die zunimmt – am Besten mit einer Gravitationsbeschleunigung!