5. Animationsschleife

Will man eine Bewegung simulieren, so verwendet man häufig das Prinzip eines „Game-Loop“. Dies ist eine Schleife, die immer und immer wieder durchgeführt wird. Dabei wird die „Spielwelt“ in jedem Durchgang der Schleife gelöscht (clear) und neu gezeichnet. Zwischen jedem Durchlauf der Schleife werden auch alle Positionen der vorhandenen Objekte etc. neu berechnet. Häufig werden Positionen der Objekte in globalen Variablen gespeichert.

Hier ein Mini-Beispiel: Ein Kreis soll sich von links nach rechts bewegen. Die Position des Kreises stellen wir mit den globalen Variablen x und y dar. Bei jedem Durchlauf wird 40 Millisekunden gewartet, das Bild gelöscht und der x-Wert vergrössert.

from gturtle import *

# x und y-Position
x = -200
y = 0
running = True # solange dies True ist, wird Animation laufen

# wenn Maus gedrückt wird, soll Programm abbrechen
def onMouseHit(x,y):
    global running
    running = False

makeTurtle(mouseHit=onMouseHit)
hideTurtle()
setPenColor("red")

while running:
  clear()
  setPos(x,y)
  dot(40)
  delay(40) 
  x = x + 4 

Aufgabe 1

Ändere das Beispiel, sodass sich der Punkt von links unten nach rechts oben bewegt.

Aufgabe 2

Ändere das Beispiel, sodass der Punkt an den Rändern zurückprallt. Tipp: setze eine Variable auf +4 und addiere dann die Variable. Wenn der Rand erreicht wird, muss du nur die Variable auf -4 setzen…

Lösung

from gturtle import *
 
# x und y-Position
x = -400
y = 0
running = True # solange dies True ist, wird Animation laufen
dx = 8
dy = 8
 
# wenn Maus gedrückt wird, soll Programm abbrechen
def onMouseHit(x,y):
    global running
    print("Jupp")
    running = False
 
makeTurtle(mouseHit=onMouseHit)
hideTurtle()
setPenColor("red")
 
while running:
  clear()
  setPos(x,y)
  dot(40)
  delay(40) 
  x = x + dx
  y = y + dy
  if x > 400:
    dx = -8
  if x < -400:
    dx = 8
  if y > 300:
    dy = -5
  if y < -300:
    dy = 5
    

Aufgabe 3

