Rasterbasierte Formänderung in p5.js
Ein p5.js Tutorial für interaktive, rasterbasierte Formerstellung mit parametrischen Veränderungen.
Ziel der Übung
Durch dieses Tutorial lernst du mithilfe von p5.js wie du verschiedene Formen kreativ durch unterschiedliche Variablen und Interaktionen erstellen und verändern kannst.
Folgende Punkte beinhaltet das Tutorial:
- Rasterbasierte Formerstellung
- Bewegung durch Position
- Bewegung durch Animation
- Veränderungen durch Nutzereingaben
- Farbrandomisierung
p5.js
Wir verwenden für diese Übung die JavaScript Bibliothek p5.js. Du kannst den Online Editor verwenden, um damit Programme zu coden. Alternativ kannst du die Bibliothek auch für deine eigene Webseite verwenden und mit einem beliebigen Quellcode-Editor bearbeiten.
Öffne zum Starten den p5.js Editor. (Der Quellcode ist am Ende des Artikels verlinkt)
Dort wird dir folgender Code angezeigt:
function setup() {
createCanvas(400, 400);
}
function draw() {
}
Diese beiden Funktionen sind das Skelett deines p5.js-Programms:
Die setup()
-Funktion wird einmalig ausgeführt, wenn das Programm zum ersten Mal geladen wird. Hier kannst du die Zeichenfläche erstellen, die p5.js zum Anzeigen von Grafiken verwendet. Textformatierung und die Farben für das Zeichnen können hier ebenfalls festgelegt werden.
Die draw()
-Funktion wiederholt sich, solange das Programm läuft. Es steuert, wie sich das Programm im Laufe der Zeit entwickeln soll, einschließlich Animationen und anderer dynamischer Elemente.
Falls du das erste Mal mit p5.js arbeitest, wirf ebenfalls einen Blick auf die get started Anleitung von p5.js.
Deklaration unserer Variablen
Wir beginnen mit der Deklaration unserer Variablen, die wir in unserem Code verwenden werden. Wir schreiben dies vor die setup()
und draw()
Funktionen.
var moduleColor;
var moduleFillColor;
var moduleAlpha = 200;
var maxDistance = 500;
var variableSize = 30;
var variableDiameter = 60;
var countUp = true;
var moduleDiameterCount = 0;
var outline = false;
function setup() {
createCanvas(400, 400);
}
function draw() {
}
setup() function
function setup() {
createCanvas(600, 600); // erstellen der Zeichenfläche
noFill();
strokeWeight(3);
moduleColor = color(0, 0, 0, moduleAlpha); // Konturfarbe der Formen
moduleFillColor = color(255, 212, 128, moduleAlpha) // Füllfarbe der Formen
}
Zuerst schauen wir uns die setup()
functon an. Wir definieren unsere Zeichenfläche mit einer Größe von 600px und ohne Hintergrundfarbe.
Unsere Kontur soll global 3px dick sein.
Unseren Variablen moduleColor
und moduleFillColor
weisen wir Farben zu.
01 – Rasterobjekte erzeugen
function draw() {
clear(); // cleart Canvas bevor alles neu gemalt wird
stroke(moduleColor);
fill(moduleFillColor);
for (var gridY = 0; gridY < width; gridY += 25) { // erstellen der y-Achse des Rasters
for (var gridX = 0; gridX < height; gridX += 25) { // erstellen der x-Achse des Rasters
var distanceBetweenPoints = dist(mouseX, mouseY, gridX, gridY);
var diameter = distanceBetweenPoints / maxDistance * variableDiameter;
rect(gridX, gridY, diameter, diameter);
}
}
In der draw()
function werden wir Formen anhand eines Rasters erstellt. Wir definieren zuerst unsere Kontur- und Füllfarbe für die entstehenden Formen mit stroke()
und fill()
.
In einer verschachtelten for()
-Schleife erstellen wir spaltenweise unsere Rasterpunkte mit einem Abstand von 25px über die ganze Breite und Höhe der Zeichenfläche.
The size of a cell depends on this distance. If the mouse is close to a cell, the the distance is short and the size is small. If the mouse is far away from the cell, then the distance is large and the size of the cell, too.
Die Formveränderung basierend auf der Mausbewegung erreichen wir indem wir den Formdurchmesser diameter
abhängig von der Distanz des Mauszeigers zum Rasterpunkt machen. Die Variable variableDiameter
benötigen wir später für die Bewegung und Nutzereingaben.
Nun zeichnen wir unsere Form mit rect()
an den aktuellen Koordinaten gridX
und gridY
mit der Größe diameter
.
Wir haben jetzt ein Raster von Formen, die kleiner werden, je näher der Mauszeiger an ihnen ist und größer, je weiter weg er ist.
02 – Formveränderung durch Position
Im nächsten Schritt wollen wir anstatt nur eines Rechtecks verschiedene Formen abhängig von der Mausposition zeichen.
Dazu ersetzen wir unser rect()
durch einige if
Anweisungen:
// andere Form, je nachdem wo die Maus ist
if (mouseX < 200) {
// rect(x1, y1, width, height)
rect(gridX, gridY, diameter, diameter);
}
if (mouseX >= 200 && mouseX <= 400) {
// ellipse(x1, y1, width, height)
ellipse(gridX, gridY, diameter, variableSize);
}
if (mouseX > 400 && mouseY < 300) {
// triangle(x1, y1, x2, y2, x3, y3)
triangle(gridX, gridY, gridX, gridY + diameter, gridX + diameter, gridY + variableSize);
}
if (mouseX > 400 && mouseY > 300) {
// quad(x1, y1, x2, y2, x3, y3, x4, y4)
quad(gridX, gridY, gridX + (diameter / 2), gridY, gridX + variableSize, gridY + (variableSize * .8), gridX, gridY + diameter)
}
Wir unterteilen unsere Zeichenfläche horizontal in Drittel. Je nachdem in welchem Drittel sich der Mauszeiger mit seiner x-Koordinate befindet, wird die entsprechende Form gezeichnet. Im linken Drittel zeichnen wir Rechtecke, im mittleren Drittel Ellipsen und im rechten Drittel Polygone.
Dieses rechte Drittel haben wir nochmal vertikal halbiert: ist der Mauszeiger in der oberen Häfte, also seine y-Koordinate größer als 300px, zeichnen wir ein Dreieck, ist der Mauszeiger in der unteren Hälfte zeichnen wir ein Viereck.
Neben unserer diameter
Variable um die Breite und Größe der Form zu bestimmen, nutzen wir auch die variableSize
Variable, die durch Nutzereingabe später verändert werden kann.
03 – Animation der Formgröße
Bringen wir etwas Bewegung dazu! Wir möchten eine stetige Vergrößerung und Verkleinerung der Formgröße.
// für Animation: ändern des variableDiameter
// erreicht der counter 100, so wird die Richtung gewechselt > counter zählt runter; Farbe wird random gewechselt
if (moduleDiameterCount == 100) {
countUp = false;
moduleFillColor = color(random(255), random(255), random(255), moduleAlpha)
}
// erreicht counter -100 > Richtungswechsel > counter zählt hoch
if (moduleDiameterCount == -100) { countUp = true }
// zählt Counter hoch, so wird diameter (also die Formen) kleiner
if (countUp == true) {
variableDiameter = variableDiameter - 0.6;
moduleDiameterCount++
}
// zählt counter runter, wird diameter (also die Formen) größer
if (countUp == false) {
variableDiameter = variableDiameter + 0.6;
moduleDiameterCount--
}
Hierfür nutzen wir die Variable moduleDiameterCount
, die ständig zwischen -100 und 100 zählt. Den Zustand, ob wir aktuell in positive oder negative Richtung zählen, speichern wir als boolean Wert in countUp
.
Je nachdem ob der Counter positiv oder negativ ist, also ob countUp
true oder false ist, zählen wir den moduleDiameterCount
hoch oder runter und vergrößern oder verkleinern wir unseren variableDiameter
konsekutiv um 0.6
. Dieser beeinflusst direkt unseren diameter
und dementsprechend die Formgröße.
Als kleines Extra ändern wir beim Erreichen des Counters von 100 unsere Füllfarbe moduleFillColor
zufällig.
04 – Nutzereingaben (keyReleased())
Wir haben mit einigen Variablen gearbeitet mit dem Hintergedanken diese durch Nutzereingabe verändern zu können.
function keyReleased() {
switch (key) {
case '0':
variableDiameter = 60;
moduleDiameterCount = 0;
moduleColor = color(0, 0, 0, moduleAlpha);
moduleFillColor = color(255, 212, 128, moduleAlpha)
strokeWeight(3);
break;
case '1':
moduleColor = color(0, 0, 0, 200)
break;
case '2':
moduleColor = color(255, 255, 255, 200)
break;
case '3':
moduleColor = moduleFillColor
break;
case 'r':
moduleFillColor = color(random(255), random(255), random(255), moduleAlpha)
break;
case 'e':
variableSize = variableSize + 15
break;
case 'd':
variableSize = variableSize - 15
break;
case 's':
saveCanvas(gd.timestamp(), 'png')
break;
default:
break;
}
Die keyReleased()
function wird ausgeführt, wenn eine Taste losgelassen wird.
In die switch
Anweisung wird als Argument key
weitergegeben, also die gedrückte Taste. Je nachdem welche Taste gedrückt wurde, wird der entsprechende case
ausgeführt.
Im case '0'
setzen wir unsere Variablen auf ihre Anfangswerte zurück, die Taste »0« ist quasi ein Reset.
Mit den Tasten »1«, »2« und »3« ändert sich die Konturfarbe, »r« weist eine zufällige Füllfarbe zu.
Mit »e« und »d« lässt sich die variableSize
ändern, die die Größe der Formen bestimmt.
Mit »s« kann man die Zeichnefläche als Bild speichern.
if (key == 'o' && outline == false) {
strokeWeight(0);
outline = true;
}
else if (key == 'o' && outline == true) {
strokeWeight(3);
outline = false;
}
Um die Konturstärke zu ändern benötigen wir jedoch zwei zu erfüllende Bedingungen und nutzen dafür if
Anweisungen. Neben der gedrückten Taste müssen wir über den aktuellen Zustand der Kontur wissen. Diese Information speichern wir in der outline
Variable als boolean Wert.
Je nach Zustand von outline
wechseln wir zwischen einer Kontur oder keiner Kontur, indem wir die strokeWeight()
ändern.
if (keyCode == LEFT_ARROW) {
variableDiameter = variableDiameter + 10
}
if (keyCode == RIGHT_ARROW) {
variableDiameter = variableDiameter - 10
}
}
Zu guter Letzt möchten wir den variableDiameter
mit den Pfeiltasten zugänglich machen. Hierfür nutzen wir if
Anweisungen, denn für Pfeiltasten lesen wir den keyCode
aus. Und wenn gedrückt wurde, ändern wir unsere Variable um 10. Die variableDiameter
Variable beeinflusst unseren diameter
, also direkt die Formgröße.
Zusammenfassung
Wir haben ein Raster verschiedener Formen erstellt, das einerseits durch stetige Animation und andererseits durch dynamische Nutzereingaben verschiedener Art verändert werden kann.
Durch die Nutzung vieler variabler Werte ist es unkompliziert weitere Werte zu verändern und dem Nutzer zugänglich zu machen. Was könnte man noch eingeben? Was soll der Nutzer verändern können und wie?
Durch das Arbeiten mit dem Code lernt man am besten. Probiere es einfach selbst aus und werde kreativ!
Quellcode
Hier findest du den gesamten Quellcode im p5.js Editor und kannst dich austoben. Viel Spaß!