Animationen


In p5.js wird die Funktion setup() {...} beim Programmstart ein einziges Mal ausgeführt. Der Computer versucht die Funktion draw() {...} so oft auszuführen, wie es mit der Anweisung frameRate(60) eingestellt wird. Bei hohen Frame-Raten (= Anzahl der Neuberechnungen des Zeichenbereichs pro Sekunde) schafft der Computer das meistens nicht, so dass die wirkliche Frame-Rate niedriger ist als die gewünschte. Die aktuelle Frame-Rate wird ausgegeben, wenn man die Funktion frameRate() ohne Argument aufruft. Gibst du keine Frame-Rate an, stellt p5.js diese auf 60 Frames pro Sekunde (= 60 fps) ein.

In der Variablen frameCount wird gespeichert, wie viele Frames seit Programmstart berechnet wurden. Mit Hilfe dieser Variablen kann man ein Objekt animieren, indem man z.B. die x-Koordinate mit Hilfe von frameCount angibt.

Beispiel

// Der Kreis wird bei jedem Frame um ein Pixel nach rechts verschoben, 
// da frameCount bei jedem Frame 1 groesser wird.
ellipse(frameCount, 200, 100, 100);

// Der Kreis wird bei jedem Frame um einen Pixel nach unten verschoben,
// da frameCount bei jedem Frame 1 groesser wird.    
ellipse(100, frameCount, 100, 100);

Du kannst jederzeit in deinen Programmcode Kommentare einfügen, indem du vor einen Text zwei // einfügst.

Du kannst auch die Größe von Objekten mit Hilfe der Variablen FrameCount verändern.

Wenn die Anweisung background('aliceblue'); (= färbe den Hintergrund mit der Farbe aliceblue) in setup() {...} steht, wird der Hintergrund nur beim Programmstart eingefärbt. Alles was in draw() {...} gezeichnet wird, wird an die neue Position mit der neuen Größe gezeichnet, aber Vorhandenes bleibt erhalten.


Animationen mit eigenen Variablen steuern

Anstelle der Variablen frameCount, kannst du für die Steuerung der Kreise auch eigene Variablen verwenden.

Dazu legst du eigene Variablen fest (hier xDelta und yDelta) und veränderst diese am Ende der draw()-Funktion. Die draw()-Funktion wird ja viele Male pro Sekunde durchlaufen und bei jedem Durchlauf werden die beiden Variablen verändert. Dadurch entsteht der Eindruck einer Animation.


Mit Hilfe einer if-Abfrage kannst du den Ablauf der Animation steuern.

if (xDelta > width) {
  xRichtung = -1;
}
if (xDelta < 0) {
  xRichtung = 1;
}
xDelta = xDelta + xRichtung;  

Erklärung:

  • Wenn xDelta größer ist als die Breite der Zeichenfläche, dann ist die Mitte des Kreises rechts ausserhalb der Zeichenfläche. Damit der Kreis wieder umdreht, soll xRichtung = -1 sein. Wenn xRichtung = -1 ist, dann wird xDelta wieder kleiner, da xDelta + (-1) kleiner wird.
  • Wenn xDelta negativ wird, dann befindet sich die Mitte des Kreises links ausserhalb des Zeichenbereichs. Damit der Ball wieder umdreht, setzt man xRichtung = 1 und xDelta wird wieder größer.

Die Intervalle kannst du auch anders setzen.


Zufällige Unruhe in der Animation

Random

Mit Hilfe der random-Funktion kann man etwas Unruhe in die Animation bringen. Zum Beispiel gibt random(-2, 3); eine zufällige Zahl zwischen -2 und 3 zurück. Dadurch erscheint die Bewegung zufällig.


Noise

Mit Hilfe der noise-Funktion sieht das etwas eleganter aus.

Erklärung

Beim Programmstart erzeugt p5.js eine zufällige Wertemenge mit Hilfe der noise()-Funktion. Diese Zufallsmenge bleibt während des Programmablaufs unverändert. Diese Wertemenge enthält Zufallszahlen, die nahe nebeneinander liegen (die Funktionswerte sind stetig). Mit noise(zufallsstelle); wird der Zufallswert an der Stelle zufallsstelle ausgegeben. Erhöht man zufallsstelle ein klein wenig (zufallsstelle = zufallstelle + 0.01;), dann bekommt man den Zufallswert an der neuen Stelle, dessen Wert nahe neben dem Wert des alten liegt. Dadurch liegen die erzeugten Zufallszahlen zufällig nahe nebeneinander und es entsteht der Eindruck einer allmählichen stetigen Änderung.

Um den noise()-Zufallsgenerator nutzen zu können, benötigt man also eine Variable z.B. zufallsstelle, die man während des Programmablaufs in kleinen Schritten verändert.

