Python Tutorial
- jetzt Python programmieren lernen

Steuerung durch Spieler: Tastatur, Maus und Game Controller

PyGame unterstützt uns und das einbinden der Steuerung 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 Spielersteuerung 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 unsere 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 unser 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 Spielevorlage 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) bzw. mit einer negativen Zahl (für die Bewegung nach oben) ändern. Weil unsere Spielfigur sich nur nach oben bzw. nach unten bewegen kann, reicht eine Variable aus!

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 PyGame-Vorlage um die Möglichkeit, das Spiel auch mit der Escape-Taste beenden zu können. Somit kann es 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 Spielerabfrage und dem eigentlichen Zeichnen! Sonst kommt ersten schnell Chaos in die Programmierung und zweitens können wir die Spielefigur (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 Variante als 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 das untere Fensterbereich und vorstellen, dann sollten wir die Höhe des Schlägers berücksichtigen. Die folgende Variante ist suboptimal:

    if spielfigur_1_y > FENSTERHOEHE:
        spielfigur_1_y = FENSTERHOEHE

Besser (noch nicht gut) 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 den Gedanken, 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 Spielelogik 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 Bewegungsvariable 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 oder ü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. 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 wegen können. Nun sollte der Ball noch entsprechend reagieren, wenn dieser auf die Schläger auftrifft. Sprich wir benötigen einen Kollisionskontrolle. Diese schauen wir uns im folgenden Kapitel an.

Alle Kürzel für die komplette Tastatur

Zum Abrunden des Kapitels über Tastatur hier alle Bezeichnungen der Tasten um diese über PyGames ansprechen 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