Arrays (Datenfelder)


In einem Array (Datenfeld) können viele Variablen oder Objekte gleichzeitig gespeichert werden. Gerade wenn du ein Programm mit einer grafischen Oberfläche programmieren möchtest, ist das wichtig. Jedes Element auf der Oberfläche ist ein Objekt, das bei einer Veränderung des Bildschirminhalts neu gezeichnet werden muss.

Wenn alle zu zeichnenden Bildschirmelemente als Objekte in einem Array gespeichert werden, kann man diese mit Hilfe einer for-Schleife neu zeichnen lassen.

Beispiel

Wir erzeugen drei Kreise und zeichnen diese. Wie du siehst, muss man in der Anweisung zum Zeichnen der Kreise den Namen der drei Kreise extra angeben. Stell dir vor, du möchtest 100 Kreise zeichnen, dann bräuchtest du 100 Kreisnamen. Das scheint unpraktisch zu sein. ! Die Erklärung für die Erzeugung der Kreise findest du im Kapitel Objekte.


Ein Array anlegen

Verwendet man ein Array, so bekommt nur das Array einen Variablennamen und die einzelnen Kreise können mit Hilfe eines Index (einer Nummer) gespeichert werden.

Ein Array legt man mit der Anweisung var arrayname = new Array(); fest. Hier nennen wir das Array der Kreise kreise.

Ein Kreis bekommt den Namen arrayname[index], hier wäre das kreise[0], kreise[1],...

Beachte, dass die Array-Nummerierung bei der Zahl 0 beginnt.

Beispiel

Erzeuge noch einen vierten Kreis.


Ein Array mit Daten füllen

Jetzt soll noch das Zeichnen der Kreise kürzer programmiert werden. Wie du siehst, hat nicht mehr jeder Kreis einen eigenen Namen, sondern eine Nummer (einen Array-Index). Mit Hilfe dieses Index kann man eine for-Schleife nutzen um die Kreise zu zeichnen.

Falls du dich nicht mehr erinnerst, eine for-Schleife legt man wie folgt fest:

for (var i = 0; i < 10; i++) { anweisungen }.

Hier muss man aufpassen, dass die for-Schleife nur versucht so viele Kreise zu zeichnen, wie im Array gespeichert sind. Ist die Zahl bei der Abbruchbedingung i < 10; zu groß, versucht das Programm einen Kreis zu zeichnen, den es nicht gibt und es gibt einen Skript-Fehler.

Es wäre sehr geschickt, wenn JavaScript selbst herausfinden könnte, wie viele Kreise im Array gespeichert sind. Das geht! In arrayname.length ist die Anzahl der Einträge in einem Array gespeichert. Also sieht die neue for-Schleife wie folgt aus:

for (var i = 0; i < arrayname.length; i++) { anweisungen }

Damit ist sichergestellt, dass das Programm nur so viele for-Schleifen durchläuft, wie Kreise im Array gespeichert sind. Wie dir vielleicht schon aufgefallen ist, beginnt ein Array in JavaScript mit dem Index 0.

Beispiel

Versuche noch einen vierten Kreis anzulegen.

In der for-Schleife wird für den Kreisnamen die Zählvariable i eingesetzt. Bei jedem Schleifendurchlauf wird die Zählvariable eins vergrößert und es ist sichergestellt, dass alle Kreise gezeichnet werden. Es spielt jetzt keine Rolle, ob du 3 oder 300 Kreise zeichnen möchtest, die Anweisung zum Zeichnen aller Kreise ist jetzt identisch. Das erspart viel Tipparbeit und die Programme lassen sich leichter verändern. Allerdings sieht der Programmiercode komplizierter aus. Aber du wirst dich daran gewöhnen.


Richtig viele Kreise

Jetzt wollen wir mal richtig viele Kreise malen. Dazu tippen wir nicht alle Eigenschaften selbst ein, sondern der Computer erzeugt diese zufällig selbst. Bislang wurden die Farben der Kreise als Namen eingegeben. Das wäre hier unpraktisch. Also werden auch die Farben mit Hilfe von Zahlen eingegeben. Einen Farbcode-Generator findest du z.B. hier: RGB Rechner (denke daran den Link so zu öffnen: rechte Maustaste -> in neuem Tab öffnen, sonst verlässt du diese Seite).

Neue Befehle:

  • var fw = color(240, 10, 90); (einen Farbwert in einer Variablen speichern)
  • var fw = color(random(255), random(255), random(255)); (zufällige Farbwerte erzeugen)
  • var zr = random(10, 100); (eine Zahl zwischen 10 und 100 erzeugen)
  • kreise[i].xkoord = kreise[i].xkoord + deltaX; (vom Kreis mit der Nummer i wird der Wert der x-Koordinate um deltaX verändert)

Schritt 1: Ein Zufallskreis

Die Eigenschaften des Kreises werden zufällig erzeugt und die Kreise werden in dem Array kreise[i] gespeichert. Da nur ein Kreis erzeugt wird, ist das schnell erledigt. Klicke mehrmals auf Play, um den Kreis zufällig neu zeichnen zu lassen.


Schritt 2: 10 Zufallskreise

Jetzt werden zufällig 10 Kreise erzeugt. Die Zufallsfunktionen sind jetzt kompakt dargestellt, sind aber die gleichen wie in Schritt 1. Klicke mehrmals auf Play, um die Kreise zufällig neu zeichnen zu lassen.


Schritt 3: 100 Zufallskreise

Was mit 10 Kreisen funktioniert geht auch mit 100. Ändere die Zahl 100 in der for-Schleife, welche die Kreise erzeugt in ein größere Zahl (aber lieber nicht zu groß, sonst musst du warten...). Klicke mehrmals auf Play, um die Kreise zufällig neu zeichnen zu lassen.