Da wir hier 2 Kreise in 2 Richtungen bewegen möchten, brauchen wir 4 Zufallswerte. Die 4 Zufallsstellen werden beim Programmstart zufällig aber verschieden voneinander gesetzt:

var zufallsstelle1 = 110;
...

Während des Programmablaufs werden bei jedem Durchlauf der draw-Funktion 4 Zufallswerte mit Hilfe der noise-Funktion verändert.

zufallswert1 = zufallswert1 + map(noise(zufallsstelle1), 0, 1, -10, 10);
...

Mit map(noise(zufallsstelle1), 0, 1, -10, 10); erzeugt man die zufällige nahezu stetige Änderung:

  • noise(zufallsstelle1) holt den noise-Zufallswert an der noise-Zufallsstelle, die beim Programmanfang zufällig mit var zufallsstelle1 = 110; herausgesucht wurde.
  • map(zahl, 0, 1, -10, 10) ist eine p5.js-Funktion, mit welcher der Wert der Variablen zahl vom Intervall [0, 1] auf das Intervall [-1, 1] passend umgerechnet wird. Das muss gemacht werden, da die noise-Funktion nur Funktionswerte zwischen 0 und 1 ausgibt. Die Kreise sollen sich in alle Richtungen bewegen, also brauchen wir dazu Werte zwischen -1 und 1.

Mit zufallsstelle1 = zufallsstelle1 + 0.01; wird die noise-Zufallsstelle um 0.01 verschoben, so dass beim nächsten Frame ein anderer, aber in der Nähe liegender noise-Zufallswert ausgegeben wird. Damit entsteht der Eindruck, dass sich die Kreise kontinuierlich bewegen und nicht auf der Zeichenfläche herumhüpfen.


Animation mit Modulo (%)

Eine weitere Möglichkeit, eine Animation zu steuern, ist der Modulo-Operator %. Wir suchen eine Möglichkeit, dass Zahlen sich wiederholen. Da frameCount eine Zahl ist, die bei jedem Frame um 1 größer wird, brauchen wir einen mathematischen Trick.

Der mathematische Trick

  • width ist die Breite der Zeichenfläche und height ist die Höhe der Zeichenfläche, also die Zahlen, die bei der Funktion createCanvas(breite, hoehe); angegeben wurden.
  • frameCount % width hat als Ergebnis den Rest der Rechnung frameCount : width (geteilt durch).
  • Also durchläuft frameCount % width alle natürlichen Zahlen von 0 bis width und springt dann wieder zur 0.

Damit hat man eine Zahl, die ein Intervall durchläuft und dann wieder an den Anfang springt.

Beispiel

Beobachte die Veränderung der Werte und verändere die Breite und Höhe der Zeichenfläche, indem du in createCanvas(350, 300); die Zahlen veränderst. Die Geschwindigkeit der Animation kannst du verändern indem du die Zahl in frameRate(40); änderst.


Du kannst auch eigene Werte dafür festlegen, wann ein Kreis zurückspringen soll.

Beispiel

Verändere die Werte für xReset und yReset und beobachte die Veränderung der Werte.


Alle anderen Parameter der Kreise kannst du man mit Hilfe von Modulo auch periodisch verändern.


Animation mit Sinus

Sinus ist eine mathematische Funktion, mit deren Hilfe periodische Vorgänge elegant animiert werden können. Bei der Animation mit Hilfe von Modulo hast du gesehen, dass nach dem Durchlaufen das Objekt an den Anfang zurückspringt. Mit Hilfe der Sinus-Funktion kann man Objekteigenschaften hin- und herschwingen lassen.

Die Sinusfunktion hat nur y-Werte zwischen -1 und 1, ganz egal wie groß oder klein die x-Werte sind, aus denen die Sinusfunktion die y-Werte berechnet. Und die y-Werte der Sinusfunktion ändern sich harmonisch.

Klappt schon, ist aber noch deutlich zu hektisch. Wir müssen also die x-Werte verlangsamen, indem frameCount durch z.B. 10 geteilt wird.

Sieht schon besser aus. Schauen wir uns die Mathematik genauer an. Beim grünen Kreis ändert sich die x-Koordinate mit folgender Anweisung:

180 + sin(frameCount/10) * 80
Erklärung:
  • frameCount ist eine Variable, deren Wert bei 0 beginnend, während des Programmablaufs immer größer wird.
  • sin(frameCount) gibt einen Wert zwischen -1 und 1 zurück. Da alle Werte der Sinusfunktion zwischen 0 und 6.28 einmal auftreten, liefert sin(frameCount) nur 4 verschiedene Werte, nämlich sin(0); sin(1); sin(2); sin(3). Dann ist ein Durchlauf zwischen -1 und 1 beendet. Das sind zu wenige Werte, um die Animation flüssig zu gestalten.
  • Daher teilt man frameCount im Argument von Sinus durch 10 (sin(frameCount/10)), um 10 Mal so viele Werte zwischen -1 und 1 zu bekommen.
  • Die Werte zwischen -1 und 1 werden jetzt mit 80 multipliziert, so dass man Werte zwischen -80 und 80 bekommt.
  • Die Werte zwischen -80 und 80 werden dann zu 180 addiert, so dass die x-Koordinate Werte zwischen 100 und 260 annimmt.
  • Wenn die Animation langsamer ablaufen soll, setzt du in sin(frameCount/10) statt 10 zum Beispiel 15 oder 20 ein.

