0t1 steckt noch in den Kinderschuhen.

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ß!


© 0t1

Cookies

0t1 mag keine Kekse (und kein Tracking). Wir verwenden lediglich notwendige Cookies für essentielle Funktionen.

Wir verwenden Schriftarten von Adobe Fonts. Dafür stellt dein Browser eine Verbindung zu den Servern von Adobe in den USA her. Wenn du unsere Seite nutzen möchtest, musst du dich damit einverstanden erklären.

Weitere Informationen in unserer Datenschutzerklärung.