Python Tutorial
- jetzt Python programmieren lernen

Spiel Pong: Bewegung des Balls - Elemente animieren

Pong mit Python Pygame programmieren

Viele Spiele leben von der Aktion auf dem Bildschirm. Hier kommt nun die Animation von Elementen in unsere Programmierung. Wir werden im folgenden Kapitel einen Ball animieren, wie wir diese aus dem Spieleklassiker Pong kennen.

Hier spielen 2 Spieler praktisch Tischtennis (Ping-Pong) und der Blick auf das Spielfeld ist von oben auf die Platte, den Ball und die Schläger. Grafisch extrem simpel – was bei der Erstveröffentlichung von Pong 1972 so möglich war. Lustigerweise war der Begriff „Ping Pong“ geschützt und so wurde das Spiel Pong genannt.

Wir wollen jetzt nur einen Ball animieren, der immer, wenn der den Fensterrand erreicht, wieder im entsprechenden Winkel abprallt.

Dazu benötigen wir unser Grundgerüst aus dem Kapitel „Grundgerüst für Spiele mit Pygame“.

# Importieren der Pygame-Bibliothek
import pygame

# initialisieren von pygame
pygame.init()

# genutzte Farbe
ORANGE  = ( 255, 140, 0)
ROT     = ( 255, 0, 0)
GRUEN   = ( 0, 255, 0)
SCHWARZ = ( 0, 0, 0)
WEISS   = ( 255, 255, 255)

# Fenster öffnen
screen = pygame.display.set_mode((640, 480))

# Titel für Fensterkopf
pygame.display.set_caption("Unser erstes Pygame-Spiel")

# solange die Variable True ist, soll das Spiel laufen
spielaktiv = True

# Bildschirm Aktualisierungen einstellen
clock = pygame.time.Clock()

# 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")

    # Spiellogik hier integrieren

    # Spielfeld löschen
    screen.fill(SCHWARZ)

    # Spielfeld/figuren zeichnen

    # Fenster aktualisieren
    pygame.display.flip()

    # Refresh-Zeiten festlegen
    clock.tick(60)

pygame.quit()

Bei unserem Klassiker ist der Hintergrund des Spielfelds schwarz. Daher können wir jedes Mal, wenn wir unser Spielfeld neu aufbauen (sprich löschen) einfach unseren screen mit der Farbe Schwarz füllen:

    # Spielfeld löschen
    screen.fill(SCHWARZ)

Zur Erinnerung. Die Konstanten für die Farben (wie z.B. SCHWARZ) haben wir am Anfang unseres Pygame-Programmes definiert:

# genutzte Farbe
ORANGE  = ( 255, 140, 0)
SCHWARZ = ( 0, 0, 0)

Ball zeichnen für unser Spiel

Im letzten Kapitel haben wir bereits einen Kreis gezeichnet. Genau diesen wollen wir nun als Spielball nutzen.

    # Spielfeld/figuren zeichnen
    pygame.draw.ellipse(screen, WEISS, [10,30,20,20])
unser Spielball bei Pong

Wir platzieren unseren Ball am Anfang mit dieser Anweisung an den Punkt X=10 und Y=30

Allerdings wollen wir unseren Ball animieren. Also setzten wir diese Werte nicht fest als Zahl, sondern nutzen Variablen. Nennen wir diese ballpos_x und ballpos_y. Unsere Ballposition steckt also in diesen beiden Variablen, die wir vor der Hauptroutine definieren müssen:

# Definieren der Variablen
ballpos_x = 10
ballpos_y = 30

# Schleife Hauptprogramm
while spielaktiv:

Jetzt können wir diese Variablen beim Zeichnen unseres Kreises nutzen:

pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, 20, 20])

Unser Ball ruht nun in der Ecke und das Spiel wird extrem spannungslos ohne Bewegung (man könnte auch langweilig dazu sagen).

Ball bewegen (sprich animieren)

Jetzt können wir in unserer Hauptroutine diese 2 Werte bei jedem Schleifendurchlauf ändern und der Ball bewegt sich dann. Das muss innerhalb der Hauptroutine geschehen!

# 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

    # Spielfeld/figuren zeichnen
    pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, 20, 20])

    # bewegen unseres Kreises
    ballpos_x += 4
    ballpos_y += 4

Hurra, unser Spielball bewegt sich nach unten rechts. Und hoppla – er verschwindet auf Nimmerwiedersehen aus dem sichtbaren Bereich (und rollt unter irgendeinen Schrank bestimmt).

Also müssen wir darauf reagieren, wenn der Ball den Spielrand erreicht. Über das Erstellen der Fenstergröße wissen wir, ab wann der Ball aus dem sichtbaren Bereich verschwindet:

# Fenster öffnen
screen = pygame.display.set_mode((640, 480))

Und auch hier sollten wir nicht mit direkt eingetragenen Werten (im Beispiel 640 und 480) arbeiten, sondern mit Variablen (oder in dem Fall Konstanten), da diese Größen sich ja während dem gesamten Spielablauf nicht ändern.