Aufgabe

Welche Zahlen müssen in folgendem Ausdruck für a, b und c eingesetzt werden, damit du Werte zwischen 100 und 500 bekommst?

a + sin(frameCount/b) * c
Lösung
// a = 300 ist die Mitte des Intervalls
// Mit b = 15 steuerst du die Geschwindigkeit der Animation
// c = 200 ist der Radius des Intervalls
300 + sin(frameCount/15) * 200

Aufgabe

Versuche weitere Intervalle zu Durchlaufen, z.B. von -500 bis +500.


Beispiel

Im folgenden Beispiel stehen für x jeweils andere Zahlen im Ausdruck sin(frameCount/x). Dadurch ist die Animationsgeschwindigkeit für jeden Kreis anders. Beim braunen Kreis ist die Animationsgeschwindigkeit in x-Richtung eine andere als in y-Richtung, wodurch sich dieser Kreis nicht mehr hin- und herbewegt, sondern eine komplizierte Kurve fliegt.

Verändere die Werte und beobachte die Wirkung.

Alle anderen Parameter lassen sich auch wieder verändern.


Wir bauen eine Welle

Jetzt wird es mathematisch ein klein wenig anspruchsvoller. Wenn dir das im Moment zu viel ist, dann such dir doch ein anderes Kapitel, das dich mehr interessiert.

Mit Hilfe einer for-Schleife können wir viele gleichartige Kreise gleich schwingen lassen.

Aufgabe

Versuche eine Welle zu bauen, bei der sich die Kreise wie eine Seilwelle bewegen.

Lösung

Versuche die Lösung zu verstehen. Wenn du die Sinus-Funktion schon im Unterricht hattest, könnte das helfen.


Erklärung

Um eine Welle zu erzeugen, muss jeder Kreis etwas später mit seiner Schwingung dran sein, als der Kreis vor ihm. Man muss es also schaffen, die for-Schleife dafür zu nutzen, eine Verschiebung der Schwingung zwischen den Kreisen hinzubekommen. Das macht man mit der folgenden Mathematik:

sin(frameCount/22-((2*PI/20)*i))
  • Mit frameCount/22 stellt man die Geschwindigkeit der Hin- und Herbewegung ein. Je größer der Divisor (hier 22), desto schneller die Schwingung.
  • Wir haben 20 Kreise. Also soll jeder Kreis einen anderen Wert der Sinus-Funktion bekommen. Dazu ziehen wir von frameCount/22 einen Zahlenwert ab, der mit der Zählvariable i größer wird. Aber welchen Wert?
  • Um das zu verstehen muss dir klar sein, dass sich die Sinusfunktion wiederholt. Weil das so häufig in der Mathematik verwendet wird, hat man der Zahl, ab der die Sinusfunktion das erste Mal wieder den gleichen Wert hat, einen Namen gegeben: PI. Bei 2 PI ist der Wert der Sinusfunktion ein zweites Mal wieder 0 und die Werte wiederholen sich.
x 0 PI/2 PI 3 PI/2 2 PI
sin(x) 0 1 0 -1 0
  • Man teilt das Intervall zwischen 0 und 2 PI in so viele Teile, wie es Kreise gibt und multipliziert diesen Wert mit der Zählvariablen i. Damit startet jeder Kreis seine Schwingung etwas versetzt zum Nachbarn.

Beispiel

Verändere die frameRate() und beobachte, wie sich die Werte zwischen -1 und 1 verändern und dass benachbarte Werte nahe beieinander liegen, aber doch verschieden sind.

Mit der Sinusfunktion hast du ein mächtiges Werkzeug, mit dem sich wiederholende Vorgänge modelliert werden können.


Aufgabe

Baue eine Welle mit 25; 30; 40;... Kreisen.

Lösung


Aufgabe

Baue eine Welle mit vielen Hügeln und Tälern und vielen Kreisen.

Lösung

Funktionen sind Werkzeuge für die Programmierung. p5.js ist eine Funktionssammlung, also ein Werkzeugkasten mit vielen nützlichen Funktionen. Ein weiterer mächtiger Werkzeugkasten für Programmierer ist die Mathematik. Je besser du diesen Werkzeugkasten kennst, desto leichter kannst du viele Probleme lösen. Bei einem Informatik-Studium ist Mathematik deshalb ein wichtiger Schwerpunkt im Studium.