Ändere das Beispiel, sodass sich der Punkt in einem Kreis mit Radius 300 im Gegenuhrzeigersinn bewegt. Denke dabei an den Einheitskreis aus der Mathematik, in welchem wir Sinus und Cosinus definiert haben. (Tipp: Punkt P(300Cos(x); 300Sin(x))

Lösung

from gturtle import *
import math # Mathe-Bibliothek laden für sin, cos
  
alpha = 0 # Startwinkel
running = True # solange dies True ist, wird Animation laufen
 
# wenn Maus gedrückt wird, soll Programm abbrechen
def onMouseHit(x,y):
    global running
    running = False
  
makeTurtle(mouseHit=onMouseHit)
hideTurtle()
setPenColor("red")
enableRepaint(False) # selbst angeben wann neu gezeichnet wird (mit repaint())
  
while running: #Game-Loop
  clear() # Bildschirm löschen 
  x = 250*math.cos(alpha) #x- und y-Wert setzen
  y = 250*math.sin(alpha)
  setPos(x,y)
  dot(40)
  repaint() #neu zeichnen (manuell um flackern zu verhindern)
  delay(40)
  alpha = alpha + 0.02
 

Aufgabe 4

Ändere das Beispiel, sodass man mit den Cursortasten den Punkt bewegen kann.

Lösung

from gturtle import *
import math # Mathe-Bibliothek laden für sin, cos
   
x = 0 # x- und y-Position
y = 0

dx = 0 #Änderung in x und y-Richtung
dy = 0

running = True # solange dies True ist, wird Animation laufen
  
# wenn Maus gedrückt wird, soll Programm abbrechen
def onMouseHit(x,y):
    global running
    running = False
    
def onKeyPressed(keycode):
    global dx
    global dy
    if keycode == 37:
        dy = 0
        dx = -5
    if keycode == 38:
        dx = 0
        dy = 5
    if keycode == 39:
        dx = 5
        dy = 0
    if keycode == 40:
        dx = 0
        dy = -5
   
makeTurtle(mouseHit=onMouseHit, keyPressed=onKeyPressed)
hideTurtle()
setPenColor("red")
enableRepaint(False) # selbst angeben wann neu gezeichnet wird (mit repaint())
   
while running: #Game-Loop
  clear() # Bildschirm löschen 
  x = x + dx
  y = y + dy
  setPos(x,y)
  dot(40)
  repaint() #neu zeichnen (manuell um flackern zu verhindern)
  delay(40)

Aufgabe 5

Ändere das Beispiel, so dass man mit den Cursortasten die Geschwindigkeit des Punktes in eine beliebige Richtung verändern kann. Tipp: Wenn die Tasten gedrückt werden, so änderst du eine Variable VelocityX bzw. VelocityY. Je grösser diese Variablen sind, desto mehr addiert/subtrahiert man dann bei der Position x bzw. y.

Lösung


from gturtle import *
   
x = 0 # x- und y-Position
y = 0

dx = 0 #Änderung in x und y-Richtung
dy = 0

running = True # solange dies True ist, wird Animation laufen
  
# wenn Maus gedrückt wird, soll Programm abbrechen
def onMouseHit(x,y):
    global running
    running = False
    
def onKeyPressed(keycode):
    global dx
    global dy
    if keycode == 37:
        dx = dx - 1
        print(dx)
    if keycode == 38:
        dy = dy + 1
    if keycode == 39:
        dx = dx + 1
    if keycode == 40:
        dy = dy - 1
   
makeTurtle(mouseHit=onMouseHit, keyPressed=onKeyPressed)
hideTurtle()
setPenColor("red")
enableRepaint(False) # selbst angeben wann neu gezeichnet wird (mit repaint())
   
while running: #Game-Loop
  delay(40)
  clear() # Bildschirm löschen
  x = x + dx
  y = y + dy
  print(x,y)
  setPos(x,y)
  dot(40)
  repaint() #neu zeichnen (manuell um flackern zu verhindern)
  

Aufgabe 6

Jetzt versuchen wir ein kleines Spiel zu programmieren und zwar ein ähnliches Spiel wie Superball auf SAT 1.

  1. Nimm die Lösung von Aufgabe 4 als Vorlage
  2. Versuche das Beispiel so zu ändern, dass der Spieler-Ball unten dargestellt wird und dass man ihn nur nach rechts/links bewegen kann
  3. Füge einen „Gegnerball“ hinzu, der von ganz oben nach unten fällt
  4. Versuche dein Beispiel so zu erweitern, dass der Ball wieder oben startet, wenn er unten rausfällt (idealerweise an einer zufälligen x-Position)
  5. Versuche die Kollision zu testen (wenn der y-Wert des Gegnerballs in einem Bestimmten Bereich ist, kann man testen, ob die x-Werte der beiden Bälle zu nahe sind…)

Grundgerüst für ein Spiel

Es folgt ein Grundgerüst für ein Spiel.

from gturtle import *
import math # Mathe-Bibliothek laden für sin, cos
from random import randint # die randint-Funktion aus de random-Bibliothek laden    

#===============================================================================
# Hier wird die Spiele-Welt definiert (Position, Geschw. der Objekte etc.

 
running = True # solange dies True ist, wird Animation laufen
#===============================================================================   
     
def onKeyPressed(keycode):
    global dx
    global dy
    global running
    if keycode == 37:
        dy = 0
        dx = -5
    if keycode == 38:
        dx = 0
        dy = 5
    if keycode == 39:
        dx = 5
        dy = 0
    if keycode == 40:
        dx = 0
        dy = -5
    if keycode == 27: # Esc-Button
        running = False
    
makeTurtle(keyPressed=onKeyPressed)
hideTurtle()
setPenColor("red")
enableRepaint(False) # selbst angeben, wann neu gezeichnet wird (mit repaint())

def calculateNewPositions():
    pass

def detectCollisions():
    pass

def drawWorld():
    pass
#===============================================================================
# Game-Loop
#===============================================================================    
while running: #Game-Loop
  clear() # Bildschirm löschen 
  calculateNewPositions() # neue Position bestimmen
  detectCollisions() # Kollisionen prüfen
  drawWorld() # Welt neu zeichnen
  repaint() #neu zeichnen (manuell um flackern zu verhindern)
  delay(40)