Hallo!
Matthias Edler-Golla
matthias.edler-golla@hm.edu
http://matthias-edler-golla.de
Matthias Edler-Golla
matthias.edler-golla@hm.edu
http://matthias-edler-golla.de
Externe Funktionen helfen Euch, Euren Code übersichtlicher und einfacher lesbar zu machen:
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// …
// ================================
// einfaches Auslagern von Aufgaben
// gut für die Lesbarkeit!
// ================================
weisserKreis();
rotesQuadrat();
willkommen();
}
// ============= externe Funktionen =============
function weisserKreis() {
strokeWeight(5);
stroke("blue");
fill("white");
ellipse(50, 60, 80);
}
function rotesQuadrat() {
noStroke();
fill("red");
rect(120, 20, 120);
}
function willkommen() {
textFont("Roboto Slab");
textSize(24);
noStroke();
fill("black");
text("Willkommen!", 280, 70);
}
DRY (Don’t repeat yourself): Redundant vorhandene Informationen (z. B. Code-Duplikate im Quelltext) sind aufwändig zu pflegen. Bei Systemen, die dem DRY-Prinzip treu bleiben, brauchen Änderungen nur an einer Stelle vorgenommen zu werden
Externe Funktionen haben auch die tolle Eigenschaft, immer wieder verwendbar zu sein, wenn man ihnen Werte übergibt. Damit muss man deutlich weniger Code schreiben und wiederholt sich nicht!
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// roter Kreis
kreisZeichnen("red", 50);
// grüner kreis
kreisZeichnen("rgb(0,185,100)", 150);
}
// externe Funktion mit 2 übergebenen Werten (fuellFarbe, xPos)
function kreisZeichnen(fuellFarbe, xPos) {
strokeWeight(5);
noStroke();
fill(fuellFarbe);
ellipse(xPos, 60, 80);
}
function setup() {
// ACHTUNG: Die Reihenfolge muss EXAKT eingehalten werden!
// Angaben: strichStaerke, strichFarbe, fuellFarbe, xPos, yPos, durchMesser
kreisZeichnenKomplex(3, "blue", "orange", 340, 60, 60);
kreisZeichnenKomplex(8, "hsl(200,50%,50%)", "#000", 430, 60, 90);
// eine Loop-Funktion zeichnet so viele Kreise wie hier angegeben
vieleKreiseZeichnen(18);
}
function kreisZeichnenKomplex(strichStaerke, strichFarbe, fuellFarbe, xPos, yPos, durchMesser){
strokeWeight(strichStaerke);
stroke(strichFarbe);
fill(fuellFarbe);
ellipse(xPos, yPos, durchMesser);
}
function vieleKreiseZeichnen(anzahl){
// anzahl Kreise zeichnen
// "20 + 30 * i" sorgt dafür, dass die Kreise waagrecht nebeneinander stehen
for (var i = 0; i <= anzahl; i++) {
kreisZeichnenKomplex(6, 120, "rgb(0,255,255)", 20 + 30 * i, 170, 20);
}
}
Mit return könnt Ihr eine externe Funktion „arbeiten lassen“ –
und sie schickt Euch das Resultat ihrer Arbeit zurück („returniert diese“)…
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// …
}
function draw() {
// …
// Ausgabe der Flächengröße oberhalb des Rechtecks
groessenAngabe();
}
function groessenAngabe() {
// …
// "flaechenBerechnung()" ist eine externe Funktion, die die Fläche ausrechnet
// und den Wert zurückgibt
text("Fläche des Rechtecks in Quadrat-px: " + flaechenBerechnung(), 10, 20);
}
function flaechenBerechnung() {
let breite = mouseX - x;
let hoehe = mouseY - y;
let flaeche = Math.round(breite * hoehe);
// nächste Zeile "schickt" den Wert zurück zur Ausgangsfunktion
return flaeche;
}
Baut den oben gezeigten Sketch nach und verwendet dazu eine externe Furnktion, die alle 3 Kreise zeichnet!
Ladet Euch dazu das Übungspaket runter – dort befinden sich schon die Anfänge des erforderlichen Codes:
function setup() {
const meinCanvas = createCanvas(600, 200);
meinCanvas.parent("canvasContainer");
background("#ddd");
// Füllfarbe, X-Position, Y-Position, Durchmesser übergeben!
kreisZeichnen();
kreisZeichnen();
kreisZeichnen();
}
// externe Funktion mit übergebenen Werten
function kreisZeichnen() {
noStroke();
// was muss hier rein?
}
Was müsst Ihr einfügen, damit die externe Function "kreisZeichnen()" die 3 Kreise zeichnet?
Code zwischen push() und pop() muss man sich wie eine eigene Photoshop-Ebene vorstellen, die mit dem Code außenrum nichts zu tun hat…
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// …
const start = 100;
const d = 80;
// Ellipse mit Default-Settings
strokeWeight(4);
stroke("red");
ellipse(start, 50, d, d);
// mit "push()" aus normalem "Code-Flow" rausnehmen
push();
strokeWeight(12);
stroke("black");
fill(204, 153, 0);
ellipse(start + 2 * d, 50, d, d);
push();
stroke(0, 102, 153);
ellipse(start + 3 * d, 50, d, d);
pop();
// Ende des speziellen "Codes"
pop();
// ab hier wieder normaler "Code-Flow"
// deswegen Ellipse wieder mit Einstellungen, die vor push & pop festgelegt wurden
ellipse(start + 5 * d, 50, d, d);
}
Oft ist es einfacher, Elemente ganz "normal" am oberen Rand des Canvas zu konstruieren und diese dann mit push() und pop() an die Stelle zu schieben, wo man diese braucht. Im nächsten Beispiel seht Ihr, dass man diese mit push() und pop() auch drehen kann…
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// …
// 3 ganz normale Elemente, die am oberen Rand kleben
fill("blue");
stroke("blue");
ellipse(0, 0, 10);
line(0, 0, 0 + 200, 0);
ellipse(0 + 200, 0, 10);
// 3 Elemente, die mit "translate()" verschoben werden
push();
translate(20, 20);
stroke("orange");
fill("orange");
// Beachtet, das die x- und y-Werte identisch wie bei den oberen Elementen sind!
// nur durch "translate(20,20)" werden sie gemeinsam verschoben
// das ist oft vom Kopf einfacher als immer alles umrechnen zu müssen…
ellipse(0, 0, 10);
line(0, 0, 0 + 200, 0);
ellipse(0 + 200, 0, 10);
pop();
// …
}
"push()" nimmt alles, was bis "pop()" hier steht, aus dem Zusammenhang und verhindert so, dass die "rotate()" Angabe auch auf die 3. Linie und das 3. Rechteck angewandt werden
Deaktiviert mal push() und pop() und seht, was dann passiert!
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
function setup() {
// …
stroke("red");
line(5, 2, 95, 2);
rectMode(CENTER);
stroke("#ddd");
fill("black");
rect(50, 50, 90);
// "push()" nimmt alles, was bis "pop()" hier steht,
// aus dem Zusammenhang und verhindert so,
// dass die "rotate()" Angabe auch auf die 3. Linie und
// das 3. Rechteck angewandt werden
// Deaktiviert mal push() und pop() und seht, was dann passiert!
push();
// Drehpunkt ist die obere, linke Ecke des Canvas
// wenn man es nicht mit "translate()" definiert
// Drehung um -35° Grad
rotate(radians(-35));
stroke("red");
line(5, 120, 95, 120);
stroke("#ddd");
rectMode(CENTER);
rect(50, 170, 90);
pop();
stroke("red");
line(205, 120, 295, 120);
noStroke();
rectMode(CENTER);
rect(250, 170, 90);
}
Im unten gezeigten for-loop wird in jeder Schleife das Koordinaten-System um den vorgegebenen Wert "winkel" um den Mittelpunkt des Canvas gedreht.
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
let winkel;
function setup() {
// …
const xMitte = width / 2;
const yMitte = height / 2;
const laenge = 140; // Länge der Linie
// 3 ganz normale Elemente, die am oberen Rand kleben
fill("blue");
stroke("blue");
ellipse(0, 0, 10);
line(0, 0, 0 + laenge, 0);
ellipse(0 + laenge, 0, 10);
// gleiche Elemente, aber mit push & pop verschoben und gedreht
push();
fill("orange");
stroke("orange");
// verschieben um jeweils 20px
translate(20, 20);
// drehen des Koordinaten-Systems um 20°
// der Drehpunkt liegt hier bei (20,20);
// der Drehpunkt liegt hier bei (20,20);
rotate(radians(20));
ellipse(0, 0, 10);
line(0, 0, 0 + laenge, 0);
ellipse(0 + laenge, 0, 10);
pop();
// mit for-Loop viele Drehungen erzeugt
// 36 * 10° = 360° (komplette Drehung)
for (var i = 0; i < 36; i++) {
push();
translate(width / 2, height / 2);
// der Drehpunkt liegt hier bei (width / 2, height / 2);
rotate(winkel);
fill(255, 0, 0);
stroke(255, 0, 0);
ellipse(0, 0, 10);
line(0, 0, 0 + laenge, 0);
// Sonderbehandlung der äußeren Kreise
// ebenfalls durch push & pop „isoliert
push();
fill("white");
ellipse(0 + laenge + 10, 0, 10);
pop();
pop();
winkel = winkel + radians(10);
}
}
Innerhalb der Funktion "draw()" wird bei jedem Durchlauf der Winkel um einen festgelegten Wert geändert und entsprechend das Koordinaten-System gedreht. Entsprechend ändert sich die Darstellung von Linien und Kreise.
Durch den Einsatz von random ändern sich Winkel, Durchmesser und Länge des Striches.
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
let xMitte, yMitte;
let laenge = 140;
let step = 5;
let winkel = 0;
let d = 10;
function setup() {
// …
// Gradangabe, um wieviel gedreht wird
winkel = radians(0);
xMitte = width / 2;
yMitte = height / 2;
frameRate(30);
}
function draw() {
push();
// Verschieben von Kreisen und Linien in die Mitte
translate(xMitte, yMitte);
// animiert rotieren durch "winkel = winkel + step;"
rotate(radians(winkel));
// die schwarze Linie
stroke(0);
line(0 - laenge, 0, 0 + laenge, 0);
// die Kreise an den Enden der Linie
fill("white");
ellipse(0 - laenge - d, 0, d);
ellipse(0 + laenge + d, 0, d);
// roter Kreis in der Mitte
strokeWeight(3);
stroke("white");
fill("red");
ellipse(0, 0, d * 4);
pop();
winkel = winkel + step;
if (winkel > 180) {
background("#fff");
winkel = 0;
// zufällige Werte generieren
step = random(0.5, 10);
laenge = random(90, height / 2 - 10);
d = random(5, 20);
}
}
Weiterentwicklung des vorherigem Beispiels – nur mit noch mehr Einsatz von random()
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
let xMitte, yMitte;
let laenge = 140;
let step = 5;
let winkel = 0;
let d = 10;
function setup() {
const meinCanvas = createCanvas(600, 350);
meinCanvas.parent("canvasContainer");
// Gradangabe, um wieviel gedreht wird
winkel = radians(0);
xMitte = width / 2;
yMitte = height / 2;
frameRate(30);
background("black");
}
function draw() {
push();
// Verschieben von Kreisen und Linien in die Mitte
translate(xMitte, yMitte);
// animiert rotieren durch "winkel = winkel + step;"
rotate(radians(winkel));
// die schwarze Linie
stroke(80);
line(0 - laenge, 0, 0 + laenge, 0);
// die Kreise an den Enden der Linie
// noStroke();
fill(random(255), random(255), random(255), random(200, 255));
ellipse(0 - laenge, 0, d);
ellipse(0 + laenge, 0, d);
pop();
fill(255, 100);
noStroke();
// ellipse(xMitte, yMitte, 40);
winkel = winkel + step;
d = random(10, 40);
laenge = random(50, width / 2);
step = random(0.5, 15);
// Abdeckfläche, die Sachen langsam verblassen lässt
// geht durch "fill(0, 10);" 10 bedeutet dabei weitgehend transparent
fill(0, 10);
rect(0, 0, width, height);
}
Der Sketch holt sich die Sekunden, Minuten und Stunden aus dem System des Computers und nützt diese Zahlen, um das Koordinaten-System des jeweiligen Zeigers zu drehen. So ist es möglich, die Uhrzeit analog darzustellen.
Im hier gezeigten Beispiel wird nur der Sekundenzeiger dargestellt.
Schaut Euch die Demo an – oder ladet das komplette Paket runter!
let winkel;
let xMitte, yMitte;
const laenge = 130;
function setup() {
const meinCanvas = createCanvas(600, 350);
meinCanvas.parent("canvasContainer");
// Gradangabe, bei Sekunden ganz oben starten
winkel = radians(270);
// Angaben zur Schrift
textFont("Roboto Slab"); // hier auch der Webfont von Google!
xMitte = width / 2;
yMitte = height / 2;
background("#ddd");
frameRate(1); // einmal pro Sekunde aktualisieren;
}
function draw() {
background("#ddd");
scalaZeichnen();
digitalAusgabe();
stundenZeiger(); // schon weiter unten vorbereitet! (schwierig!)
minutenZeiger(); // schon weiter unten vorbereitet!
sekundenZeiger();
}
function digitalAusgabe() {
textAlign(CENTER);
textSize(18);
fill(255);
noStroke();
let sek = second();
let min = minute();
let stunde = hour();
// bei einstelligen Werten noch eine "0" einfügen
// weil sonst die Uhrzeit eigenartig aussieht
if (sek < 10) {
sek = "0" + sek;
}
if (min < 10) {
min = "0" + min;
}
if (stunde < 10) {
stunde = "0" + stunde;
}
text(stunde + ":" + min + ":" + sek, xMitte, yMitte - 17);
}
function scalaZeichnen() {
// Anzeige der Mitte
fill(60);
noStroke();
ellipse(xMitte, yMitte, 18);
// fetter Dot bei den Viertelstunden
for (var i = 0; i < 4; i++) {
push();
translate(width / 2, height / 2);
rotate(winkel);
noStroke();
fill(60);
ellipse(0 + laenge + 8, 0, 12);
pop();
winkel = winkel + radians(90);
}
// alle 5min ein Dot
for (var i = 0; i < 12; i++) {
push();
translate(width / 2, height / 2);
rotate(winkel);
noStroke();
fill(60);
ellipse(0 + laenge + 8, 0, 8);
pop();
winkel = winkel + radians(30);
}
// alle 1min ein kleiner Dot
for (var i = 0; i < 60; i++) {
push();
translate(width / 2, height / 2);
rotate(winkel);
noStroke();
fill(255);
ellipse(0 + laenge + 8, 0, 3);
pop();
winkel = winkel + radians(6);
}
}
function stundenZeiger() {
let stunde = hour();
console.log(stunde); // Ausgabe in der Konsole
let min = minute(); // wird hier auch gebraucht!
// hier die Anzeige des jeweiligen Zeigers einbauen!
// ACHTUNG: 12 Stunden-Anzeige -- Sonderfall!
}
function minutenZeiger() {
let min = minute();
console.log(min); // Ausgabe in der Konsole
// hier die Anzeige des jeweiligen Zeigers einbauen!
}
function sekundenZeiger() {
let sek = second();
// Aussehen des Sekundenzeiger
strokeWeight(4);
stroke(255, 0, 0);
fill(255, 0, 0);
push();
translate(xMitte, yMitte);
// "sek * 6", weil 60sek pro Minute, entspricht 6° * 60 = 360°
// "270" damit bei "12Uhr" angefangen wird
rotate(radians(270 + sek * 6));
ellipse(0, 0, 5);
line(0, 0, laenge, 0);
pop();
}
Erweitert den vorherigen Sketch („Sekundenzeiger mit Push & Pop“) so, dass der Minuten-Zeiger und – als Königsaufgabe – auch der Stundenzeiger richtig dargestellt wird.
Der Stundenanzeiger ist schwieriger, weil dieser im Lauf der jeweiligen Stunde nicht fix an einer Stelle stehen bleibt, sondern sich langsam zwischen der aktuellen und der kommenden Stunden-Ziffer weiter bewegt…
Wir hören/sehen uns nächsten Donnerstag (23.4.2020)!
Bleibt gesund!