====== Animation von Grafikobjekten (die act-Methode) ====== Alle modernen Game-[[https://de.wikipedia.org/wiki/Programmierschnittstelle|APIs]] besitzen eine [[https://gameprogrammingpatterns.com/game-loop.html|Game-Loop]], die fortwährend läuft und mit konstanter Frequenz (i.d.R. 60-mal pro Sekunde) eine Methode zur Berechnung des neuen Spielzustands aufruft ([[https://gameprogrammingpatterns.com/update-method.html|Update Method]]). Diese wiederum ruft die Update-Methode aller Spielobjekte auf, so dass auch diese ihren neuen Zustand berechnen können. Anschließend wird der Bildschirm gelöscht und alle graphischen Objekte werden neu gezeichnet (Rendering). \\ \\ Auch in unserer Programmier-API gibt es diese Game-Loop. Sie wird 30-mal pro Sekunde aufgerufen und ruft ihrerseits die Update-Methode aller Spielobjekte auf, genauer: Diese Methode heißt ''act'' und ist in allen Klassen enthalten, die Unterklassen der Klasse ''Actor'' sind, insbesondere auch in allen Grafikklassen (''Rectangle'', ''Circle'', ...). \\ \\ Wenn wir also eine Klasse schreiben, die von einer Grafikklasse (oder direct von der Klasse ''Actor'') erbt, können wir diese ''act''-Methode mit unserer eigenen ''act''-Methode überschreiben, so dass dann **diese** 30-mal pro Sekunde aufgerufen wird. \\ \\ Klingt kompliziert? Keine Angst, anhand der folgenden Beispiele lernst Du schnell, wie es geht und welche großartigen Möglichkeiten sich Dir damit eröffnen!
===== Beispiel 1: Drehendes Rechteck ===== * Starte das Programm und regle die Geschwindigkeit hoch/runter. -> Die Winkelgeschwindigkeit des Rechtecks ändert sich nicht, da die ''act''-Methode mit konstanter Frequenz (30-mal pro Sekunde) aufgerufen wird. * Die Bewegung des Rechtecks ist sehr weich (ohne Ruckeln), da die ''act''-Methode im Gleichtakt mit der Render-Methode (s.o.) aufgerufen wird.
===== Beispiel 2: Hin- und herbewegende Rechtecke ===== * Das ''MovingRectangle''-Objekt muss jederzeit "wissen", ob es sich gerade unterwegs zum rechten oder linken Rand befindet. Es benötigt daher ein Attribut, das diesen Zustand speichert. Wir verwenden das Attribut ''int dx'', in dem wir speichern, um wie viel sich das Rechteck im nächsten Schritt in x-Richtung bewegt. Ist ''dx == -8'', so bewegt sich das Rechteck nach links, ist ''dx == 8'', so bewegt sich das Rechteck nach rechts.
===== Beispiel 3: Fliegende Bälle ===== Jetzt wird's Zeit für ein anspruchsvolleres Beispiel: Wir wollen Bälle simulieren, die vom der Mitte des unteren Bildschirmrandes aus hochgeworfen werden und sich unter dem Einfluss der Gravitationskraft möglichst "natürlich" bewegen. Dazu nutzen wir die [[https://www.leifiphysik.de/uebergreifend/allgemeines-und-hilfsmittel/ausblick/methode-der-kleinen-schritte|Methode der kleinen Schritte]]. Sie bedeutet in unserem Fall, dass wir jede 30-tel Sekunde die neuen Werte für die Position ($x_{neu}, y_{neu}$) und die Geschwindigkeit ($v_{x, neu}, v_{y, neu}$) aus den alten Werten $x, y, vx, vy$ folgendermaßen berechnen: $$v_{x, neu} = v_x$$ $$v_{y, neu} = v_y - g\cdot\Delta t$$ $$x_{neu} = x + v_{x, neu}\cdot\Delta t$$ $$y_{neu} = y + v_{y, neu}\cdot\Delta t$$ Das $g$ in der zweiten Gleichung ist die Erdbeschleunigung $g = 9,81\frac{m}{s^2}$. Aus dem "-" wird im Programm ein "+", da die Y-Achse nach unten zeigt. $\Delta t$ ist in unserem Fall $\frac{1}{30} s$.\\ \\ Als Spieleprogrammierer wollen wir natürlich, dass der Algorithmus möglichst schnell abläuft. Wir setzen daher $$\Delta t = 1 s$$ und passen dafür die Anfangsgeschwindigkeit und die Beschleunigung etwas an. Da sich $v_x$ nicht ändert, ist bei jedem Zeitschritt also nur noch folgendes zu tun: $$v_{y, neu} = v_y + g$$ $$x_{neu} = x + v_x$$ $$y_{neu} = y + v_{y, neu}$$ Als Physiklehrer überfällt mich ein großes Unbehagen, wenn ich an die Einheiten der drei obigen Gleichungen denke. Stellt Euch daher rechts jeweils "$\cdot 1 s$ vor, damit Ihr wieder ruhig schlafen könnt ;-) Als Programmierer freue ich mich aber über die einfache und performante Umsetzung. Die zweite und dritte Gleichung zusammengenommen lassen sich jetzt nämlich mit einer einzigen Java-Anweisung erledigen: ''move(vx, vy)''. \\ \\ === Erzeuger-Objekt === Im [[#beispiel_2hin-_und_herbewegende_rechtecke|Beispiel mit den hin- und herbewegenden Rechtecken]] haben wir die neuen Rechtecke im Hauptprogramm erzeugt. Das ist problematisch, da bei vielen Laufenden actor-Methoden nicht sichergestellt ist, mit welcher Geschwindigkeit das Hauptprogramm durchlaufen wird. Stell Dir vor, in einem Spiel würde die Rate, mit der vom Rechner Gegner erzeugt werden, von der Geschwindigkeit Deines Rechners abhängen! \\ Wir wollen es diesmal besser machen und erledigen die Erzeugung der Bälle ebenfalls in einem Ereignis-Handler. Dazu erstellen wir die Klasse ''Erzeuger'' als Unterklasse von ''Actor''. Letztere besitzt eine ''act''-Methode, die 30-mal pro Sekunde aufgerufen wird. Wir überschreiben sie mit einer eigenen Methode, die bei jedem fünften Aufruf einen neuen Ball erzeugt.
===== Beispiel 4: Feuerwerk ===== Dieses Beispiel habe ich als Wiederholungsübung für meine zehnten Klassen im Schuljahr 2020/21 geschrieben. Damals war wegen er Corona-Epidemie das Sylvesterfeuerwerk ausgefallen. {{ youtube>4OY-p4M4hpY?large }}