Steuerung durch Spieler: Tastatur, Maus und Game Controller
Pygame unterstützt uns und das Einbinden der Steuerung der Spielfiguren und Bewegen durch den Spieler ist kein Problem. Wir haben bereits bei unserem Grundgerüst aus dem ersten Pygame-Kapitel eine Abfrage der Tastatur integriert. In diesem Kapitel wollen wir die Spielsteuerung auch mit einer Spielerfigur verbinden und Aktion auf dem Bildschirm sehen.
Im ersten Schritt werden wir die Spielerfigur mit der Tastatur steuern – in einem folgenden Kapitel wird die Abfrage der Maus und Game-Controller über Pygame gezeigt.
Wir benötigen unser Grundgerüst aus dem Kapitel „Grundgerüst für Spiele mit Pygame“.
Als Erstes benötigen wir eine Spielerfigur – aus dem letzten Kapitel mit Pong benötigen wir einen Tischtennisschläger. Dieser wird Grafisch ganz simpel über ein Rechteck dargestellt. Auch hier benötigen wir wieder die Definition der Variablen außerhalb unsere Hauptroutine.
Für den ersten Spieler legen wird fest:
spielfigur_1_x
spielfigur_1_y
Diese setzen wir auf die linke Spielbrettseite an die Position X = 20 und Y = 20:
spielfigur_1_x = 20
spielfigur_1_y = 20
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
Nun zeichnen wir innerhalb der Hauptroutine den Tischtennisschläger des ersten Spielers:
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCHMESSER])
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, 100])
Tastatur abfragen und in Variablen speichern
In unserer Hauptschleife wird nun die Tastatur abgefragt. Hier können wir unsere Programmcodevorlage aus dem ersten Kapitel entsprechend erweitern und die im Vorfeld (was wir noch tun müssen) gesetzt Variable spielfigur_1_bewegung
mit entweder einer positiven Zahl (für die Bewegung nach unten) oder mit einer negativen Zahl (für die Bewegung nach oben) ändern. Eine Variable reicht aus, weil unsere Spielfigur sich nur nach oben bzw. nach unten bewegen kann!
spielfigur_1_x = 20
spielfigur_1_y = 20
spielfigur_1_bewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
elif event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Taste für Spieler 1
elif event.key == pygame.K_UP:
print("Spieler hat Pfeiltaste hoch gedrückt")
spielfigur_1_bewegung = -6
elif event.key == pygame.K_DOWN:
print("Spieler hat Pfeiltaste runter gedrückt")
spielfigur_1_bewegung = 6
Zusätzlich erweitern wir unsere Programmcodevorlage um die Möglichkeit, das Spiel auch mit der Escape-Taste beenden zu können. Somit kann das Spiel entweder über das Schließen des Fensters oder über die Escape-Taste beendet werden:
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
Wichtig: Trennung Spiellogik und Zeichnen
Wichtig ist die Trennung zwischen der Eingabeabfrage (wohin wollen die Spieler ihre Figur bewegen) und dem eigentlichen Zeichnen! Sonst kommt ersten schnell Chaos in die Programmierung und zweitens können wir die Spielerfigur (in dem Fall den Schläger) nicht beliebig weit nach unten bzw. oben bewegen. Denn sonst würde dieser aus dem Spielfeld verschwinden.
Aber der Reihe nach – vor dem Zeichnen kommt die Berechnung. Dazu haben wir im Ablauf unseres Programms den Punkt „# Spiellogik“ vorgesehen. Danach zeichnen wir frisch den Schläger. Dazu müssen wir einfach die bisher fixen Werte durch das Ergebnis der neuen Variablen spielfigur_1_bewegung
ersetzen.
spielfigur_1_bewegung = 0
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Taste für Spieler 1
if event.key == pygame.K_UP:
print("Spieler hat Pfeiltaste runter gedrückt")
spielfigur_1_bewegung = -6
elif event.key == pygame.K_DOWN:
print("Spieler hat Pfeiltaste runter gedrückt")
spielfigur_1_bewegung = 6
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
Spieler im sichtbaren Bereich halten
Bevor der Schläger aus der sichtbaren Fläche verschwindet, müssen wir bei der Spiellogik dies verhindern.
Die Position des Schlägers darf nicht kleiner als 0 werden. Dazu Überprüfen wir die y-Position und wird diese kleiner als 0, setzten wird diese einfach wieder auf 0 zurück. Dies ist die einfachere Möglichkeit als viel Aufwand zu treiben und im Vorfeld darauf zu überprüfen.
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
Wenn wir das Gleich für den unteren Fensterbereich machen wollen, dann sollten wir unbedingt die Höhe des Schlägers berücksichtigen. Die erste gezeigte Variante ist suboptimal:
if spielfigur_1_y > FENSTERHOEHE:
spielfigur_1_y = FENSTERHOEHE
Besser (noch nicht optimal) ist:
if spielfigur_1_y > FENSTERHOEHE - 100:
spielfigur_1_y = FENSTERHOEHE – 100
Und noch besser ist, wenn wir wieder mit Variablen arbeiten (hier kann man sich streiten, ob das auch eine Konstante sein sollte). Aber einfach einmal als Gedanken für mehr Spielspaß, dass der Schläger umso kleiner wird, je länger das Spiel läuft als Spielerschwernis. Daher machen wir eine Variable.
Also vornweg wieder definieren und dann nutzen:
spielfigur_1_bewegung = 0
schlaegerhoehe = 100
# Schleife Hauptprogramm
Und für die Berechnung der Spiellogik und die Bewegung:
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
if spielfigur_1_y > FENSTERHOEHE - schlaegerhoehe:
spielfigur_1_y = FENSTERHOEHE - schlaegerhoehe
# Spielfeld löschen
screen.fill(SCHWARZ)
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCHMESSER])
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, schlaegerhoehe])
Bewegung stoppen, wenn die Taste losgelassen wird
Bei der bisherigen Tastaturabfrage gaben wir immer geschaut, ob eine Taste gedrückt wurde und haben dann die entsprechende Variable für die Bewegung gesetzt. Wenn wir die Bewegung stoppen wollen, dann können wir einfach abfragen, ob eine bestimmte Taste losgelassen wurde, nachdem diese gedrückt wurde. Ist das der Fall, dann kann man die Variable für die Bewegung auf 0 setzen.
Machen wir das Beispielhaft für den ersten Spieler:
# zum Stoppen der Spielerbewegung
if event.type == pygame.KEYUP:
print("Spieler hat Taste losgelassen")
# Tasten für Spieler 1
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
print("Spieler 1 stoppt bewegung")
spielfigur_1_bewegung = 0
Für den zweiten Spieler ist es dasselbe.
Zweiter Spieler
Das war die Steuerung für die erste Spielfigur. Jetzt benötigen wir es für die Zweite. Hier gibt es die Variante, einfach wieder so vorzugehen wie wir es bei der ersten Spielfigur gemacht haben oder eine schönere Lösung über Funktionen (was wir später machen). Bei 2 Spielern wählen wir den erst einmal den simplen Weg, was wir später durch Funktionen dann ändern. Didaktisch wichtig ist, langsam das Verständnis aufzubauen.
Wir benötigen für unseren 2 Spieler wieder die entsprechenden Variablen:
spielfigur_1_x = 20
spielfigur_1_y = 20
spielfigur_1_bewegung = 0
spielfigur_2_x = FENSTERBREITE - (2 * 20)
spielfigur_2_y = 20
spielfigur_2_bewegung = 0
schlaegerhoehe = 60
# Schleife Hauptprogramm
Bei den Tasten, die wir für die Steuerung auswählen, nutzen wir nun aus Tradition die Tasten w und s.
In der Hauptschleife erweitern die Kontrolle für die Steuerung:
# Schleife Hauptprogramm
while spielaktiv:
# Überprüfen, ob Nutzer eine Aktion durchgeführt hat
for event in pygame.event.get():
if event.type == pygame.QUIT:
spielaktiv = False
print("Spieler hat Quit-Button angeklickt")
if event.type == pygame.KEYDOWN:
print("Spieler hat Taste gedrückt")
# Taste für Spieler 1
if event.key == pygame.K_UP:
print("Spieler hat Pfeiltaste runter gedrückt")
spielfigur_1_bewegung = -6
elif event.key == pygame.K_DOWN:
print("Spieler hat Pfeiltaste runter gedrückt")
spielfigur_1_bewegung = 6
# Taste für Spieler 2
elif event.key == pygame.K_w:
print("Spieler 2 hat w für hoch gedrückt")
spielfigur_2_bewegung = -6
elif event.key == pygame.K_s:
print("Spieler 2 hat s für runter gedrückt")
spielfigur_2_bewegung = 6
# zum Stoppen der Spielerbewegung
if event.type == pygame.KEYUP:
print("Spieler hat Taste losgelassen")
# Tasten für Spieler 1
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
print("Spieler 1 stoppt bewegung")
spielfigur_1_bewegung = 0
# Tasten für Spieler 2
elif event.key == pygame.K_w or event.key == pygame.K_s:
print("Spieler 1 stoppt bewegung")
spielfigur_2_bewegung = 0
Und erweitern die Spiellogik:
# Spiellogik
if spielfigur_1_bewegung != 0:
spielfigur_1_y += spielfigur_1_bewegung
if spielfigur_1_y < 0:
spielfigur_1_y = 0
if spielfigur_1_y > FENSTERHOEHE - schlaegerhoehe:
spielfigur_1_y = FENSTERHOEHE - schlaegerhoehe
if spielfigur_2_bewegung != 0:
spielfigur_2_y += spielfigur_2_bewegung
if spielfigur_2_y < 0:
spielfigur_2_y = 0
if spielfigur_2_y > FENSTERHOEHE - schlaegerhoehe:
spielfigur_2_y = FENSTERHOEHE - schlaegerhoehe
Und noch den Schläger für den zweiten Spieler zeichnen:
# Spielfeld/figuren zeichnen
# -- Ball
pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCHMESSER])
# -- Spielerfigur 1
pygame.draw.rect(screen, WEISS, [spielfigur_1_x, spielfigur_1_y, 20, schlaegerhoehe])
# -- Spielerfigur 2
pygame.draw.rect(screen, WEISS, [spielfigur_2_x, spielfigur_2_y, 20, schlaegerhoehe])
Somit haben wir die Interaktion vom den 2 Spieler eingebaut, die nun Ihre Schläger bewegen können. Nun sollte der Ball noch entsprechend reagieren, wenn dieser auf die Schläger auftrifft: Wir benötigen eine Kollisionskontrolle. Diese schauen wir uns im folgenden Kapitel an.
Alle Kürzel für die komplette Tastatur
Zum Abrunden des Kapitels über die Steuerug durch Tastatureingaben hier alle Bezeichnungen der Tasten um diese über Pygame abfragen zu können.
Pygame Code | Bezeichnung |
---|---|
K_BACKSPACE | Backspace-Taste (dt. Rücktaste) |
K_RETURN | Return |
K_TAB | Tab-Taste |
K_ESCAPE | Escape |
K_SPACE | Leertaste |
K_COMMA | , Komma |
K_MINUS | - Minus |
K_PERIOD | period slash |
K_SLASH | / Schrägstrich |
K_0 | 0 |
K_1 | 1 |
K_2 | 2 |
K_3 | 3 |
K_4 | 4 |
K_5 | 5 |
K_6 | 6 |
K_7 | 7 |
K_8 | 8 |
K_9 | 9 |
K_SEMICOLON | ; Semikolon |
K_EQUALS | = Gleichheitszeichen |
K_LEFTBRACKET | [ linke Klammer |
K_RIGHTBRACKET | ] rechte Klammer |
K_BACKSLASH | Rückwärtsschrägstrich |
K_BACKQUOTE | rückwärts geneigtes Hochkomma |
K_a | a |
K_b | b |
K_c | c |
K_d | d |
K_e | e |
K_f | f |
K_g | g |
K_h | h |
K_i | i |
K_j | j |
K_k | k |
K_l | l |
K_m | m |
K_n | n |
K_o | o |
K_p | p |
K_q | q |
K_r | r |
K_s | s |
K_t | t |
K_u | u |
K_v | v |
K_w | w |
K_x | x |
K_y | y |
K_z | z |
K_DELETE | Taste delete |
K_KP0 | Zehnerblock 0 |
K_KP1 | Zehnerblock 1 |
K_KP2 | Zehnerblock 2 |
K_KP3 | Zehnerblock 3 |
K_KP4 | Zehnerblock 4 |
K_KP5 | Zehnerblock 5 |
K_KP6 | Zehnerblock 6 |
K_KP7 | Zehnerblock 7 |
K_KP8 | Zehnerblock 8 |
K_KP9 | Zehnerblock 9 |
K_KP_PERIOD | . Zehnerblock Punkt |
K_KP_DIVIDE | // Zehnerblock geteilt |
K_KP_MULTIPLY | * Zehnerblock mal |
K_KP_MINUS | - Zehnerblock Minus |
K_KP_PLUS | Zehnerblock Plus |
K_KP_ENTER | Zehnerblock Enter |
K_KP_EQUALS | = Zehnerblock Gleich |
K_UP | Pfeil hoch |
K_DOWN | Pfeil nach unten |
K_RIGHT | Pfeil rechts |
K_LEFT | Pfeil links |
K_INSERT | Taste Einfügen |
K_HOME | Taste Home |
K_END | Taste Ende |
K_PAGEUP | Taste Seite hoch |
K_PAGEDOWN | Taste Seite nach unten |
K_F1 | F1 |
K_F2 | F2 |
K_F3 | F3 |
K_F4 | F4 |
K_F5 | F5 |
K_F6 | F6 |
K_F7 | F7 |
K_F8 | F8 |
K_F9 | F9 |
K_F10 | F10 |
K_F11 | F11 |
K_F12 | F12 |
K_NUMLOCK | Taste numlock |
K_CAPSLOCK | Feststelltaste |
K_RSHIFT | Shift rechts |
K_LSHIFT | Shift links |
K_RCTRL | ctrl (STRG) Taste rechts |
K_LCTRL | ctrl (STRG) Taste links |
K_RALT | alt-Taste rechts |
K_LALT | alt-Taste links |