Setzen wir also hier diese Zahlen als Konstanten:

FENSTERBREITE = 640
FENSTERHOEHE = 480

# Fenster öffnen
screen = pygame.display.set_mode((FENSTERBREITE, FENSTERHOEHE))

Die gewählten Begriffe im Deutschen sind zwar sehr lang, dafür sollte aber klar sein, welche Werte sich dahinter verbergen. Und jetzt können wir kontrollieren, ob der Ball das sichtbare Fenster verlassen möchte.

Ball am Fensterrand abprallen lassen

Wir kennen die Position des Balls über die Variablen ballpos_x und ballpos_y und wir kennen die Größe des Spielfelds anhand der Konstanten FENSTERBREITE und FENSTERHOEHE.

Überprüfen wir als Erstes, ob der Ball am unteren Rand ankommt. Hier wissen wir, wenn der Wert der Variable ballpos_y größer ist als die Konstante FENSTERHOEHE, dann sollten wir die Bewegungsrichtung ändern. Die Bewegungsrichtung ändern sich, indem wir die ballpos_y wieder verkleinern. Anstelle von „plus 4“ werden wir dann „minus 4“ rechnen.

Also benötigen wir eine Abfrage, bevor wir unseren Kreis bewegen. Bisher haben wir für unsere Bewegung:

    # bewegen unseres Kreises
    ballpos_x += 4
    ballpos_y += 4

Natürlich wollen wir auch hier nicht mit fest eingetragenen Werten wie im Beispiel „4“ arbeiten, sondern auch hier eine Variable nutzen. Eigentlich sollten wir die Variablen nennen wie z.B. „bewegungsaenderung_x“ – aber das ist deutlich zu lang. Wir nutzen dafür die Variablen mit der Bezeichnung bewegung_x und bewegung_y. Auch diese müssen außerhalb unserer Hauptschleife das erste Mal festgelegt werden, um dann in der Hauptschleife genutzt zu werden.

# Definieren der Variablen
ballpos_x = 10
ballpos_y = 30

bewegung_x = 4
bewegung_y = 4

Und innerhalb der Hauptschleife ändern wir von „ballpos_x += 4“ zu:

    # bewegen unseres Kreises
    ballpos_x += bewegung_x
    ballpos_y += bewegung_y

Jetzt wollen wir über eine if-Abfrage die Berührung des Fensterrands kontrollieren:

    if ballpos_y < FENSTERHOEHE:
        ballpos_y += bewegung_y
    else:
        ballpos_y -= bewegung_y

Das wäre im ersten Augenblick eine Variante, die aber leider dazu führt, dass der Ball bei Verlassen des unteren Fensterbereichs nicht nach oben fliegt, sondern dann nach rechts wegrutscht.