Schritt 4: 100 Zufallskreise, die sich bewegen

Statische Kreise sehen so undynamisch aus. Deswegen werden wir diese jetzt animieren:

for (var i = 0; i < kreise.length; i++) {
  kreise[i].xkoord = kreise[i].xkoord + random(-2,2);
  kreise[i].ykoord = kreise[i].ykoord + random(-2,2); 
} 

Mit dieser for-Schleife wird die x- und y-Koordinate eines jeden Kreises bei jedem Frame um einen zufälligen Wert zwischen -2 und 2 geändert. p5.js berechnet viele Male pro Sekunde die Zeichenfläche neu, indem die Funktion draw()immer wieder aufgerufen wird. Daher werden die for-Schleifen in der draw()-Funktion immer wieder ausgeführt. Darum musst du dich selbst nicht um die Animation der Keise kümmern, das übernimmt alles p5.js.

Klicke mehrmals auf Play, um die Kreise zufällig neu zeichnen zu lassen.

Anmerkung

Beim letzten Schritt siehst Du, warum die Speicherung der Kreise in einem Array sehr sinnvoll sein kann. Da alle Daten eines Kreises gespeichert sind, kann man einzelne während des Programmablaufs verändern und den Kreis mit den neuen Eigenschaften jederzeit neu zeichnen.


Schritt 4: 100 Zufallskreise, die sich sanft bewegen

p5.js malt jede Sekunde 60 mal die Zeichenfläche neu (es sei denn man setzt diesen Wert mit der Anweisung frameRate(zahl); auf einen anderen Wert). In Schritt 3 wurde die Koordinate in jeder Sekunde zufällig um +2/-2 Pixel verändert. Dadurch hüpfen die Kreise. Schön wäre es, wenn die Änderung der Koordinate nur ganz allmählich geschehen würde (in der Mathematik würden wir sagen, die Werte sollen sich stetig ändern).

Dafür gibt es in p5.js den Zufallsgenerator noise();. Details dazu findest du in der p5.js-Referenz. Dieser besondere Zufallsgenerator wurde von Ken Perlin entwickelt, der dafür 1997 einen technischen Oskar gewonnen hat, da dieser Algorithmus die digitale Filmproduktion revolutioniert hatte. Die Erklärung für die noise-Funktion ist etwas mathematisch. In der Anmerkung unter dem folgenden Beispiel kannst du dir diese durchlesen.

Klicke mehrmals auf Play, um die Kreise zufällig neu zeichnen zu lassen. Sieht schön aus, oder?

Anmerkung

Wie versprochen gibt es hier eine Erklärung zum noise-Zufallsgenerator.

Beim Programmstart erzeugt p5.js eine zufällige Wertemenge mit Hilfe der noise()-Funktion. 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 100 Kreise bewegen möchten, muss für jeden Kreis eine andere zufallsstelle der noise-Funktion herausgesucht werden, sonst würden sich alle Kreise synchron bewegen. Die noise-Funktion wurde am Anfang des Programms generiert und die Werte sind während des Programmverlaufs unveränderlich. Erst wenn das Programm neu gestartet wird, wird eine andere noise-Funktion mit neuen Werten generiert.

Für die x- und y-Wertänderungen wird jeweils ein Array angelegt:

var xZufallsstelle = new Array();
var yZufallsstelle = new Array();

In der for-Schleife, in der die Kreise generiert werden, wird für jeden Kreis eine xZufallsstelle und eine yZufallsstelle mit Hilfe der random-Funktion zufällig ausgewählt, von der aus die noise-Zufallswerte abgelesen werden.

xZufallsstelle[i] = random(0,500);
yZufallsstelle[i] = random(501,1000);

Damit die x- und y-Werte auch wirklich anders geändert werden, nimmt man diese noise-Zufallsstellen sogar aus einem völlig anderen Intervall.

Um die Kreise zu bewegen benutzt man folgende for-Schleife:

  for (var i = 0; i < kreise.length; i++) {
    kreise[i].xkoord = kreise[i].xkoord + map(noise(xZufallsstelle[i]), 0, 1, -1, 1);
    kreise[i].ykoord = kreise[i].ykoord + map(noise(yZufallsstelle[i]), 0, 1, -1, 1); 
    xZufallsstelle[i] = xZufallsstelle[i] + 0.01;
    yZufallsstelle[i] = yZufallsstelle[i] + 0.01;
  }  

Mit map(noise(xZufallsstelle[i]), 0, 1, -1, 1); erzeugt man die zufällige nahezu stetige Änderung:

  • noise(xZufallsstelle[i]) holt den noise-Zufallswert an der noise-Zufallsstelle, die beim Programmanfang zufällig mit xZufallsstelle[i] = random(0,500); herausgesucht wurde.
  • map(zahl, 0, 1, -1, 1) 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 xZufallsstelle[i] = xZufallsstelle[i] + 0.01; wird die noise-Zufallsstelle für diesen Kreis um 0.01 verschoben, so dass beim nächsten Frame ein anderer, aber in der Nähe liegender noise-Zufallswert ausgegeben wird. Bei der y-Koordinate geht man genauso vor. Und damit entsteht der Eindruck, dass sich die Kreise kontinuierlich bewegen und nicht auf der Zeichenfläche herumhüpfen.


Keine Angst!

Wenn du das letzte Programm nicht verstanden hast, erinnere dich bitte an die Ankündigung auf der ersten Seite des JavaScript-Kurses: In diesem Kapitel hast du gelernt, wie man mit JavaScript ein Programm steuern könnte. Arbeite jetzt bitte die nächsten Kapitel durch und dann wirst du Schritt für Schritt lernen, wie du ein Programm steuern kannst.