P5
in a Nutshell - Die wichtigsten Funktionen auf einen Blick
Das Canvas-Prinzip
Grundlegend
für die Arbeit mit P5 ist das mit HTML5 eingeführte "Canvas-Prinzip",
in dessen Rahmen ein Bereich auf der Webseite quasi als Leinwand gilt,
auf der beliebig programmierbare Aktionen möglich sind.
Der Canvas
wird in der setup()-Funktion
bestimmt. Im Grunde reichen die Zeilen
<script>
function setup(){
createCanvas(800,400); // Canvas mit
der Weite von 800 Pixeln
// und der Höhe von 400 Pixeln erstellen
}
</script>
Wenn nichts
weiter hinzukommt, wird der Canvas in der linken oberen Ecke des Browsers
platziert.
Um den Canvas
beliebig im Browser platzieren zu können, muss er an einen <DIV>-Container
angehängt werden, dessen Position dann frei bestimmt werden kann,
also:
<script>
function setup(){
var container = createCanvas(800,400); //
Canvas erstellen
container.parent('p5canvas'); // Canvas
an Container auf der Seite anhängen
}
</script>
und im Body
der Seite wird an der gewünschten Stelle ein <DIV>-Container
eingerichtet, der beliebig gestaltet werden kann (hier mit dem Namen "p5canvas"):
<DIV id="p5canvas"
style="width:800;border: 1px solid #333;box-shadow: 8px 8px 5px
#444;padding: 8px 12px;background-color:ffffff"></DIV>
Innerhalb
des Canvas entspricht das Koordinatensystem dem des Browsers (links oben
ist 0,0).
Wie in Javascript
werden auch in P5 die Scripte Zeile für Zeile nacheinander ausgeführt.
Jeder Befehl wird hierbei mit einem Semikolon abgeschlossen.
Man kann
die Scripte normal in einem html-Editor erstellen und dann im Rahmen einer
Webseite laufen lassen (z.B. mit dem Editor Brackets unter https://brackets.io/
). Zum schnellen Ausprobieren reicht in den meisten Fällen aber auch
schon der Online-P5-Editor unter https://editor.p5js.org/
aus (hier braucht man auch keine <script>...</script>-Tags).
Während
in
function setup(){...}
Das Script
nur einmal am Anfang ausgeführt wird, wird alles in
function draw(){...}
in einer
Schleife ausgeführt, deren Framerate (Durchläufe pro Sekunde)
sich via frameRate() ausgeben
bzw. verändern lässt (wodurch sich z.B. die Geschwindigkeit
von Anwendungen anpassen lässt), z.B. (kopieren und im https://editor.p5js.org/
ausführen):
function draw(){
background(255,255,255); // weißer
Hintergrund (r,g,b)
text(frameRate(), 10, 10); // Textausgabe
mit Framerate auf dem Punkt (x,y) 10,10
}
Die Konsole
In Browsern
gibt es eine Konsole, die praktisch ist, um sich zwischendurch via print()
Variablen ausgeben zu lassen oder die Stelle zu finden, an der
ein Fehler auftritt. Die Konsole erreicht man in den verschiedenen Browsern
folgendermaßen:
Chrome und
Firefox:
F12 drücken (bzw. am Mac: [⌘]+[Optionstaste]+[J]).
Safari (Mac):
1. Rechte Maustaste klicken und im dortigen Menü auf "Element
Information" klicken
Internet
Explorer:
F12 drücken, im rechten Reiter auf "Command"-Symbol
klicken
Hier kann
man sich die Framerate z.B. nun mit print() über die Konsole ausgeben
lassen:
function draw(){
print (frameRate()); // Textausgabe in
der Konsole
}
Formen
und Farben
Mit P5 lassen
sich schnell Linien, Kreise, Qudrate und andere geometrische Formen zeichnen.
Das ist besonders für die Darstellung von interaktiven Graphen spannend,
aber auch für viele andere Visualisierungen.
Die hierfür
zuständigen Formen sind sehr einfach aufgebaut: Es wird immer zunächst
die Form beschrieben, die man zeichnen möchte, und dann die Positionen
der Grenzpunkte (x,y).
Bei Rechtecken und Ellipsen wird die linke obere Ecke mit einem Punkt
beschrieben (x,y) und dann
die Weite und Höhe angegeben (width,
height).
Beim Kreisbogen (arc) wird
ebenfalls die linke obere Ecke mit einem Punkt (x,y)
und die Weite und Höhe mit width
und height beschrieben.
Hinzu kommt noch der Start- und Endwinkel (start,
stop). Will man diesen in Grad angeben, dann sollte man in der
setup()-Funktion die Zeile
hinzufügen: angleMode(DEGREES);
Verschiedene Grundformen (McCarthy, Reas, Fry 2015, S. 20)
Man könnte
hier z.B im https://editor.p5js.org/
mit verschiedenen Formen experimentieren:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
}
function draw(){
background(200,200,200); //grauen Hintergrund
erzeugen
line (0,0, 400,400); // Linie erzeugen
triangle(50,50, 250,250, 400,50); //
Dreieck erzeugen
quad(400,50, 260,260, 60,220, 310,60); //
Viereck erzeugen
rect(250,250, 100,100); // Rechteck erzeugen
ellipse(250,250, 100,100); // Ellipse/Kreis
erzeugen
arc(150,350, 100,100, 45,315); // Kreisbogen/Pacman
erzeugen
}
Um Vielecke oder z.B. auch komplexe (Audio-)Kurven oder Spektren zu visualisieren
bietet sich die Kombination aus beginShape()
- vertex(x, y) - endShape()
an (bzw. endShape(CLOSE),
wenn die Form wieder geschlossen werden soll). Hier werden nach beginShape()
mit Hilfe von vertex(x, y)
eine ganze Reihe von Punkten gesetzt und mit endShape()
die Reihe abgeschlossen, z.B.:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
}
function draw(){
background(200,200,200); //grauen Hintergrund
erzeugen
beginShape();
// komplexe Form
beginnen;
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
endShape(CLOSE); //
komplexe Form beenden und abschließen;
}
Mit fill(r,g,b,a) als Füllfarbe
(für Flächen) und stroke(r,g,b,a)
als Strichfarbe (für Linien und Buchstaben) lassen sich diese Formen
farblich verändern. Es können hierfür Zahlenwerte von 0-255
für die r-, g- und b-Werte eingegeben werden sowie Zahlenwerte zwischen
0 und 100 für die Transparenz (a). Mit strokeWeight()
lässt sich die Dicke von Begrenzungslinien bestimmen.
Möchte man keine Strich- oder Füllfarbe verwenden, kann man
sie mit noStroke() und
noFill() abschalten.
So lassen
sich die zufälligen Formen (s.o.) mit zufälligen Farben und
zufälliger Transparenz darstellen, z.B.:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
}
function draw(){
background(200,200,200); //grauen Hintergrund
erzeugen
r = random(255);
// zufällige Zahl zwischen 0 und 255 für die Variable r erzeugen
g = random(255);
// zufällige Zahl zwischen 0 und 255 für die Variable g erzeugen
b = random(255); // zufällige
Zahl zwischen 0 und 255 für die Variable b erzeugen
a = random(100); // zufällige
Zahl zwischen 0 und 100 für die Variable a erzeugen
fill(r,g,b,a); //
Füllfarbe aus den Zufallsvariablen zusammensetzen;
r = random(255);
// zufällige Zahl zwischen 0 und 255 für die Variable r erzeugen
g = random(255);
// zufällige Zahl zwischen 0 und 255 für die Variable g erzeugen
b = random(255); // zufällige
Zahl zwischen 0 und 255 für die Variable b erzeugen
a = random(100); // zufällige
Zahl zwischen 0 und 100 für die Variable a erzeugen
stroke(r,g,b,a); //
Strichfarbe aus den Zufallsvariablen zusammensetzen
s = random(10);
// zufällige Zahl zwischen 0 und 10 für die Variable a erzeugen
strokeWeight(s);
// Strichdicke bestimmen
beginShape(); //
komplexe Form beginnen
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
x = random(400);
// zufällige Zahl zwischen 0 und 400 für die Variable x erzeugen
y = random(400); // zufällige Zahl
zwischen 0 und 400 für die Variable y erzeugen
vertex(x, y); // einen Punkt der Form
auf den Koordinaten x,y bilden
endShape(CLOSE); //
komplexe Form beenden und abschließen;
}
Um schnell
die richtigen Zahlenwerte für die gewünschte Farbe zu finden,
eignen sich Color-Picker wie z.B. unter
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Colors/Color_picker_tool
,
https://htmlcolorcodes.com/color-picker/
oder https://fffuel.co/cccolor/
.
Will man verschiedene Formen (oder auch Bilder etc.) über den Bildschirm
bewegen, so gibt es hier die Möglichkeit, einfach über die x-
und y-Koordinaten eine Bewegung herzustellen, wie z.B. einen Pacman mit
jedem Frame um 1 Pixel weiter nach links zu verschieben.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
x=0; // Variable x für den Start auf
0 setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
x=x+1; // x bei jedem Frame um 1 erhöhen
arc(x,200, 100,100, 45,315); // Pacman
auf der jeweiligen Position von x anzeigen
}
Texte, Variablen und Operatoren
Neben Formen
und Farben können natürlich auch Texte und Zahlen ausgegeben
werden. Dies geschieht mit Hilfe von
text('Beispieltext', x, y,width,height) an der Position x,y
und optional auch in einer bestimmten Weite (width)
und Höhe (height).
Die Textgröße kann dabei über
textSize() bestimmt werden, der Textstil über textStyle()
(mit den Einstellungen 'NORMAL',
'ITALIC', 'BOLD' und 'BOLDITALIC'), und die Textfarbe über
stroke() (die Buchstabenumrisse)
und fill() (die Füllfarbe,
s.o.). So könnte man z.B. die x-Koordinaten von Pacman am oberen
Bildrand in roter Farbe ausgeben:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
x=0; // Variable x für den Start
auf 0 setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(200,50,50); // rote Füllfarbe
für den Text erzeugen
textSize(20); // Textgröße
einstellen (optional)
textStyle('BOLD'); // Textstil einstellen
(optional)
text('X-Koordinate von Pacman: ' + x, 10,20); //
Text ausgeben
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
x=x+1; // x bei jedem Frame um 1 erhöhen
arc(x,200, 100,100, 45,315); // Pacman
auf der jeweiligen Position von x anzeigen
}
Variablen können Texte, ganze Zahlen (int),
Dezimalzahlen (float),
Listen (array) oder auch
boolsche Variblen sein (true/false).
Sie werden mit var deklariert.
Werden Sie innerhalb von Funktionen mit var
deklariert (z.B. setup(){...}
oder draw(){...}), dann
gelten sie nur innerhalb der jeweiligen Funktion.
Werden sie außerhalb von Funktionen mit var
deklariert, dann gelten sie für alle Bereiche.
Man kann Variablen aber auch einfach ohne Deklaration mit einem Gleicheitszeichen
erstellen, dann gelten sie auch über die Funktionen hinweg.
Variablen
werden via Gleichheitszeichen zugewiesen, d.h. =
bedeutet nicht "ist gleich", sondern, dass das, was rechts vom
Gleichheitszeichen steht, der linken Seite zugewiesen wird.
Natürlich gelten die mathematischen Operatoren (wie +,
-, *, /, pow(x,y) (x
hoch y), sqrt(x,y) (xte
Wurzel aus y) und %
(Modulo) etc.) sowie Regeln (wie z.B. Punktrechnung geht vor Strichrechnung).
Arrays
sind Listen von Zahlen (getrennt mit Beistrichen, z.B. 1, 2, 3, 4, 5 ...)
oder Wörtern/Texten/Buchstaben (in Apostrophen und getrennt mit Beistrichen,
z.B. 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#',...) und sie werden via var
in eckigen Klammern deklariert, z.B.
var oktave_array = [1, 2, 3, 4,
5, 6, 7, 8]; // Array für Oktavlage
anlegen
var tonhoehe_array = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
'A', 'A#', 'H']; //
Array für Tonhöhen anlegen
var frequenz_array = [32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535,
46.2493, 48.9994, 51.9131, 55.0000, 58.2705, 61,7354];
//
Array für Frequenzen anlegen
Die Reihenfolge in Arrays wird über den Index bestimmt (gezählt
ab 0), so dass man hierüber auf einzelne Elemente des Arrays zugreifen
kann, wie z.B. über die Mauspositon (erhältlich durch mouseX
und mouseY):
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
}
function draw(){
background(200,200,200);
var
oktave_array = [1, 2, 3, 4, 5, 6, 7, 8]; //
Array für Oktavlage anlegen
var tonhoehe_array = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
'A', 'A#', 'H']; //
Array für Tonhöhen anlegen
var frequenz_array = [32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535,
46.2493, 48.9994, 51.9131, 55.0000, 58.2705, 61,7354];
//
Array für Frequenzen anlegen
maus_x = round(map(mouseX,
0,400, 0,11)); // x-Mausposition (mouseX)
von der X-Skala des Canvas (0-400) auf die Anzahl der Elemente im tonhoehe_array
(0-11) mappen, den Wert zu einer ganzen Zahl runden und der Variablen
maus_X zuweisen.
maus_y = round(map(mouseY, 0,400, 7,0)); //
y-Mausposition (mouseY) von der Y-Skala des Canvas (0-400) auf die Anzahl
der Elemente im oktave_array
(0-7) mappen, den Wert zu einer ganzen Zahl runden und der Variablen
maus_Y zuweisen.
oktavlage = oktave_array[maus_y]; //
über die gemappte y-Mausposition die Position der Oktavlage im
oktave_array ermitteln und an die Variable oktavlage übergeben.
oktavierung = oktavlage-1; // aus der
Oktavlage den Faktor für die Oktavierung bilden und an die Variable
oktavierung übergeben
tonhoehe = tonhoehe_array[maus_x]; //
über die gemappte x-Mausposition die Position der Tonhöhe
im tonhoehe_array ermitteln und an die Variable tonhoehe übergeben.
frequenz = round(pow(2,oktavierung) * frequenz_array[maus_x]); //
über die gemappte x-Mausposition die Position der Frequenz im frequenz_array
ermitteln und mit dem Quadrat des Werts in der Variable oktavierung
multiplizieren und das Ergebnis an die Variable frequenz übergeben.
text('aktuelle Tonhöhe: ' + tonhoehe + oktavlage + ' (' + frequenz
+ ' Hz)', 10, 10); //Ausgabe von Tonhöhe
und Frequenz
}
Mit Hilfe
der Funktion map(Wert, start1,
stop1, start2, stop2) lassen sich Wertebereiche aneinander angleichen.
Das ist hilfreich, wenn z.B. 12 Tonhöhen über eine Weite von
400 Pixeln verteilt werden sollen (s.o.).
Wie in anderen
Sprachen auch lassen sich über
.unshift() Elemente an den Anfang eines Array hinzufügen bzw.
über .pop() am Ende
aus dem Array entfernen. So ließe sich z.B. eine fortlaufende Welle
erzeugen, indem man zu einem Array ständig neue Zahlen hinzufügt
und die gleiche Anzahl von Zahlen wieder entfernt, z.B.:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
noise_array=[]; // Array deklarieren
for (i = 0; i < 400; i++) { // for-Schleife
starten: zähle i von 0 hoch, solange es kleiner als 400 ist.
noise_array.push(random(100,200)); //
Füge eine zufällige Zahl zwischen 100 und 200 am Ende des
Arrays hinzu
}
}
function draw(){
background(200,200,200); // grauen Hintergrund anzeigen
noFill(); // keine Füllfarbe
noise_array.pop(); // entferne das letzte
Element aus dem Array
noise_array.unshift(random(100,200)); //
füge eine zufällige Zahl zwischen 100 und 200 zum Beginn des
Arrays hinzu
beginShape(); // komplexe Form beginnen
for (i = 0; i < 400; i++) { // for-Schleife
starten: zähle i von 0 hoch, solange es kleiner als 400 ist.
vertex(i, noise_array[i]); // einen Punkt
der Form auf den Koordinaten i und i-tes Element des Arrays bilden
}
endShape(); // komplexe Form beenden
}
Weitere Befehle zum Anhängen/Entfernen von Elementen in einem Array
sind:
.pop() : entfernt das letzte
Element aus einem Array
.push() : fügt ein oder
mehrere Elemente ans Ende eines Arrays hinzu
.shift() : entfernt das erste
Element aus einem Array
.unshift() : fügt ein
oder mehrere Elemente an den Anfang eines Arrays hinzu
Schleifen
und Entscheidungen
Besonders
bei der Arbeit mit Arrays oder größeren Datenmengen benötigt
man Schleifen, also Vorgänge, die so lange wiederholt werden, bis
alle Variablen entsprechend gesetzt/verändert/bearbeitet worden sind.
Am prominentesten ist die for(Anfangsbedingung,
Endbedingung, Zähler){...}- Schleife mit folgender Struktur
for (i = 0; i <
400; i++) { // starte bei i = 0 und solange
i kleiner als 400 ist, erhöhe i um 1
// .. mache irgendwas
}
Man kann z.B. die Schleife dazu verwenden, um Elemente eines Arrays nacheinander
abzuarbeiten (s.o.).
Weniger prominent
und im Einsatz etwas gefährlicher ist die while(Bedingung){...}-Schleife,
die so lange ausgeführt wird, so lange eine bestimmte Bedingung erfüllt
ist. Das Gefährliche bei der while()-Schleife
ist, dass sie keine Abbruchbedingung voraussetzt, so dass man schnell
Gefahr läuft eine unendliche Schleife zu erschaffen, während
bei der for()-Schleife
die Abbruch- oder Endbedingung immer schon ein Teil der Ausgangsdefinition
ist.
while()-Schleifen kann
man als idle-Funktionen verwenden, die z.B. solange ablaufen, bis eine
Maus- oder Tastatureingabe erfolgt, z.B.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
}
function draw(){
while (mouseX>100 && mouseY>100 && mouseX<300
&& mouseY<300) { // solange
die Maus sich innerhalb eines Quadrats im Canvas befindet ...
background(random(255),random(255),random(255)); //
... färbe den Hintergrund zufällig ein
}
}
Für Entscheidungen werden if(Bedingung){...}else{...}-Strukturen
verwendet.
if (i == 0) { //
wenn die Variable i = 0 ist, dann
// .. mache irgendwas
} else { // sonst
// .. mache etwas anderes
}
Zum Testen der Bedingung in den runden Klammern stehen verschiedene Operatoren
zur Verfügung:
x == y
: x ist gleich y (bei if-Bedingungen werden immer doppelte Gleichheitszeichen
verwendet)
x != y : x ist ungleich
y
x > y : x ist größer
als y
x < y : x ist kleiner
als y
x >= y : x ist größer/gleich
y
x <= y : x ist kleiner/gleich
y
Man kann
auch mehrerere Bedingungen mit den logischen Operatoren &&
(und) oder || (oder) miteinander
verknüpfen (dies gilt auch für while()-Schleifen).
So könnte man z.B. über eine if()-else-Struktur den Mund des
Pacmans sich öffnen und schließen lassen
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
mund="auf"; // Variable mund
für den Pacman auf "auf" setzen
oberkiefer=315; // Winkel für den
Oberkiefer auf 315° setzen
unterkiefer=45; // Winkel für den
Unterkiefer auf 45° setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
if (mund=="auf") { // wenn
der Mund geöffnet ist ...
oberkiefer=oberkiefer+1; // addiere zum
Oberkieferwinkel 1°
unterkiefer=unterkiefer-1; // subtrahiere
vom Unterkieferwinkel 1°
}
if (mund=="zu") { // wenn der
Mund geöffnet ist ...
oberkiefer=oberkiefer-1; // subtrahiere
vom Oberkieferwinkel 1°
unterkiefer=unterkiefer+1; // addiere
zum Unterkieferwinkel 1°
}
if (unterkiefer==0){mund="zu"} //
wenn der Unterkiefer auf 0 ist, setze die Variable mund auf "zu"
if (unterkiefer==45){mund="auf"} //
wenn der Unterkiefer auf 45 ist, setze die Variable mund auf "auf"
arc(200,200, 50,50, unterkiefer,oberkiefer); //
zeige Pacman mit seiner jeweiligen Mundöffnung
}
Rotieren, Skalieren, Transponieren
Um eine Figur
um ihre eigene Achse drehen zu lassen, eignet sich die rotate()-Funktion
sehr gut. Der Winkel sollte hierbei via angleMode(DEGREES)
in Grad eingestellt werde (da er sonst in radians berechnet wird).
Da sich bei der Rotation immer an den Koordinaten 0,0 orientiert wird
(= linke obere Ecke des Canvas), sollte man diese via translate(x,
y) entsprechend verschieben.
Man könnte hierüber z.B. den Pacman an die Maus anhängen
und ihn je nach Position um seine eigene Achse drehen lassen, z.B.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
mund="auf"; // Variable mund
für den Pacman auf "auf" setzen
oberkiefer=315; // Winkel für den
Oberkiefer auf 315° setzen
unterkiefer=45; // Winkel für den
Unterkiefer auf 45° setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
if (mund=="auf") { // wenn
der Mund geöffnet ist ...
oberkiefer=oberkiefer+1; // addiere zum
Oberkieferwinkel 1°
unterkiefer=unterkiefer-1; // subtrahiere
vom Unterkieferwinkel 1°
}
if (mund=="zu") { // wenn der
Mund geöffnet ist ...
oberkiefer=oberkiefer-1; // subtrahiere
vom Oberkieferwinkel 1°
unterkiefer=unterkiefer+1; // addiere
zum Unterkieferwinkel 1°
}
if (unterkiefer==0){mund="zu"} //
wenn der Unterkiefer auf 0 ist, setze die Variable mund auf "zu"
if (unterkiefer==45){mund="auf"} //
wenn der Unterkiefer auf 45 ist, setze die Variable mund auf "auf"
translate(mouseX, mouseY); //
verlagere die Koordinaten 0,0 auf die jeweiligen Mauskoordinaten
rotate(mouseY); //
verwende die Y-Koordinate der Maus in Grad, um alles weitere zu drehen
arc(0,0, 50,50, unterkiefer,oberkiefer); //
zeige Pacman mit seiner jeweiligen Mundöffnung
}
Man könnte mit der Maus-X-Koordinate gleichzeitig via scale()
die Skalierung des Canvas verändern und damit je nach Mausposition
den Pacman größer und kleiner werden lassen. Wenn man möchte,
dass sich das Rotieren, Transponieren und Skalieren nur auf den Pacman
auswirkt und nicht auf z.B. ein zusätzliches rotes Quadrat im Bild,
dann kann man diese Funktionen via push()
und pop() auf den
Pacman beschränken, z.B.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
mund="auf"; // Variable mund
für den Pacman auf "auf" setzen
oberkiefer=315; // Winkel für den
Oberkiefer auf 315° setzen
unterkiefer=45; // Winkel für den
Unterkiefer auf 45° setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
if (mund=="auf") { // wenn
der Mund geöffnet ist ...
oberkiefer=oberkiefer+1; // addiere zum
Oberkieferwinkel 1°
unterkiefer=unterkiefer-1; // subtrahiere
vom Unterkieferwinkel 1°
}
if (mund=="zu") { // wenn der
Mund geöffnet ist ...
oberkiefer=oberkiefer-1; // subtrahiere
vom Oberkieferwinkel 1°
unterkiefer=unterkiefer+1; // addiere
zum Unterkieferwinkel 1°
}
if (unterkiefer==0){mund="zu"} //
wenn der Unterkiefer auf 0 ist, setze die Variable mund auf "zu"
if (unterkiefer==45){mund="auf"} //
wenn der Unterkiefer auf 45 ist, setze die Variable mund auf "auf"
push(); //
Geltungsbereich für das verschobene Koordinatensystems beginnen
translate(mouseX, mouseY); // verlagere
die Koordinaten 0,0 auf die jeweiligen Mauskoordinaten
rotate(mouseY); //
verwende die Y-Koordinate der Maus in Grad, um alles weitere zu drehen
scale(mouseX/100); // Koordinatensystem
um ein Hundertstel der jeweiligen X-Maus-Koordinate vergrößern/verkleinern
arc(0,0, 50,50, unterkiefer,oberkiefer); //
zeige Pacman mit seiner jeweiligen Mundöffnung
pop(); //
Geltungsbereich für das verschobene Koordinatensystems beenden
fill(150,50,50); // Füllfarbe auf
dunkelrot setzen
rect(50,50,50,50);
//
Rechteck zeichnen
}
Maus-
und Tastatureingaben
Über
mouseX und mouseY
lassen sich unkompliziert die Maus-Koordinaten im aktuellen Frame abfragen,
so dass man hierüber die Maus tracken kann, z.B.:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
fill(200,200,200); // graue Füllfarbe
einstellen
noStroke(); // keine Strichfarbe
}
function draw(){
ellipse(mouseX, mouseY, 8,8); // Punkt
an die Maus anhängen und mit jedem Frame einen Punkt malen
}
Über pmouseX und pmouseY
lassen sich die Mauskoordinaten des jeweils vorangegangenen Frames abrufen,
so dass man diese mit den aktuellen Koordinaten zu einer Linie verbinden
kann. Wenn man diese Funktion davon abhängig macht, ob eine Maustaste
geklickt ist oder nicht (via mouseIsPressed),
kann man hierüber gezielt Linien zeichnen, z.B.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
stroke(200,200,200); // graue Füllfarbe
einstellen
}
function draw(){
if (mouseIsPressed == true) { // bei
einem Mausklick:
line (mouseX, mouseY, pmouseX, pmouseY); //
Linie zwischen aktueller und letzter Mausposition zeichnen
}
}
Bei der Abfrage
von mouseIsPressed lässt
sich mit Hilfe von mouseButton
weiter abfragen, ob die linke oder rechte Maustaste gedrückt wurde.
So kann z.B. über die Maustaste zwischn den Farben gewechselt werden:
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
stroke(200,200,200); // graue Füllfarbe
einstellen
}
function draw(){
if (mouseIsPressed == true) { // bei
einem Mausklick:
if (mouseButton == LEFT) { stroke(200,200,200); } //
bei linker Maustaste: Strichfarbe wird grau
if (mouseButton == RIGHT) { stroke(150,50,50); } //
bei rechter Maustaste: Strichfarbe wird rot
line (mouseX, mouseY, pmouseX, pmouseY); //
Linie zwischen aktueller und letzter Mausposition zeichnen
}
}
Schieberegler (slider) sind für Mauseingaben eingaben sehr hilfreich.
So lassen sich Schieberegler via createSlider(Minimum,
Maximum, Defaultwert, Schrittgröße) erstellen und
über .position(x,y)
und .style() in ihrer
Position und Größe verändern. Z.B. könnte man die
Farbwerte, Transparenz und Strichdicke bei den Mauslinien via Slider
einstellen
function setup(){
createCanvas(500,400); // Canvas-Größe
bestimmen
rslider = createSlider(0, 255, 100, 1); //slider
für rot von 0-255 erstellen
rslider.position(0, 20); // rot-slider
bei 0,20 positionieren
rslider.style('width', '80px'); // Weite
des Sliders bestimmen
gslider = createSlider(0, 255, 100, 1); //slider
für grün von 0-255 erstellen
gslider.position(100, 20); // grün-slider
bei 100,20 positionieren
gslider.style('width', '80px'); // Weite
des Sliders bestimmen
bslider = createSlider(0, 255, 100, 1); //slider
für blau von 0-255 erstellen
bslider.position(200, 20); // blau-slider
bei 200,20 positionieren
bslider.style('width', '80px'); // Weite
des Sliders bestimmen
aslider = createSlider(0, 100, 100, 1); //slider
für Transparenz von 0-255 erstellen
aslider.position(300, 20); // Transparenz(alpha)-slider
bei 300,20 positionieren
aslider.style('width', '80px'); // Weite
des Sliders bestimmen
swslider = createSlider(0, 10, 1, 0.1); //slider
für Strichdicke von 0-255 erstellen
swslider.position(400, 20); // Strichdicke-slider
bei 400,20 positionieren
swslider.style('width', '80px'); // Weite
des Sliders bestimmen
}
function draw(){
stroke(rslider.value(), gslider.value(), bslider.value(), aslider.value());
// Strichfarbe nach den Slidereinstellungen
richten
fill(rslider.value(), gslider.value(), bslider.value(), aslider.value());
// Füllfarbe nach den Slidereinstellungen
richten
strokeWeight(swslider.value()); // Strichdicke
nach den Slidereinstellungen richten
if (mouseIsPressed == true) { // bei
einem Mausklick:
line (mouseX, mouseY, pmouseX, pmouseY); //
Linie zwischen aktueller und letzter Mausposition zeichnen
}
rect(0,0,500,20); // Rechteck als Vorschau
mit der ausgewählten Farbe zeichnen
}
Es gibt über
createInput() und createButton()
auch die Möglichkeit zur Texteingabe, so dass man z.B. in dem Farbscript
auch beliebige Texte beliebig einfärben kann:
function setup(){
createCanvas(500,400); // Canvas-Größe
bestimmen
rslider = createSlider(0, 255, 100, 1); //slider
für rot von 0-255 erstellen
rslider.position(0, 20); // rot-slider
bei 0,20 positionieren
rslider.style('width', '80px'); // Weite
des Sliders bestimmen
gslider = createSlider(0, 255, 100, 1); //slider
für grün von 0-255 erstellen
gslider.position(100, 20); // grün-slider
bei 100,20 positionieren
gslider.style('width', '80px'); // Weite
des Sliders bestimmen
bslider = createSlider(0, 255, 100, 1); //slider
für blau von 0-255 erstellen
bslider.position(200, 20); // blau-slider
bei 200,20 positionieren
bslider.style('width', '80px'); // Weite
des Sliders bestimmen
aslider = createSlider(0, 100, 100, 1); //slider
für Transparenz von 0-255 erstellen
aslider.position(300, 20); // Transparenz(alpha)-slider
bei 300,20 positionieren
aslider.style('width', '80px'); // Weite
des Sliders bestimmen
swslider = createSlider(0, 10, 1, 0.1); //slider
für Strichdicke von 0-255 erstellen
swslider.position(400, 20); // Strichdicke-slider
bei 400,20 positionieren
swslider.style('width', '80px'); // Weite
des Sliders bestimmen
textfenster = createInput(); //
Texteingabe erstellen
textfenster.position(0,50); // Texteingabe
positionieren
textfenster.style('width', '400px'); //
Weite der Texteingabe bestimmen
tbutton = createButton("texteingabe"); //
Texteingabebutton erstellen
tbutton.position(400, 50); // Texteingabebutton
positionieren
tbutton.style('width', '100px'); // Weite
des Texteingabebuttons
bestimmen
tbutton.mousePressed(textausgabe); //
Funktion ausführen, wenn der Texteingabebutton geklickt wird
}
function draw(){
stroke(rslider.value(), gslider.value(), bslider.value(), aslider.value());
// Strichfarbe nach den Slidereinstellungen
richten
fill(rslider.value(), gslider.value(), bslider.value(), aslider.value());
// Füllfarbe nach den Slidereinstellungen
richten
strokeWeight(swslider.value()); // Strichdicke
nach den Slidereinstellungen richten
if (mouseIsPressed == true) { // bei
einem Mausklick:
line (mouseX, mouseY, pmouseX, pmouseY); //
Linie zwischen aktueller und letzter Mausposition zeichnen
}
rect(0,0,500,20); // Rechteck als Vorschau
mit der ausgewählten Farbe zeichnen
}
function textausgabe(){
// Funktion erstellen, die nach einer
Texteingabe ausgeführt wird
textSize(swslider.value()*10); // Textgröße
über den strokeWeight-Slider bestimmen lassen
text(textfenster.value(), random(0,400), random(50,400)); //
Textausgabe an einer zufälligen Position
}
Es zeigt sich hier, dass neben
setup(){...} und draw(){...}
auch via
function beliebigerName(){...} beliebige eigene Funktionen möglich
sind, die die Vorgänge innerhalb und außerhalb des Canvas beeinflussen
können.
Diese Funktionen werden immer mit function
und dem Namen der Funktion eingeleitet, in den runden Klammern ()
können Variablen übergeben werden und in den geschweiften
Klammen {} findet dann
die weitere Verarbeitung statt.
Mit Hilfe
der Library p5.touchgui (https://github.com/L05/p5.touchgui)
lassen sich alle möglichen Eingabefelder, Slider, Buttons etc. beliebig
gestalten
Neben
Mauseingaben sind natürlich über die Abfrage keyIsPressed
und key (bei einfachem
Tastendruck) oder keyIsDown(keycode)
(bei kombiniertem Tastendruck) auch Tastatureingaben möglich (die
entsprechende Nummer für den keycode lässt sich schnell über
z.B. https://www.toptal.com/developers/
keycode/for/alt ermitteln). So ließe sich z.B. die Bewegung
des Pacmans über die Pfeiltasten steuern und die Bewegungen des Ghosts
(z.B. ein rotes Rechteck) über die Tasten A,S,D,W, während man
via dist() die Distanz
zwischen beiden ausrechnen kann, z.B.
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
angleMode(DEGREES); // Winkelmaße
in Grad einstellen
mund="auf"; // Variable mund
für den Pacman auf "auf" setzen
oberkiefer=315; // Winkel für den
Oberkiefer auf 315° setzen
unterkiefer=45; // Winkel für den
Unterkiefer auf 45° setzen
richtung="rechts"; // Ausgangs-Richtung
festlegen
x_pac=200; // Pacman X-Koordinate in
die Mitte setzen
y_pac=200; // Pacman Y-Koordinate in
die Mitte setzen
x_ghost=50 // Ghost X-Koordinate in die
Mitte setzen
y_ghost=50 // Ghost Y-Koordinate in die
Mitte setzen
}
function draw(){
background(0,0,0); // schwarzen Hintergrund
erzeugen
fill(255,240,25); // gelbe Füllfarbe
für Pacman erzeugen
if (mund=="auf") { // wenn
der Mund geöffnet ist ...
oberkiefer=oberkiefer+1; // addiere zum
Oberkieferwinkel 1°
unterkiefer=unterkiefer-1; // subtrahiere
vom Unterkieferwinkel 1°
}
if (mund=="zu") { // wenn der
Mund geschlossen ist ...
oberkiefer=oberkiefer-1; // subtrahiere
vom Oberkieferwinkel 1°
unterkiefer=unterkiefer+1; // addiere
zum Unterkieferwinkel 1°
}
if (unterkiefer==0){mund="zu"} //
wenn der Unterkiefer auf 0 ist, setze die Variable mund auf "zu"
if (unterkiefer==45){mund="auf"} //
wenn der Unterkiefer auf 45 ist, setze die Variable mund auf "auf"
if (keyIsDown(RIGHT_ARROW))
{ //wenn Pfeil nach rechts gedrückt
ist
if(x_pac>450){x_pac=-50;} // Zurücksetzen
des Pacmans, falls am Rand
x_pac=x_pac+1; // zur x-Koordinate 1
dazu addieren
}
if (keyIsDown(LEFT_ARROW)) { //wenn Pfeil
nach links gedrückt ist
if(x_pac<-50){x_pac=450;} // Zurücksetzen
des Pacmans, falls am Rand
x_pac=x_pac-1; // von x-Koordinate 1
abziehen
}
if (keyIsDown(DOWN_ARROW)) { //wenn Pfeil
nach unten gedrückt ist
if(y_pac>450){y_pac=-50;} // Zurücksetzen
des Pacmans, falls am Rand
y_pac=y_pac+1; // zu
y-Koordinate 1 daz addieren
}
if (keyIsDown(UP_ARROW)) { //wenn Pfeil
nach oben gedrückt ist
if(y_pac<-50){y_pac=450;} // Zurücksetzen
des Pacmans, falls am Rand
y_pac=y_pac-1; // von y-Koordinate 1
abziehen
}
if (keyIsDown(87)) { //wenn w gedrückt
ist
if(y_ghost<-50){y_ghost=450;} // Zurücksetzen
des Ghosts, falls am Rand
y_ghost=y_ghost-1; // von y-Koordinate
1 abziehen
}
if (keyIsDown(83)) { //wenn s gedrückt
ist
if(y_ghost>450){y_ghost=-50;} // Zurücksetzen
des Ghosts, falls am Rand
y_ghost=y_ghost+1; // zur y-Koordinate
1 dazu addieren
}
if (keyIsDown(65)) { //wenn a gedrückt
ist
if(x_ghost<-50){x_ghost=450;} // Zurücksetzen
des Ghosts, falls am Rand
x_ghost=x_ghost-1; // von x-Koordinate
1 abziehen
}
if (keyIsDown(68)) { //wenn d gedrückt
ist
if(x_ghost>450){x_ghost=-50;} // Zurücksetzen
des Ghosts, falls am Rand
x_ghost=x_ghost+1; // zu x-Koordinate
1 daz addieren
}
arc(x_pac,y_pac, 50,50,
unterkiefer,oberkiefer); // zeige Pacman
mit seiner jeweiligen Mundöffnung an der Position x_pac,y_pac
fill(255,0,0); // rote Füllfarbe
für Ghost erzeugen
ellipse(x_ghost, y_ghost, 50,50) // Kreis
mit den x- und y-Koordinaten für den Ghost mit einer Höhe
und Weite von 50 Pixeln erzeugen
abstand = dist(x_pac,y_pac,x_ghost, y_ghost); //
Abstand via dist(); zwischen den x-/y-Mittelpunkten von Pacman und Ghost
errechnen
if(abstand<50){ // Wenn Abstand kleiner
als die Hälfte der Summe von Radius des Pacmans und des Ghosts
ist
fill(255,0,0); // Füllfarbe für
den Text = rot
} else {
fill(255,255,255); // Füllfarbe
für den Text = weiß
}
text(round(abstand), 190,20); // Abstand
(gerundet) als Text ausgeben
}
Bilder,
Audio und Video
Neben
Formen, Farben und Texten kann man in P5 natürlich auch mit Bildern,
Klängen und Videos arbeiten. Diese Mediendateien sind manchmal etwas
größer, weswegen es sich immer anbietet, diese in einer preload()-Funktion
vorauszuladen.
Bilder werden über loadImage('Bilderpfad')
in der preload()-Funktion
einer Variablen zugeordnet, die dann im Script beliebig weiter verarbeitet
werden kann. Gleiches gilt für Klänge
Man könnte z.B. anstelle eines Pacmans mit diesen zwei Autos fahren,
die möglichst nicht zusammenstoßen sollen. Über die Funktion
dist() kann der Abstand
zwischen zwei Punkten ermittelt werden, so dass bei einem zu geringen
Abstand zwischen den beiden Autos ein Unfall angezeigt wird. Dies lässt
sich auch mit den entsprechenden Klängen untermalen: über
loadSound()
können
Klänge (Fahr- und Crashgeräusche) über die preload()-Funktion
entsprechenden Variablen zugeordnet werden, die via .play();
und .stop() gestartet und
gestoppt werden können. Mit Hilfe von .isPlaying()
kann dabei abgefragt werden, ob ein Klang gerade spielt oder nicht.
auto1.png
(122 * 271 Pixel) auto2.png
(125*248)
auto1.mp3, auto2.mp3
und crash.mp3
(Die Autobilder- und Klänge können über die rechte Maustaste
heruntergeladen werden)
Da Bilder von einer externen Quelle geladen werden, benötigt dieses
Script eine eigene Server-Umgebung, um lauffähig zu sein, d.h. das
Ergebnis kann man erst sehen, wenn man alles auf einen Server geladen
hat. Für die Wiener Musikwissenschaft wurde deswegen unter https://muwiserver.synology.me:444
eine Testumgebung eingerichtet, in der Studierende jeweils einen Ordner
mit ihrem Namen anlegen können und eigene Scripte ausprobieren können.
Über das ftp-Programm FileZilla
können die Daten hochgeladen werden, der Zugang ist:
Server: muwiserver.synology.me
Benutzername: Student
Passwort: [wird im Unterricht verraten]
Port: 22
<script>
var auto1; //
Variable für das Autobild1 deklarieren
var auto2; // Variable für das Autobild2
deklarieren
var autoklang1; // Variable für
das Auto 1 deklarieren
var autoklang2; // Variable für
das Auto 1 deklarieren
var crash;
// Variable für den Zusammenstoß-Klang
deklarieren
function preload(){
// Bilder von ihren Pfaden vorausladen
auto1 = loadImage("auto1.png"); //
Auto1-Bild einladen
auto2 = loadImage("auto2.png"); //
Auto2-Bild einladen
autoklang1 = loadSound("klang/auto1.mp3"); //
Auto1-Klang einladen
autoklang2 = loadSound("klang/auto2.mp3"); //
Auto1-Klang einladen
crash = loadSound("klang/crash.mp3");
// Auto1-Zusammenstoß-Klang einladen
}
function setup(){
var container = createCanvas(800,800); //
Canvas erstellen
container.parent('p5canvas'); // Canvas
an Container auf der Seite anhängen
angleMode(DEGREES); // Winkel in °
berechnen
auto1_x=0; // Ausgangsposition X des
Autos 1 festlegen
auto1_y=0; // Ausgangsposition Y des
Autos 1 festlegen
auto2_x=200; // Ausgangsposition X des
Autos 2 festlegen
auto2_y=0; // Ausgangsposition Y des
Autos 2 festlegen
auto1_dreh=0; // Rotation des Autos 1
festlegen
auto2_dreh=0; // Rotation des Autos 2
festlegen
auto1_breite=61; // Breite des Autos
1 festlegen
auto1_laenge=136; // Länge des Autos
1 festlegen
auto2_breite=63; // Breite des Autos
2 festlegen
auto2_laenge=124; // Länge des Autos
2 festlegen
}
function draw(){
background(255,255,255); // weißen
Hintergrund erzeugen
text("a = <-", 70,20); //
Erklärender Text für a-Taste (links)
text("w = ^", 70,40); // Erklärender
Text für w-Taste (auf)
text("s = v", 70,60); // Erklärender
Text für s-Taste (ab)
text("d = ->", 70,80); //
Erklärender Text für d-Taste (rechts)
text("<- =
<-", 270,20); // Erklärender
Text für Pfeil-links-Taste (links)
text("^ = ^", 270,40); // Erklärender
Text für Pfeil-oben-Taste
(auf)
text("v = v", 270,60); // Erklärender
Text für Pfeil-unten-Taste
(ab)
text("-> = ->", 270,80); //
Erklärender Text für Pfeil-rechts-Taste
(rechts)
if (keyIsPressed)
{ // bei Tastendruck:
if (key=='d'){ // wenn d gedrückt
wurde:
if (auto1_x<850){auto1_x = auto1_x+2; //
lasse Auto1 nach rechts fahren
auto1_dreh=270; // drehe es um 270°
}
}
if (key=='a'){ // wenn a gedrückt
wurde:
if (auto1_x>-50){auto1_x = auto1_x-2; //
lasse Auto1 nach links fahren
auto1_dreh=90; // drehe es um 90°
if (!autoklang1.isPlaying()){autoklang1.play();} //
wenn Auto1-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='w'){ // wenn w gedrückt
wurde:
if (auto1_y>-50){auto1_y = auto1_y-2; //
lasse Auto1 nach oben fahren
auto1_dreh=180; // drehe es um 180°
if (!autoklang1.isPlaying()){autoklang1.play();} //
wenn Auto1-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='s'){ // wenn s gedrückt
wurde:
if (auto1_y<850){auto1_y = auto1_y+2; //
lasse Auto1 nach unten fahren
auto1_dreh=0; // drehe es um 0°
if (!autoklang1.isPlaying()){autoklang1.play();} //
wenn Auto1-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='ArrowRight'){
// wenn Pfeil-rechts gedrückt wurde:
if (auto2_x<850){auto2_x = auto2_x+2; //
lasse Auto2 nach rechts fahren
auto2_dreh=270; // drehe es um 270°
if (!autoklang2.isPlaying()){autoklang2.play();} //
wenn Auto2-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='ArrowLeft'){ // wenn Pfeil-links
gedrückt wurde:
if (auto2_x>-50){auto2_x = auto2_x-2; //
lasse Auto2 nach links fahren
auto2_dreh=90; // drehe es um 90°
if (!autoklang2.isPlaying()){autoklang2.play();} //
wenn Auto2-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='ArrowUp'){ // wenn Pfeil-oben
gedrückt wurde:
if (auto2_y>-50){auto2_y = auto2_y-2; //
lasse Auto2 nach oben fahren
auto2_dreh=180; // drehe es um 180°
if (!autoklang2.isPlaying()){autoklang2.play();} //
wenn Auto2-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
if (key=='ArrowDown'){ // wenn Pfeil-unten
gedrückt wurde:
if (auto2_y<850){auto2_y = auto2_y+2; //
lasse Auto2 nach unten fahren
auto2_dreh=0; // drehe es um 0°
if (!autoklang2.isPlaying()){autoklang2.play();} //
wenn Auto2-Klang gerade nicht spielt, dann spiele ihn ab.
}
}
}
if (!keyIsPressed)
{ // wenn keine Taste gedrückt ist
if (autoklang1.isPlaying()){autoklang1.stop();} //
stoppe Auto1-Klang, falls er spielt
if (autoklang2.isPlaying()){autoklang2.stop();} //
stoppe Auto2-Klang, falls er spielt
}
push(); //
Änderung des Koordinatensystems für Auto1 ab hier
translate(auto1_x, auto1_y); // setze
x,y=0,0 auf die Position des Autos1
rotate(auto1_dreh); // drehe Auto1 um
den entsprechenden Winkel
image(auto1, -1*auto1_breite/2, -1*auto1_laenge/2, auto1_breite, auto1_laenge);
//zeige das Bild Auto1 an der entsprechenden
Position
pop(); // Ende der Änderung des
Koordinatensystems für Auto1
push(); // Änderung des Koordinatensystems
für Auto2 ab hier
translate(auto2_x, auto2_y); // setze
x,y=0,0 auf die Position des Autos2
rotate(auto2_dreh); // drehe Auto2 um
den entsprechenden Winkel
image(auto2, -1*auto2_breite/2, -1*auto2_laenge/2, auto2_breite, auto2_laenge);
//zeige das Bild Auto2 an der entsprechenden
Position
pop(); // Ende der Änderung des
Koordinatensystems für Auto2
//Collision Detection mit Hilfe von dist();
distanz = round(dist(auto1_x,
auto1_y, auto2_x, auto2_y)); // ermittle
die Distanz über die Mittelpunkte von Auto1 (auto1_x, auto1_y)
und Auto2 (auto2_x, auto2_y) und runde sie auf eine ganze Zahl.
text("Abstand: "+distanz, 70,100);
// Gebe den Abstand der Mittelpunkte als Text aus
noStroke(); // keine Strichfarbe
if (auto1_dreh==0 ||auto1_dreh==180){
// wenn das Auto1 senkrecht steht
a1k_breite=auto1_breite;
// weise der Variablen a1k_breite die auto1_breite zu
a1k_laenge=auto1_laenge; //
weise der Variablen a1k_laenge die auto1_laenge zu
} else {
// sonst:
a1k_breite=auto1_laenge; //
weise der Variablen a1k_breite die auto1_laenge zu
a1k_laenge=auto1_breite; //
weise der Variablen a1k_laenge die auto1_breite zu
}
if (auto2_dreh==0 ||auto2_dreh==180){ //
wenn das Auto2 senkrecht steht
a2k_breite=auto2_breite;
// weise der Variablen a2k_breite die auto2_breite zu
a2k_laenge=auto2_laenge;
//
weise der Variablen a2k_laenge die auto2_laenge zu
} else { //
sonst:
a2k_breite=auto2_laenge; //
weise der Variablen a2k_breite die auto2_laenge zu
a2k_laenge=auto2_breite; //
weise der Variablen a2k_laenge
die auto2_breite z
}
if (distanz < (a1k_laenge+a2k_laenge)/2){
// wenn die Distanz kleiner ist als der Mittelwert zwischen den beiden
Längenmaßen der Autos, dann:
tint(150,0,0); //
färbe die Autos rot ein
if (!crash.isPlaying()){crash.play();}
// wenn das Zusammenstoßgeräusch nicht spielt, spiele es
ab
} else { //
sonst:
tint(255,255,255); //
keine Färbung
if (crash.isPlaying()){crash.stop();}
// wenn das Zusammenstoßgeräusch spielt, stoppe es.
}
}
</script>
Mit der
P5-Library P5.play
lassen sich Spiele dieser Art sehr viel schneller und robuster entwickeln.
Hier werden besonders Collision Detection, Animation sowie Maus- und
Tastatureingaben unterstützt.
Via p5.AudioIn() und
p5.Amplitude() und .getLevel()
lässt sich auch das Mikrofon einbinden, um Formen und Farben etc.
über den Schallpegel zu verändern, z.B.:
var mikrofon;
// Variable fürs den Audioeingang deklarieren
var amplitude; // Variable fürs
die Amplitude deklarieren
var skalierung = 1.0; // Variable fürs
die Skalierung deklarieren
function setup() {
createCanvas(400, 400); // Canvas-Größe
bestimmen
background(255,255,255); // weißen
Hintergrund erzeugen
mikrofon = new p5.AudioIn(); // Audio-In
der Variablen mikrofon zuweisen
mikrofon.start(); // den Audio-Input
starten
amplitude = new p5.Amplitude(); // den
Amplituden-Detektor der Variablen amplitude zuweisen
amplitude.setInput(mikrofon); // den
Audio-Input (in Form der Variablen mikrofon) dem Amplituden-Detektor
zuweisen.
}
function draw() {
noStroke(); // keine Strichfarbe
fill(255, 255, 255); // weiße Füllfarbe
rect(0, 0, width, height); // Rechteck
in Höhe und Breite des Canvas zeichnen
skalierung = map(amplitude.getLevel(), 0, 1.0, 10, width); //
den jeweiligen Amplitudenwert (amplitude.getLevel()
zwischen 0 und 1.0) auf die Größe
des Canvas skalieren (zwischen 10 und width).
fill(255,0,0,10*skalierung); // rote
Füllfarbe für den Kreis, Transparenz via skalierung durch
die Amplitude bestimmen lassen
ellipse(width/2, height/2, skalierung, skalierung); //
Kreis zeichnen, dessen Mittelpunkt in der Mitte des Canvas ist (width/2,
height/2) und dessen Größe bzw. Radius von der Amplitude
abhängt.
}
Über
den Sinus-Oszllator p5.SinOsc()
und der Frequenzeinstellung .freq()
lassen sich beliebige Zahlen als Frequenzen hörbar machen.
So wird es z.B. einfach, das Script mit den verschiedenen Tonhöhen
in den verschiedenen Oktavlagen (s.o.) mit den dazugehörenden Klängen
zu versehen:
var sinuston; //
Variable für den Sinus-Oszillator erstellen
function setup(){
createCanvas(400,400); // Canvas-Größe
bestimmen
sinuston
= new p5.SinOsc(); // Sinus-Oszillator
einbinden und der Variablen sinuston
// zuweisen
sinuston.start(); // Sinus-Oszillator
über die Variable sinuston starten.
}
function draw(){
background(200,200,200);
var
oktave_array = [1, 2, 3, 4, 5, 6, 7, 8]; //
Array für Oktavlage anlegen
var tonhoehe_array = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
'A', 'A#', 'H']; //
Array für Tonhöhen anlegen
var frequenz_array = [32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535,
46.2493, 48.9994, 51.9131, 55.0000, 58.2705, 61,7354];
//
Array für Frequenzen anlegen
maus_x = round(map(mouseX,
0,400, 0,11)); // x-Mausposition (mouseX)
von der X-Skala des Canvas (0-400) auf die Anzahl der Elemente im tonhoehe_array
(0-11) mappen, den Wert zu einer ganzen Zahl runden und der Variablen
maus_X zuweisen.
maus_y = round(map(mouseY, 0,400, 7,0)); //
y-Mausposition (mouseY) von der Y-Skala des Canvas (0-400) auf die Anzahl
der Elemente im oktave_array
(0-7) mappen, den Wert zu einer ganzen Zahl runden und der Variablen
maus_Y zuweisen.
oktavlage = oktave_array[maus_y]; //
über die gemappte y-Mausposition die Position der Oktavlage im
oktave_array ermitteln und an die Variable oktavlage übergeben.
oktavierung = oktavlage-1; // aus der
Oktavlage den Faktor für die Oktavierung bilden und an die Variable
oktavierung übergeben
tonhoehe = tonhoehe_array[maus_x]; //
über die gemappte x-Mausposition die Position der Tonhöhe
im tonhoehe_array ermitteln und an die Variable tonhoehe übergeben.
frequenz = round(pow(2,oktavierung) * frequenz_array[maus_x]); //
über die gemappte x-Mausposition die Position der Frequenz im frequenz_array
ermitteln und mit dem Quadrat des Werts in der Variable oktavierung
multiplizieren und das Ergebnis an die Variable frequenz übergeben.
sinuston.freq(frequenz);
text('aktuelle
Tonhöhe: ' + tonhoehe + oktavlage + ' (' + frequenz + ' Hz)', 10,
10); // Ausgabe von Tonhöhe und
Frequenz
}
Mit der P5.sound-Library
(https://p5js.org/reference/#/libraries/p5.sound)
erhält man enorme zusätzliche Möglichkeiten für den
Einsatz von Klängen, die im weiteren Verlauf der Übung behandelt
werden.
Über createCapture(VIDEO)
lässt sich auch der Eingang der Videokamera einbinden, und
die damit eingefangenen Bilder lassen sich mit verschiedenen Filtern weiter
verarbeiten, z.B.
var videokamera; //
Variable für den Video-Input definieren
function setup() {
createCanvas(800, 600); // Canvas-Größe
bestimmen
videokamera = createCapture(VIDEO); //
Video-Capture erstellen und der Variablen
// videokamera zuweisen
videokamera.hide(); // das Originalbild
des Video-Captures verstecken, um darauf Filter
// anwenden zu können (s.u.)
}
function draw() {
background(255,255,255); // weißer
Hintergrund
var seitenverhaeltnis = videokamera.height/videokamera.width;
// Seitenverhältnis des Kamerabilds ermitteln ...
var hoehe = width* seitenverhaeltnis;
// ... und darüber die passende Höhe für das
// Videobild errechnen
image(videokamera, 0, 0, width, hoehe);
// Video als Bild auf der Position 0,0
// ausgeben und mit passender Weite und Höhe ausgeben
if (keyIsPressed) { // bei Tastendruck:
if (key=='1'){filter(THRESHOLD);} //
filter das Bild schwarz/weiß
if (key=='2'){filter(GRAY);} // filter
das Bild grau
if (key=='3'){filter(INVERT);} // invertiere
das Bild
if (key=='4'){filter(POSTERIZE, 5);} //
reduziere die Farben und mache ein Poster aus
// dem Bild (Werte ab 2 aufwärts)
if (key=='5'){filter(DILATE);} // erweitere
die hellen Pixel im Bild
if (key=='6'){filter(BLUR, 10);} // füge
Unschärfe hinzu (Werte ab 2 aufwärts)
if (key=='7'){filter(ERODE);} // erweitere
die dunklen Pixel im Bild
}
if (mouseIsPressed) { // bei Mausklick:
tint(mouseX, 255-mouseX, mouseY); //
färbe das Bild entsprechend der Mausposition ein
} else { // oder ...
tint(255, 255, 255); // ... hebe die
Färbung auf.
}
}
Mit
einer Kombination von Mikrofon und Webcam ist es z.B. auch möglich das
Bild der Webcam pegelabhängig einzufärben:
var videokamera; //
Variable für den Video-Input definieren
function setup() {
createCanvas(800, 600); // Canvas-Größe
bestimmen
mikrofon = new p5.AudioIn(); // Audio-In
der Variablen mikrofon zuweisen
mikrofon.start(); // den Audio-Input
starten
amplitude = new p5.Amplitude(); // den
Amplituden-Detektor der Variablen amplitude
// zuweisen
amplitude.setInput(mikrofon);
videokamera
= createCapture(VIDEO); // Video-Capture
erstellen und der Variablen
// videokamera zuweisen
videokamera.hide(); // das Originalbild
des Video-Captures verstecken, um darauf Filter
// anwenden zu können (s.u.)
}
function draw() {
background(255,255,255); // weißer
Hintergrund
pegel=amplitude.getLevel()*5000; // Die
Amplitude des Mikrofonsignals mit 5000
// multiplizieren, um in einen Bereich zwischen 0 und 255 zu kommen.
var seitenverhaeltnis = videokamera.height/videokamera.width;
// Seitenverhältnis des Kamerabilds
ermitteln ...
var hoehe = width* seitenverhaeltnis; //
... und darüber die passende Höhe für das
// Videobild errechnen
image(videokamera, 0, 0, width, hoehe); //
Video als Bild auf der Position 0,0
// ausgeben und mit passender Weite und Höhe ausgeben
tint(pegel+mouseX/4, pegel+mouseY/3, pegel); //
färbe das Bild entsprechend der
// Mausposition und dem Mikrofonpegel ein.
}
Durch die Möglichkeiten der p5-Machine-Learning-Library (ML5 und
https://ml5js.org/) lassen
sich Videocapture unter P5 auch zum Motion- und Face-Tracking sowie zur
Objekterkennung einsetzen.
|