Wir müssen also EINMAL die Bewegungsrichtung ändern. Dazu nutzen wir den mathematischen Trick von * -1 . So können wir die Bewegungsrichtung „umschalten“. Zur Erinnerung an die alten Schulzeiten die 2 wichtigen Fälle von „mal minus 1“:

  • Haben wir ein + wird durch * -1 aus dem Plus ein Minus.
  • Haben wir ein – wird durch * -1 aus dem Minus ein Plus.
    • Die benötigten Variablen für die beiden Bewegungsrichtungen haben wir bereits und können dann darauf unsere Mathematik anwenden.

          if ballpos_y > FENSTERHOEHE:
              bewegung_y = bewegung_y * -1
      

      Wenn man es testet, dann verschwindet der Ball fast unten (darum kümmern wir uns später) und springt dann nach oben, um rechts zu verschwinden. Also kümmern wir uns um den rechten Rand. Hier dieselbe Vorgehensweise, nur für unsere x-Bewegung:

          if ballpos_x > FENSTERBREITE:
              bewegung_x = bewegung_x * -1
      

      Jetzt überlebt unser Ball unten und rechts, aber verschwindet oben aus dem Fensterrahmen bzw. links. Also auch hierfür die entsprechende Abfrage wobei wir einfach mit 0 vergleichen (was den oberen und den linken Fensterrand darstellt):

      Unsere bisher komplette Abfrage:

      
          if ballpos_y > FENSTERHOEHE:
              bewegung_y = bewegung_y * -1
      
          if ballpos_x > FENSTERBREITE:
              bewegung_x = bewegung_x * -1
      
          if ballpos_y < 0:
              bewegung_y = bewegung_y * -1
      
          if ballpos_x < 0:
              bewegung_x = bewegung_x * -1
      

      Das funktioniert zwar, aber kürzer ist schöner – also machen wir aus den 8 Zeilen nur noch 4 und fassen die if-Abfragen zusammen:

          if ballpos_y > FENSTERHOEHE or ballpos_y < 0:
              bewegung_y = bewegung_y * -1
      
          if ballpos_x > FENSTERBREITE or ballpos_x < 0:
              bewegung_x = bewegung_x * -1
      

      Jetzt haben wir noch den Schönheitsfehler, dass der Ball unten und rechts aus dem sichtbaren Bereich fast verschwindet. Unsere Rechnung ist bisher nicht exakt richtig: wir vergleichen die Ballposition mit der Fensterbreite (bzw. Höhe). Aber eigentlich ist die Breite (bzw. Höhe des Balls) auch noch ausschlaggebend. Daher sollten wir berechnen:

      (FENSTERHOEHE – Balldurchmesser)

      Und auch hier gehört eine Variable (bzw. Konstante her). Wir müssen diese Konstante bereits (wie die anderen auch) im Vorfeld definieren, können diese beim Zeichnen unseres Balls verwenden und dann bei der if-Abfrage einsetzen:

      Wieder wollen wir einen sprechenden Namen haben – wer die mathematischen Bezeichnungen gewohnt ist, wird „d“ für Durchmesser nehmen, sprich die Konstantenbezeichnung wäre dann „BALL_D“ – wir nutzen lieber für 100 % Transparenz den wuchtigen Namen: BALL_DURCHMESSER“

      Also Vorneweg definieren:

      # Definieren der Variablen/Konstanten
      ballpos_x = 10
      ballpos_y = 30
      
      BALL_DURCHMESSER = 20
      

      Und einsetzen beim Kreis zeichnen:

      
      pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCHMESSER])
      

      Und noch in der Abfrage wegen Fensterrand:

          if ballpos_y > FENSTERHOEHE - BALL_DURCHMESSER or ballpos_y < 0:
              bewegung_y = bewegung_y * -1
      
          if ballpos_x > FENSTERBREITE - BALL_DURCHMESSER or ballpos_x < 0:
              bewegung_x = bewegung_x * -1
      

      Und somit haben wir einen wunderbar herum springenden Ball. Wir können die Spielfeldgröße, Ballgröße und Geschwindigkeit durch Ändern der Werte bei der entsprechenden Variablen (bzw. Konstanten) schnell anpassen und alle Programmteile reagieren darauf.

      Hier der komplette Quellcode:

      
      # Importieren der Pygame-Bibliothek
      import pygame, math
      
      # initialisieren von pygame
      pygame.init()
      
      # genutzte Farbe
      ORANGE  = ( 255, 140, 0)
      ROT     = ( 255, 0, 0)
      GRUEN   = ( 0, 255, 0)
      SCHWARZ = ( 0, 0, 0)
      WEISS   = ( 255, 255, 255)
      
      FENSTERBREITE = 640
      FENSTERHOEHE = 480
      
      # Fenster öffnen
      screen = pygame.display.set_mode((FENSTERBREITE, FENSTERHOEHE))
      
      # Titel für Fensterkopf
      pygame.display.set_caption("Unser erstes Pygame-Spiel")
      
      # solange die Variable True ist, soll das Spiel laufen
      spielaktiv = True
      
      # Bildschirm Aktualisierungen einstellen
      clock = pygame.time.Clock()
      
      # Definieren der Variablen/Konstanten
      ballpos_x = 10
      ballpos_y = 30
      
      BALL_DURCHMESSER = 20
      
      bewegung_x = 4
      bewegung_y = 4
      
      # 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
      
          # Spiellogik hier integrieren
      
          # Spielfeld löschen
          screen.fill(SCHWARZ)
      
          # Spielfeld/figuren zeichnen
          pygame.draw.ellipse(screen, WEISS, [ballpos_x, ballpos_y, BALL_DURCHMESSER, BALL_DURCHMESSER])
      
          # bewegen unseres Kreises
          ballpos_x += bewegung_x
          ballpos_y += bewegung_y
      
          if ballpos_y > FENSTERHOEHE - BALL_DURCHMESSER or ballpos_y < 0:
              bewegung_y = bewegung_y * -1
      
          if ballpos_x > FENSTERBREITE - BALL_DURCHMESSER or ballpos_x < 0:
              bewegung_x = bewegung_x * -1
      
          # Fenster aktualisieren
          pygame.display.flip()
      
          # Refresh-Zeiten festlegen
          clock.tick(60)
      
      pygame.quit()
      quit()
      

      Weiterempfehlen • Social Bookmarks • Vielen Dank

Bitte unterstützen Sie dieses Projekt

Sie können dieses Projekt in verschiedenen Formen unterstützen - wir würden uns freuen und es würde uns für weitere Inhalte motivieren :).

Empfehlen Sie es weiter - wir freuen uns immer über Links und Facebook-Empfehlungen.

Das neue E-Book zum Kurs gibt es zum Kaufen.

Sie können uns auch eine Spende über PayPal zukommen lassen.

Bestellen Sie Bücher über folgenden Link bei Amazon:
Bücher über Python

Vielen Dank für Ihre Unterstützung