====== 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 [[https://www.youtube.com/watch?v=p2l04VawHe8|Superball auf SAT 1]]. - Nimm die Lösung von Aufgabe 4 als Vorlage - Versuche das Beispiel so zu ändern, dass der Spieler-Ball unten dargestellt wird und dass man ihn nur nach rechts/links bewegen kann - Füge einen "Gegnerball" hinzu, der von ganz oben nach unten fällt - Versuche dein Beispiel so zu erweitern, dass der Ball wieder oben startet, wenn er unten rausfällt (idealerweise an einer zufälligen x-Position) - 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)