Unter Processing.org kann die Programmeirumgebung für Processing kostenlos für alle gängigen Betriebssysteme heruntergeladen werden. Die heruntergeladene ZIP-Datei muss entpackt werden. Anschliessend kann die Anwendung Processing gestartet werden.
Der Editor ist sehr einfach aufgebaut und lässt sich intuitiv bedienen. Erste Anweisungen lassen sich mit Strichpunkten (;) getrennt eintippen und mit dem Run-Knopf austesten. Viel Erfolg!
Hinweis: Processing erstellt einen Ordner mit dem Programmnamen und darin die eigentliche Programmdatei mit gleichem Namen und der Erweiterung .pde. Diese beiden Namen müssen zwingend identisch sein. Belassen Sie die Ordner- oder Dateinamen unverändert.
circle(x, y, d)square(x, y, s)arc().Hinweis: Die Funktion radians() rechnet Grad (0 - 360) in Bogenmass (0 - 2*PI) um und die Funktion degrees() Bogenmass in Grad.
Hinweis: PI, TWO_PI, HALF_PI und QUARTER_PI sind Konstanten die in Processing zur Verfügung stehen.
fill( ) mit Hilfe der Simulation. Was bedeuten jeweils die Parameter?fill( )-Funktion auf die background( )-Funktion an.size(400,420); background(255); fill(51); ellipse(80,140,120,190); fill(152,204); ellipse(170,80,190,90); fill(229,152,0); ellipse(180,320,250,140); fill(39,229,52,205); ellipse(270,270,150,280);
Hinweis für Farbliebhaber: Neben dem hier gezeigten RGB-System kennt Processing auch das HSB-System. Konsultieren Sie dazu die Processing-Referenz.
stroke( ) mit Hilfe der Simulation. Was bedeuten jeweils die Parameter?noStroke( ) und noFill( ) ohne Parameter an verschiedenen Stellen im Code ein. Was bewirken diese?size(400,420); background(255); strokeWeight(16); fill(160); stroke(50); ellipse(80, 140, 120, 190); stroke(153, 204); fill(83); ellipse(170, 80, 190, 90); stroke(229, 153, 0); fill(70, 121, 211); ellipse(180, 320, 250, 140); stroke(39, 229, 52, 205); fill(172, 85, 232); ellipse(270, 270, 150, 280);
Variabeln dienen zur Speicherung von Daten. Daten werden auf dem Datenträger in binärer Form gespeichert, d.h. als Folgen aus lauter Einsen und Nullen. Acht Bit zusammen ergeben ein Byte, z.B. 01101011. Diese Zahlenfolge 011010112 entspricht 10710 im Dezimalsystem.
Ein Bit kann man als Schalter mit den beiden Zuständen offen und zu. Nur wenn der Schalter geschlossen ist, fliesst Strom. Der offene Schalter wird mit 1 und der geschlossene Schalter mit 0 dargestellt.
Variabeln kann man sich als Boxen vorstellen, die einen Datenwert aufnehmen können. Je nach Datentyp ist die Box unterschiedlich gross.
Folgende Standard-Datentypen kennt Processing:
| Datentyp | Speicherbedarf (Byte) | Wertebereich | Standardwert |
|---|---|---|---|
| byte | 1 | -128 bis +127 | 0 |
| short | 2 | -32768 bis +32767 | 0 |
| int | 4 | -2147483648 bis +2147483647 | 0 |
| long | 8 | -263 bis +263-1 | 0 |
| float | 4 | +- 3.40282347 * 1038 | 0.0 |
| double | 4 | +- 1.79769313 * 10308 | 0.0 |
| boolean | 1 | true, false | false |
| char | 2 | alle Unicodezeichen | |
| String | x*2 | Zeichenketten | |
Da je nach Datentyp unterschiedlich viel Speicherplatz benötigt wird, müssen Variablen deklariert werden. D.h. es muss der Datentyp und der Name der Variabeln festgelegt werden. Bei der Deklaration wird eine Box (vgl. Bild oben) der richtigen Grösse bereitgestellt und mit dem Variablennamen beschriftet.
// Deklaration byte meinByte; char meinZeichen; int meineGanzzahl; float meineKommazahl; String meineZeichenkette; //Initialisierung meinByte = 107; meinZeichen = 'R'; meineGanzzahl = 2782; meineKommazahl = 7.317; meineZeichenkette = "Hallo Welt";
Erst dank der Deklaration kann einer Variable ein Wert zugewiesen werden. Bei der ersten Wertzuweisung spricht man von der Initialisierung. Die Werte der Variablen können jederzeit ausgegeben oder für Berechnungen benutzt werden.
Wie der Name sagt, sind die Werte von Variabeln variabel. Die Werte können mit einer erneuten Wertzuweisung überschrieben, d.h. verändert, werden.
Deklaration und Initialisierung lassen sich in einer Anweisung kombinieren:
//Deklaration int a; int b; float v; // Deklaration + Initialisierung byte meinByte = 107; char meinZeichen = 'R'; int meineGanzzahl = 2782; float meineKommazahl = 7.317; String meineZeichenkette = "Hallo Welt"; // Wertzuweisungen a = meineGanzzahl; b = 31639 - meineGanzzahl; a = a * 2; v = meineKommazahl / 4; b = b + 100; meineZeichenkette = "Sprich: " + meineZeichenkette; // Ausgabe in Konsole println(a);
a = a * meineKommazahl. Was beobachten Sie? Wo liegt das Problem?Hinweis: Die Funktion println() schreibt eine Zeile in die Konsole. print() generiert eine Konsolenausgabe ohne Zeilensprung. Mit diesen beiden Befehlen lassen sich verschiedenste Ausgaben realisieren:
println("Hallo mein Freund");
println("Wert der Variable a ist: " + a);
println(4*5/3.0);
print("meine Kommazahl beträgt: ");
print(meineKommazahl);
Tipp: Mit println()-Ausgaben lassen sich Fehler einfacher aufspüren, indem man an entscheidenden Stellen im Programmablauf den Wert von einer Variable ausgibt.
+ | Addition |
|---|---|
- | Subtraktion |
* | Multiplikation |
/ | Division |
= | Wertzuweisung |
Tipp: Die Zeichen für die Operationen finden sich am einfachsten im Zifferblock der Tastatur.
Hinweis: Wertzuweisungen werden wie folgt gelesen: x = x + 11 wird als "x wird zu x + 11" gelesen.
Wird eine Variable vor dem setup()-Block deklariert, so ist sie global sichtbar. D.h. man kann aus allen Codeblöcken heraus auf diese Variable zugreifen.
Wird dagegen eine Variable innerhalb eines Blocks, z.B. im draw()-Block deklariert, ist diese Variable nur innerhalb dieses Blocks sichtbar. Man spricht von einer lokalen Variablen.
Tipp: Verwenden Sie wo immer möglich lokale Variablen. So werden Fehler durch unbeabsichtigtes Überschreiben von Variabelnwerten minimiert.
Hinweis: Wird eine lokale Variable mit gleichem Namen wie eine globale Variable eingesetzt, so überdeckt die lokale Variable die globale. Im Notfall kann mit vorangestelltem this. auf die globale Variable zugegriffen werden. Z.B. a = this.meineZahl;.
//Deklaration globale Variabeln
int meineGanzzahl = 2782;
float meineKommazahl = 7.317;
void setup() {
// lokale Deklaration
int meineGanzzahl = 125;
float winkel = 2.0478;
println(meineGanzzahl);
println(meineKommazahl);
println(winkel);
println(this.meineGanzzahl);
}
void draw() {
// lokale Deklaration
int a = 353;
println(meineGanzzahl);
println(a);
println(winkel);
noLoop();
}
// voranstellen.noLoop() entfernen? Studieren Sie auch die folgende Abbidlung.
Um Farben zu speichern, bietet Processing den Datentyp color an. Farben werden bekanntlich mit einem bis vier Parametern festgelegt. Die Funktion color() erstellt aufgrund der ihr übergebenen Parametern die eigentliche Farbe. So lassen sich Farben generieren und in Variablen speichern:
//Deklaration color meinGrau; color meinGrau2; color meineFarbe; color meineFarbe2; //Initialisierung meinGrau = color(100); // color(Grauwert) meinGrau2 = color(100,180); // color(Grauwert,Deckkraft) meineFarbe = color(255,190,40); // color(R,G,B) meineFarbe2 = color(255,190,40,180); // color(R,G,B,Deckkraft) fill(meinGrau); rect(0,0,60,60); fill(meinGrau2); rect(60,0,60,60); fill(meineFarbe); rect(120,0,60,60); fill(meineFarbe2); rect(180,0,60,60);
Der obige Code generiert folgendes Bild:
Eine Variable vom Typ Array, auch Datenfeld genannt, kann mehrere Werte des gleichen Typs speichern. Unter dem gleichen Namen lassen sich viele Werte abspeichern, die mit einem Index angesprochen werden. Die Nummerierung beginnt mit dem Index 0.
Hinweis: Beachten Sie, dass der letzte Index eines Arrays immer um 1 kleiner ist, als die Länge des Datenfeldes. Die Länge eines Arrays lässt sich mit der Funktion myArray.length ermitteln.
// Deklaration int[] meineZahlenreihe; // Initialisierung meineZahlenreihe = new int[9]; //Wertzuweisung meineZahlenreihe[0] = 4; meineZahlenreihe[3] = 132; meineZahlenreihe[5] = 71; // Konsolenausgabe println(meineZahlenreihe[3]); println(meineZahlenreihe[0]); println(meineZahlenreihe[8]); println(meineZahlenreihe); // gibt das ganze Array aus
println(meineZahlenreihe[9]); einfügen?der letzte Index von meineZahlenreihe ist: 8Hinweis: Deklaration und Wertzuweisung lassen sich bei Arrays kombinieren:
// Deklaration
int[] meineZahlenreihe;
// Initialisierung & Zuweisung kombiniert
meineZahlenreihe = new int[] {5, -14, 67, 0, -2, 4};
Beim Programmieren sind zweidimensionale Arrays oft sehr hilfreich. So zum Abbilden eines Koordinatensystems wie in den Spielen "Vier gewinnt" oder "Schiffe versenken". Zweidimensionale Arrays lassen sich einfach deklarieren:
// Deklaration
int[][] meinKoordinatenfeld;
// Initialisierung & Zuweisung kombiniert
meinKoordinatenfeld = new int[][] {{1, 0, 2},{2, 2 , 0},{1, 0, 1}};
// Konsolenausgabe
println(meinKoordinatenfeld[1][2]);
// einzelne Wertzuweisung
meinKoordinatenfeld[1][2] = 1;
// Konsolenausgabe
println(meinKoordinatenfeld[1][2]);
Die Ganzzahlen können als Code betrachtet werden:
Das erstellte Array sieht wie folgt aus:
Tipp: Für das Durchlaufen von 2D-Arrays sind verschachtelte for-Schleifen sinnvoll.
| Name | Beschreibung |
|---|---|
mouseX | x-Koordinate der Maus |
mouseY | y-Koordinate der Maus |
pmouseX | vorherige x-Koordinate der Maus |
pmouseY | vorherige y-Koordinate der Maus |
mousePressed | ist TRUE wenn die Maustaste gedrückt, sonst FALSE |
width | Fensterbreite in Pixel |
height | Fensterhöhe in Pixel |
PI | PI, 3.1415... |
|---|---|
TWO_PI | 2*PI |
HALF_PI | PI/2 |
QUARTER_PI | PI/4 |
Funktionen sind Unterprogramme, die bestimmte, isolierte Aufgaben übernehmen. Bekannt sind die beiden Systemfunktionen void setup() und void draw().
Eine dritte zentrale Systemfunktion ist void mousePressed(). Sie wird bei Mausklick einmalig durchlaufen:
Übernehmen Sie den folgenden Code in einen leeren Sketch und testen Sie die Funktionsweise von void mousePressed().
int rot = 45;
int gruen = 30;
int blau = 90;
void setup() {
size(200,100);
}
void draw() {
background(rot, gruen, blau);
}
void mousePressed() {
rot = rot + 30;
if (rot > 255) {
rot = 45;
}
}
Wir nehmen uns vor, einen Hund zu zeichnen. Damit es einfacher wird, verschieben wir mit translate(100,100) den Nullpunkt des Koordinatensystems zum Punkt 100/100. Dies ist zugleich die Mitte der Zeichnung. Nun können wir die verschiedenen Formen symmetrisch zur Mittelachse zeichnen. In der Skizze sind der Ursprung 0/0 und die Koordinaten der Mittelpunkte der Formen von Hand eingetragen.
Programmieren Sie einen Sketch, der einen Hund mit den skizzierten Dimensionen zeichnet.
Der Code für den ganzen Hund sieht wie folgt aus:
void setup() {
size(200, 200);
smooth();
}
void draw() {
background(200);
translate(100, 100);
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(240);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
}
Um den Hund zu zeichnen sind viele Anweisungen notwendig und der void draw()-Block wird unübersichtlich. Es macht Sinn, den Code zum Zeichnen des Hundes in eine Funktion mit passendem Namen zu verpacken. Der Aufbau der selber gebauten Funktion ist gleich wie bei den System-Funktionen:
void meinHund() {
Anweisung 1;
...
Anweisung n;
}
Nun kann im void draw()-Block das Zeichnen des Hundes mit dem Aufruf der Funktion meinHund() übersichtlich ausgelöst werden.
void setup() {
size(200, 200);
smooth();
}
void draw() {
background(200);
meinHund();
}
void meinHund() {
translate(100, 100);
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(240);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
}
PS: Das dem Funktionsnamen vorangestellte void zeigt an, dass die Funktion keinen Wert zurück liefert.
Nun möchten wir zwei Hunde zeichnen und zwar an verschiedenen Orten. Man könnte bei der ersten Version ohne Funktion einfach den Code verdoppeln, was aber zu einem extrem schlecht lesbaren Code führt.
Kein vorbildlicher Code!
void setup() {
size(400, 200);
smooth();
}
void draw() {
background(230);
translate(100,100);
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(240);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
translate(200,0);
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(240);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
}
Bedeutend einfacher ist, der Funktion die Koordinaten für den Mittelpunkt des Hundes zu übergeben. Der Funktionskopf wird mit den beiden Parametern xPos und yPos ergänzt. Zu jedem Paramter muss der Datentyp deklariert werden, damit die Funktion entsprechende Variablen bereit stellen kann. In unserem Fall sind dies Ganzzahlen vom Datentyp int.
Im void draw()-Block wird nun die Funktion zweimal aufgerufen und zwar mit unterschiedlichen Koordinaten. Die übergebenen Paramter müssen genau den im Funktionskopf bestimmten Datentypen entsprechen. Hier werden zwei Parameter, beides Ganzzahlen, erwartet.
void setup() {
size(400, 200);
smooth();
}
void draw() {
background(200);
meinHund(100,100);
meinHund(300,100);
}
void meinHund(int xPos, int yPos) {
pushMatrix(); // bisheriger 0/0-Punkt wird zwischengespeichert
translate(xPos, yPos);
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(240);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
popMatrix(); // zuletzt zwischengespeicherter 0/0-Punkt wird wieder hergestellt
}
PS: Eine selber definierte Funktion mit Parametern funktioniert genau gleich wie von Processing zur Verfügung gestellte Funktionen, z.B. rect(x,y,width,height) oder random(0,26).
Erweitern Sie die Parameter der Funktion meinHund() so, dass auch der Grauwert zur Füllung des Gesichts und die Grösse des Gesichts übergeben werden.
Tipp: Die Grösse kann am einfachsten mit der scale()-Anweisung gesteuert werden.
void setup() {
size(400, 200);
smooth();
}
void draw() {
background(200);
meinHund(100,100,245,1.1);
meinHund(240,80,200,0.6);
meinHund(320,110,225,0.9);
}
void meinHund(int xPos, int yPos, int grau, float sFaktor) {
pushMatrix(); // bisheriger 0/0-Punkt wird zwischengespeichert
translate(xPos, yPos);
scale(sFaktor); // Zeichenfläche skalieren
noFill();
strokeWeight(1);
stroke(90);
fill(30);
ellipse(-40, -50, 60, 60);
ellipse(40, -50, 60, 60);
fill(grau);
ellipse(0, 0, 140, 140);
fill(30);
ellipse(-30, -30, 15, 15);
ellipse(30, -30, 15, 15);
ellipse(0, 10, 40, 40);
strokeWeight(2);
noFill();
arc(-20, 30, 40, 40, 0, HALF_PI);
arc(20, 30, 40, 40, HALF_PI, PI);
popMatrix(); // zuletzt zwischengespeicherter 0/0-Punkt wird wieder hergestellt
}
Die bisher angeschauten Funktionen hatten den Rückgabetyp void. Sie liefern also keinen Wert zurück. Folgende Systemfunktionen liefern ebefalls keinen Wert zurück:
fill(r,g,b);noStroke();line(x1,y1,x2,y2);arc(x,y,w,h,start,end);Viele Funktionen liefern aber einen Wert zurück. Bekannte Systemfunktionen mit Rückgabewert sind:
sin(winkel);sq(zahl);sqrt(zahl);min(zahl1, zahl2 [, zahlX]);dist(x1,y1,x2,y2);Testen Sie den folgenden Sketch:
In diesem Sketch ist eine Funktion eingebaut, die die Fläche des Rechtecks berechnet und zurückliefert. Der Rückgabewert ist vom Typ int.
Der Code zeigt die Besonderheiten
void draw()-Block herausmouseX und mouseY mitgegeben.rechteckFlaeche der Rückgabetyp int vorangestellt.int und übernimmt die Werte in die Variablen laenge und breite.flaeche.flaeche mit return zurück.// Variable zur Speicherung des Rückgabewertes der Funktion
int groesse;
void setup() {
size(660, 120);
}
void draw() {
background(230);
fill(255,196,46);
rect(0, 0, mouseX, mouseY);
// Funktionsaufruf u. Zuweisung des Rückgabewertes an Variable
groesse = rechteckFlaeche(mouseX, mouseY);
// Textausgabe der Reckteckfläche
fill(30);
text("Fläche: " + groesse + " Pixel", 5, 15);
}
// eigene Funktion mit Rückgabewert vom Typ int
int rechteckFlaeche(int laenge, int breite) {
int flaeche = laenge * breite; // Fläche berechnen
return flaeche; // Resultat zurückgeben
}
Studieren Sie den folgenden Sketch und programmieren Sie ihn nach. Setzen Sie eine Funktion zur Berechnung der Mondanziehung ein. Die Mondanziehung ist nur rund 0.165 mal so stark wie die Erdanziehung.
float mErde; // Masse auf der Erde
float mMond; // Masse auf dem Mond
void setup() {
size(300, 300);
}
void draw() {
mErde = height-constrain(mouseY,20,height); // constrain = begrenzen
mMond = umrechnerErdeMond(mErde); // Funktionsaufruf
background(245);
// Säule Erde
fill(46, 46, 255);
text("Erde:",20,height-5);
rect(60, height, 60, -mErde);
// Säule Mond
fill(247, 132, 7);
text("Mond:",140,height-5);
rect(180, height, 60, -mMond);
fill(30);
// Beschriftung beider Werte
text(nf(mErde,1,1)+" kg",70,height-mErde-5);
text(nf(mMond,1,1)+" kg",190,height-mMond-5);
}
// eigene Funktion
// Rückgabewert-Typ Funktionsname (Datentyp Parameter)
float umrechnerErdeMond(float gewichtErde) {
float resultat;
resultat = gewichtErde * 0.165; // Berechnung
return resultat; // Rückgabe des Ergebnisses
}
Schreiben Sie analog zum Beispiel Hund einen Sketch, der folgenden Comic mit Hilfe einer Funktion und der Übergabe von Parametern zeichnet.
Hinweise:
arc() verwendet. Beachten Sie dazu das Kapitel Einleitung > Formen zeichnen > Zusatzinfos zu arc().void draw()-Block, zeichnen.void draw()-Block heraus aufrufen.mögliche Ausgabe:
color meineFarbe = color(255,196,46); translate(100,160); strokeWeight(1); stroke(90); // Stirn fill(meineFarbe); arc(0,0,100,240,PI,TWO_PI); // Augen fill(230); arc(-20,0,40,120,PI,TWO_PI); arc(20,0,40,120,PI,TWO_PI); // Pupillen fill(30); arc(-30,0,20,60,PI,TWO_PI); arc(10,0,20,60,PI,TWO_PI); // Haare noFill(); arc(-20,-120,40,40,PI+HALF_PI,TWO_PI); arc(30,-120,60,60,PI,PI + HALF_PI); arc(20,-120,40,40,PI,PI + HALF_PI); // Mundpartie fill(meineFarbe); ellipse(0,10,160,40); // Mund stroke(30); strokeWeight(2); noFill(); arc(0,10,80,10,0,PI);
color myColor;
void setup() {
size(660, 240);
smooth();
}
void draw() {
background(245);
myColor = color(255,196,46);
comicZeichnen(100,160,myColor,1);
myColor = color(204,189,16);
comicZeichnen(220,120,myColor,0.8);
myColor = color(127,98,23);
comicZeichnen(430,150,myColor,0.7);
myColor = color(16,165,201);
comicZeichnen(350,190,myColor,1.2);
myColor = color(162,47,245);
comicZeichnen(550,170,myColor,1.1);
}
void comicZeichnen(int xPos, int yPos, color meineFarbe, float sFaktor) {
pushMatrix(); // bisheriger 0/0-Punkt wird zwischengespeichert
translate(xPos, yPos);
scale(sFaktor); // Zeichenfläche skalieren
strokeWeight(1);
stroke(90);
// Stirn
fill(meineFarbe);
arc(0,0,100,240,PI,TWO_PI);
// Augen
fill(230);
arc(-20,0,40,120,PI,TWO_PI);
arc(20,0,40,120,PI,TWO_PI);
// Pupillen
fill(30);
arc(-30,0,20,60,PI,TWO_PI);
arc(10,0,20,60,PI,TWO_PI);
// Haare
noFill();
arc(-20,-120,40,40,PI+HALF_PI,TWO_PI);
arc(30,-120,60,60,PI,PI + HALF_PI);
arc(20,-120,40,40,PI,PI + HALF_PI);
// Mundpartie
fill(meineFarbe);
ellipse(0,10,160,40);
// Mund
stroke(30);
strokeWeight(2);
noFill();
arc(0,10,80,10,0,PI);
popMatrix(); // zuletzt zwischengespeicherter 0/0-Punkt wird wieder hergestellt
}
Erweitern Sie die Comicgesichter derart, dass die Pupillen dem Mauszeiger folgen. Beispiel:
void setup() {
size(480, 280);
smooth();
}
void draw() {
if (mousePressed == true) {
fill(70);
}
else {
fill(180);
}
ellipse(mouseX, mouseY, 60, 60);
}
In der Systemvariable mouseButton wird entweder LEFT, RIGHT oder CENTER gespeichert. Mit if (mouseButton == LEFT) {...} kann zum Beispiel ein Linksklick gestgestellt werden.
Ergänzen Sie den obigen Code so, dass sich die Farbe der Kreise in Abhängigkeit von der gedrückten Maustaste ändert.
void setup() {
size(480, 280);
smooth();
}
void draw() {
if (mousePressed) {
if (mouseButton == LEFT) {
fill(210, 50, 50);
}
if (mouseButton == CENTER) {
fill(50, 210, 50);
}
if (mouseButton == RIGHT) {
fill(50, 50, 210);
}
}
else {
fill(180);
}
ellipse(mouseX, mouseY, 60, 60);
}
Mouse-Events können auch in separaten Systemfunktionen abgearbeitet werden. Zur Verfügung stehen:
mousePressed() | Code wird bei Mausklick einmal ausgeführt |
|---|---|
mouseReleased() | Code wird beim Loslassen eines Mausbuttons einmal ausgeführt |
mouseMoved() | Code wird beim Bewegen der Maus einmal ausgeführt |
mouseDragged() | Code wird beim Bewegen der Maus bei gehaltener Maustaste einmal ausgeführt |
// globale Variabeln
int xMuenze;
int yMuenze;
int dMuenze= 30; // Durchmesser der Muenze
int xZiel;
int yZiel;
int dZiel = 70; // Durchmesser des Ziels
// setup() wird beim Start einmal ausgeführt
void setup() {
size(250,250);
xMuenze = 40;
yMuenze = 35;
xZiel = width/2;
yZiel = height/2;
}
// draw() wird wiederholt
void draw() {
background(230);
fill(50);
ellipse(xZiel, yZiel, dZiel, dZiel);
fill(210, 50, 50);
ellipse(xMuenze, yMuenze, dMuenze, dMuenze);
}
// wird ausgeführt, wenn die Maus gedrückt bewegt wird
void mouseDragged() {
xMuenze = mouseX;
yMuenze = mouseY;
}
dist() im Block draw().mouseDragged() analoge Prozedur ein.Testen Sie das fertige Programm:
// globale Variabeln
int xStart = 40;
int yStart= 35;
int xMuenze;
int yMuenze;
int dMuenze= 30; // Durchmesser der Muenze
int xZiel;
int yZiel;
int dZiel = 70; // Durchmesser des Ziels
float abstand; // Abstand zum Ziel
// setup() wird beim Start einmal ausgeführt
void setup() {
size(250, 250);
xMuenze = xStart;
yMuenze = yStart;
xZiel = width/2;
yZiel = height/2;
}
// draw() wird wiederholt
void draw() {
abstand = dist(xMuenze, yMuenze, xZiel, yZiel);
if (abstand < dZiel/2 - dMuenze/2) {
background(50, 230, 50);
}
else {
background(230);
}
fill(50);
ellipse(xZiel, yZiel, dZiel, dZiel);
fill(210, 50, 50);
ellipse(xMuenze, yMuenze, dMuenze, dMuenze);
}
// wird ausgeführt, wenn die Maus gedrückt bewegt wird
void mouseDragged() {
xMuenze = mouseX;
yMuenze = mouseY;
}
// wird einmal ausgeführt, wenn die Maustaste losgelassen wird
void mouseReleased() {
xMuenze = xStart;
yMuenze = yStart;
}
Erweitern Sie den obigen Sketch zu einem einfachen Spiel:
frameCount und frameRate an Stelle von Zeitfunktionen wie minute(), second() etc.Viel Spass!
Die Systemvariable keyPressed funktioniert analog zu mousePressed
void setup() {
size(480, 280);
smooth();
}
void draw() {
if (keyPressed == true) {
fill(70);
}
else {
fill(180);
}
ellipse(mouseX, mouseY, 60, 60);
}
In der Systemvariable key wird der gedrückte Buchstabe gespeichert. Mit if (key == 's' || key == 'S') {...} kann zum Beispiel auf die Eingabe von 's' oder 'S' getestet werden.
Ergänzen Sie den obigen Code so, dass die Farbe nur ändert wenn 'f' oder 'F' gedrückt wird.
void setup() {
size(480, 280);
smooth();
}
void draw() {
if (keyPressed == true && key == 'f' || key == 'F') {
fill(70);
}
else {
fill(180);
}
ellipse(mouseX, mouseY, 60, 60);
}
Key-Events können in der Systemfunktionen keyPressed() abgearbeitet werden. Zur Verfügung stehen folgende Variabeln oder Funktionen:
keyPressed() | Systemfunktion wird beim Drücken einer Taste einmal ausgeführt. Die gedrückte Taste wird in der Systemvariable key gespeichert. |
|---|---|
keyReleased() | Systemfunktion wird beim Loslassen einer Taste einmal ausgeführt. Die losgelassene Taste wird in der Systemvariable key gespeichert. |
key | Systemvariable für das Erkennen welche Taste gedrückt wurde. Beispiel: if (key == 'b' || key == 'B') {...} |
keyCode | Systemvariable für das Erkennen von Spezialtasten wie die Pfeiltasten UP, DOWN, LEFT, RIGHT und ALT, CONTROL, SHIFT. Beispiel: if (keyCode == UP) {...}Achtung, die Spezialtasten BACKSPACE, TAB, ENTER, RETURN, ESC und DELETE werden nicht codiert und müssen direkt mit key verarbeitet werden. Beispiel: if (key == BACKSPACE) {...} |
Anhand eines kleinen Spiels sollen die Möglichkeiten der Key-Events gezeigt werden. Zuerst wird ein einfaches Raumschiff entworfen. Wie kann dieses Raumschiff möglichst einfach gezeichnet werden?
Das Raumschiff ist mit Kreisbogen, arc(x, y, breite, höhe, startWinkel, endWinkel), einfach zu zeichnen. Mit einem Rechteck ergänzt ist der Raumgleiter schon fertig. In der folgenden Skizze sind nur die Umrisse und Ursprünge der Formen eingezeichnet.
fill(57,63,170); noStroke(); arc(0, 0, 20, 60, PI, TWO_PI); rect(-10,0,20,10); fill(183,187,242); arc(0, -10, 10, 30, PI, TWO_PI); fill(222,58,118); arc(-10, 20, 10, 50, PI, PI + HALF_PI); arc(10, 20, 10, 50, PI + HALF_PI, TWO_PI);
Tipp: mit translate(x,y) kann vor dem Zeichnen der Ursprung an die gewünschte Position verschoben werden und anschliessend mit translate(-x,-y) wieder zurück.
int schritt = 3;
int xRaumschiff; // x-Position des Raumschiffs
void setup() {
size(280, 140);
smooth();
xRaumschiff = width/2; // x-Startposition festlegen
}
void draw() {
background(150);
raumschiffZeichnen(xRaumschiff,height-25);
}
void raumschiffZeichnen(int xPos, int yPos) {
translate(xPos, yPos); // Zeichnenursprung verschieben
fill(57,63,170);
noStroke();
arc(0, 0, 20, 60, PI, TWO_PI);
rect(-10,0,20,10);
fill(183,187,242);
arc(0, -10, 10, 30, PI, TWO_PI);
fill(222,58,118);
arc(-10, 20, 10, 50, PI, PI + HALF_PI);
arc(10, 20, 10, 50, PI+ HALF_PI, TWO_PI);
translate(-xPos, yPos); // Zeichnenursprung zurück verschieben
}
void keyPressed() {
if (keyCode == LEFT) {
xRaumschiff = xRaumschiff - schritt;
if (xRaumschiff < 0) {
xRaumschiff = width;
}
}
}
Ergänzen Sie den obigen Code so, dass das Raumschiff erst mit 's' oder 'S' gestartet wird. Der Sketch soll sich wie hier verhalten:
Tipp: Für Schalter wie "gestartet" oder "nicht gestartet" eignet sich der Datentyp boolean.
int schritt = 3;
int xRaumschiff;
boolean gestartet = false;
void setup() {
size(280, 140);
smooth();
xRaumschiff = width/2;
}
void draw() {
background(150);
if (gestartet == false) {
fill(255);
text("'s' für Start", 10, 20);
text("bewegen mit den Pfeiltasten links | rechts", 10, 40);
}
raumschiffZeichnen(xRaumschiff, height-25);
}
void raumschiffZeichnen(int xPos, int yPos) {
translate(xPos, yPos);
fill(57, 63, 170);
noStroke();
arc(0, 0, 20, 60, PI, TWO_PI);
rect(-10, 0, 20, 10);
fill(183, 187, 242);
arc(0, -10, 10, 30, PI, TWO_PI);
fill(222, 58, 118);
arc(-10, 20, 10, 50, PI, PI+ HALF_PI);
arc(10, 20, 10, 50, PI+ HALF_PI, TWO_PI);
translate(-xPos, yPos);
}
void keyPressed() {
if (key == 's' || key == 'S') {
gestartet = true;
}
if (gestartet == true) {
if (keyCode == LEFT) {
xRaumschiff = xRaumschiff - schritt;
if (xRaumschiff < 0) {
xRaumschiff = width;
}
}
if (keyCode == RIGHT) {
xRaumschiff = xRaumschiff + schritt;
if (xRaumschiff > width) {
xRaumschiff = 0;
}
}
}
}
Nun soll das Raumschiff durch das Weltall fliegen und Planeten und Gaswolken begegnen:
image(bild, xPos, yPos) im Sketch.

PImage und die Bildausrichtung imageMode(CENTER).v für die Geschwindigkeit der Objekte ein. Bewegen Sie die Objekte bei jedem Durchlauf von draw() in y-Richtung um den Wert von v.random(0,width).So könnte die Lösung funktionieren - bitte antesten:
int schritt = 4;
int xRaumschiff;
boolean gestartet = false;
// Variablen für die beiden Bilder deklarieren
PImage meinPlanet;
PImage meinNebel;
// Fluggeschwindigkeit deklarieren und initialisieren
float v = 4;
// Startpositionen der Objekte deklarieren und initialisieren
float xPlanet = 40;
float yPlanet = 0;
float xNebel = 120;
float yNebel = 35;
void setup() {
size(280, 280);
smooth();
xRaumschiff = width/2;
// Ursprung für die Anzeige von Bildern ins Zentrum des Bildes setzen
imageMode(CENTER);
// Bilder in die bereit gestellten Variabeln einmalig !!! laden
meinPlanet = loadImage("planet.png");
meinNebel = loadImage("nebel.png");
}
void draw() {
background(150);
if (gestartet == false) {
fill(255);
text("'s' für Start", 10, 20);
text("bewegen mit den Pfeiltasten links | rechts", 10, 40);
}
else {
// Planet bewegen und allenfalls an oberen Rand mit zufälliger xPosition setzen
yPlanet = yPlanet + v;
if (yPlanet > height) {
yPlanet = 0;
xPlanet = random(0,width);
}
// Nebel bewegen und allenfalls an oberen Rand mit zufälliger xPosition setzen
yNebel = yNebel + v;
if (yNebel > height) {
yNebel = 0;
xNebel = random(0, width);
}
// Bilder an der aktuellen Position anzeigen
image(meinPlanet,xPlanet,yPlanet);
image(meinNebel,xNebel,yNebel);
}
// Raumschiff an der aktuellen Position anzeigen
raumschiffZeichnen(xRaumschiff, height-25);
}
// benutzerdefinierte Funktion zum Zeichnen eines Raumschiffs
void raumschiffZeichnen(int xPos, int yPos) {
translate(xPos, yPos); // Zeichnenursprung verschieben
fill(57, 63, 170);
noStroke();
arc(0, 0, 20, 60, PI, TWO_PI);
rect(-10, 0, 20, 10);
fill(183, 187, 242);
arc(0, -10, 10, 30, PI, TWO_PI);
fill(222, 58, 118);
arc(-10, 20, 10, 50, PI, PI+ HALF_PI);
arc(10, 20, 10, 50, PI+ HALF_PI, TWO_PI);
translate(-xPos, yPos); // Zeichnenursprung zurück verschieben
}
// Steuerung des Raumschiffs per Key-Ereignisse
void keyPressed() {
if (key == 's' || key == 'S') {
gestartet = true;
}
if (gestartet == true) {
if (keyCode == LEFT) {
xRaumschiff = xRaumschiff - schritt;
if (xRaumschiff < 0) {
xRaumschiff = width;
}
}
if (keyCode == RIGHT) {
xRaumschiff = xRaumschiff + schritt;
if (xRaumschiff > width) {
xRaumschiff = 0;
}
}
}
}
Nun soll das einfache Spiel fertig gestellt werden:
score zum Zählen der Punkte ein.dist(x1,y1,x2,y2) die Kollision des Raumschiffs mit dem Planet und dem Nebel. Eine Kollision mit dem Planet gibt 20 Punkte Abzug. Der Nebel enthält Energie und der Spieler erhält 10 Punkte gutgeschrieben.dist():
Wenn die Distanz kleiner als die Summe der beiden Radien ist, so sind sich die Objekte zu nahe. Für Planet und Raumschiff beträgt die Summe der Radien z.B. 35. In code umgesetzt:if (dist(xPlanet, yPlanet, xRaumschiff, yRaumschiff) < 35) { ... }
So könnte die Lösung ticken - bitte antesten:
int schritt = 6;
int xRaumschiff;
int yRaumschiff;
boolean gestartet = false;
// Variablen für die beiden Bilder deklarieren
PImage meinPlanet;
PImage meinNebel;
// Fluggeschwindigkeit deklarieren und initialisieren
float v = 4;
// Startpositionen der Objekte deklarieren und initialisieren
float xPlanet = 40;
float yPlanet = 0;
float xNebel = 120;
float yNebel = 35;
int score = 0;
void setup() {
size(280, 280);
smooth();
xRaumschiff = width/2;
yRaumschiff = height-25;
// Ursprung für die Anzeige von Bildern ins Zentrum des Bildes setzen
imageMode(CENTER);
// Bilder in die bereit gestellten Variabeln einmalig !!! laden
meinPlanet = loadImage("planet.png");
meinNebel = loadImage("nebel.png");
}
void draw() {
background(150);
if (gestartet == false) {
fill(255);
textSize(12);
textAlign(LEFT);
text("'s' für Start", 10, 20);
text("bewegen mit den Pfeiltasten links | rechts", 10, 40);
}
else {
// Planet bewegen
yPlanet = yPlanet + v;
// falls Kollision mit Raumschiff Punkte abziehen und zurück an oberen Rand
if (dist(xPlanet, yPlanet, xRaumschiff, yRaumschiff) < 35) {
yPlanet = 0;
xPlanet = random(0, width);
score = score - 20;
// falls Score kleiner 0 Spiel zurücksetzen
if (score < 0) {
score = 0;
gestartet = false;
yPlanet = 0;
yNebel = 0;
}
}
// falls Planet unten verschwunden an oberen Rand mit zufälliger xPosition setzen
if (yPlanet > height) {
yPlanet = 0;
xPlanet = random(0, width);
}
// Nebel bewegen
yNebel = yNebel + v;
// falls Kollision mit Raumschiff Punkte abziehen und zurück an oberen Rand
if (dist(xNebel, yNebel, xRaumschiff, yRaumschiff) < 45) {
yNebel = 0;
xNebel = random(0, width);
score = score + 10;
}
// falls Nebel unten verschwunden an oberen Rand mit zufälliger xPosition setzen
if (yNebel > height) {
yNebel = 0;
xNebel = random(0, width);
}
// Bilder an der aktuellen Position anzeigen
image(meinPlanet, xPlanet, yPlanet);
image(meinNebel, xNebel, yNebel);
// Score anzeigen
textSize(20);
textAlign(RIGHT);
text("Score: "+score, width-20, 20);
}
// Raumschiff an der aktuellen Position anzeigen
raumschiffZeichnen(xRaumschiff, yRaumschiff);
}
// benutzerdefinierte Funktion zum Zeichnen eines Raumschiffs
void raumschiffZeichnen(int xPos, int yPos) {
translate(xPos, yPos); // Zeichnenursprung verschieben
fill(57, 63, 170);
noStroke();
arc(0, 0, 20, 60, PI, TWO_PI);
rect(-10, 0, 20, 10);
fill(183, 187, 242);
arc(0, -10, 10, 30, PI, TWO_PI);
fill(222, 58, 118);
arc(-10, 20, 10, 50, PI, PI+ HALF_PI);
arc(10, 20, 10, 50, PI+ HALF_PI, TWO_PI);
translate(-xPos, yPos); // Zeichnenursprung zurück verschieben
}
// Steuerung des Raumschiffs per Key-Ereignisse
void keyPressed() {
if (key == 's' || key == 'S') {
gestartet = true;
}
if (gestartet == true) {
if (keyCode == LEFT) {
xRaumschiff = xRaumschiff - schritt;
if (xRaumschiff < 0) {
xRaumschiff = width;
}
}
if (keyCode == RIGHT) {
xRaumschiff = xRaumschiff + schritt;
if (xRaumschiff > width) {
xRaumschiff = 0;
}
}
}
}
Der folgende Code erstellt untenstehende Grafik. Es fällt auf, dass im Code die line()-Anweisung wiederholt eingesetzt wird.
size(330, 100); background(230); smooth(); stroke(0,0,200); strokeWeight(6); line(10, 20, 60, 80); line(70, 20, 120, 80); line(130, 20, 180, 80); line(190, 20, 240, 80); line(250, 20, 300, 80);
Wiederholungen lassen sich oft mit Schleifen vereinfachen. Obiger Code kann wie folgt charakterisiert werden:
Für diese Anwendung eignet sich eine Zählerschleife, die sogenannte for-Schleife:
for (int i=10; i <= 250; i=i+60) {
line(i, 20, i+50, 80);
}
line()-Anweisungen durch die for-Schleife.for-Anweisung?Man kann alle Eigenschaften mit Ausnahme der 5 Wiederholungen erkennen. In der folgenden Variante lässt sich die Anzahl Wiederholungen besser erkennen, dafür andere Eigenschaften schlechter:
for (int i=0; i <5; i=i+1) {
line(10+i*60, 20, 10+i*60+50, 80);
}
Bei der Zählerschleife steht die Anzahl Wiederholungen zu Beginn der Schleife fest. Die Anweisung hat folgende Struktur: for(Initialisierung; Bedingung; Update). Konkret sieht die dreigliedrige Anweisung wie folgt aus:
for (int i=0; i <10; i=i+1) {
line(10+i*30, 20, 10+i*30, 80);
}
Die Zählervariable i wird deklariert und mit 0 initialisiert. Als Bedingung wird i muss kleiner 10 sein festgelegt. Und am Ende jedes Schleifendurchgangs wird i zu i + 1. Die Zählvariable wird also mit 0 startend hochgezählt über 1, 2, ... bis 9. Am Schluss wird sie gar auf 10 erhöht, wobei i dann die Bedingung nicht mehr erfüllt und der Programmlauf dem false-Pfad im Flussdiagramm folgt. D.h. die Schleife wird beendet (vgl. Abb.).
Die oben in Codeform präsentierte for-Schleife generiert folgende Grafik:
for-Schleife so, dass folgende zwei Varianten entstehen. Speichern Sie die einzelnen Sketches.
size(330, 100);
background(230);
smooth();
stroke(0,0,200);
strokeWeight(4);
for (int i=0; i <10; i=i+1) {
line(10+i*30, 20, 10+i*30+30, 80);
}
size(330, 100);
background(230);
smooth();
stroke(0,0,200);
strokeWeight(4);
for (int i=0; i <10; i=i+1) {
line(10+i*30, 20, 10+i*30+30, 50);
line(10+i*30+30, 50, 10+i*30, 80);
}
Festigen Sie die Anwendung der for-Schleife indem Sie folgende sechs Beispiele selber programmieren. Analysieren Sie dazu jede der 200*200 Pixel grossen Abbildungen:
for (int i=0; i<10; i=i+1) {
ellipse(100,100,i*20, i*20);
}
for (int i=0; i<10; i=i+1) {
ellipse(i*20+10, i*20+10, 20, 20);
}
for (int i=0; i<10; i=i+1) {
rect(i*20, 180-i*20, 20, 20);
}
for (int i=0; i<11; i=i+1) {
line(0, i*20, i*20, 200);
}
for (int i=0; i<11; i=i+1) {
line(0, i*20, 200, 200-i*20);
}
for (int i=0; i<21; i=i+1) {
line(0, 200-i*10, i*10, 0);
line(200, i*10, 200-i*10, 200);
}
Bei der while-Schleife ist zu Beginn unbekannt, wie oft sie durchlaufen wird. Da die Bedingung zu Beginn der Schleife steht, wird sie nie, einmal oder mehrmals durchlaufen.
float a = 1;
while(a < 100) {
ellipse(10+3*a,50,a,a);
a = a*1.2;
}
Bei der do while-Schleife ist zu Beginn unbekannt, wie oft sie durchlaufen wird. Da die Bedingung zum Schluss steht, wird sie mindestens einmal durchlaufen.
Die allgemeine Syntax ist:
int a = 1;
do {
a = a + 1;
} while (a < 13);
Eine sinnvolle Anwendung wäre beim euklidischen Algorithmus zur Berechnung des ggT (grösster gemeinsamer Teiler).
do while-Schleife und der Rest-Division %. Processing-Referenz zur Restdivision (Modulo-Division).Der ggT von a=252 und b=196 ist gleich 28.
int a = 252;
int b = 196;
int rest;
do {
rest = a % b;
a = b;
b = rest;
} while (rest > 0);
println("Der ggT ist gleich "+a);
int a = 252;
int b = 196;
int a1 = a;
int b1 = b;
int rest;
do {
rest = a % b;
a = b;
b = rest;
} while (rest > 0);
println("Der ggT von a=" + a1 + " und b=" + b1 +" ist gleich " + a);
Ein zweidimensionales Array wie abgebildet darzustellen, geht am einfachsten mit einer verschachtelten for-Schleife:
for(int i=0; i<3;i++) {
for(int j=0; j<3;j++) {
fill(230);
rect(i*s,j*s,s,s);
fill(0,0,200);
text(meinKoordinatenfeld[i][j],i*s+s/2,j*s+s/2);
}
}
Hinweis: verschachtelte for-Schleifen müssen unterschiedliche Zählvariabeln aufweisen. Im Beispiel sind dies i und j.
// Deklaration
int[][] meinKoordinatenfeld;
// Initialisierung & Zuweisung kombiniert
meinKoordinatenfeld = new int[][] {{1, 0, 2},{2, 2 , 0},{1, 0, 1}};
size(301,302);
float s = 100;
textAlign(CENTER,CENTER);
textSize(45);
stroke(0,0,200);
for(int i=0; i<3;i++) {
for(int j=0; j<3;j++) {
fill(230);
rect(i*s,j*s,s,s);
fill(0,0,200);
text(meinKoordinatenfeld[i][j],i*s+s/2,j*s+s/2);
}
}
Die folgende Darstellung ist mit zwei for-Schleifen realisiert. Beantworten Sie folgende Fragen:
for-Schleifen verschachtelt oder nicht? Argumentieren Sie.
size(660, 120);
background(230);
smooth();
noStroke();
fill(30,30,230,140);
for (int x = 0; x < width+45; x = x+40) {
ellipse(x, 0, 40, 40);
}
fill(230,30,30,140);
for (int y = 0; y < height+45; y = y+40) {
ellipse(0, y, 40, 40);
}
PS: Der Kreis oben links ist andersfarbig, weil zwei unterschiedliche Farben mit reduzierter Deckkraft übereinander liegen.
Verschachteln Sie die beiden for-Schleifen.
Programmieren Sie verschachtelte for-Schleifen so, dass folgende Darstellung entsteht. Tipps:
size(255, 255);
smooth();
stroke(70);
for (int x = 0; x < 51; x = x+1) {
for (int y = 0; y < 51; y = y+1) {
fill(x*5,30,y*5);
rect(x*5, y*5, 5, 5);
}
}
PS: Die Rot- und Blau-Anteile der Farbwerte errechnen sich je aus einer Zählvariabel, hier x*5 bzw. y*5. Der Grünanteil ist in der Musterlösung zufällig auf 30 fixiert.
Die if-Anweisung verzweigt den Programmablauf. Wenn eine Bedingung wahr (true) ist, so werden die folgenden Anweisungen ausgeführt, sonst (false) werden diese übersprungen.
Die allgemeine Schreibweise ist:
if (Bedingung) {
Anweisung 1;
Anweisung 2;
...
Anweisung n;
}
Beobachten Sie obigen Sketch und ergänzen Sie folgenden Satz:
Wenn ........., dann ......... .
Richtig! Wenn die x-Koordinate des Pacmans grösser als die Fensterbreite ist, dann wir sie auf 0 gesetzt. Die Fensterbreite ist in der Systemvariable width gespeichert.
if (xPos > width) {
xPos = 0;
}
Programmieren Sie ebenfalls eine Form, die nach rechts wandert, und bevor sie rechts aus dem Fenster verschwindet an den linken Rand gesetzt wird.
int xPos = 0;
int geschwindigkeit = 5;
void setup() {
size(660,100);
smooth();
}
void draw() {
background(230);
fill(0,0,200);
xPos = xPos + geschwindigkeit;
if (xPos > width) {
xPos = 0;
}
arc(xPos, height/2, 70, 70, PI/8, TWO_PI - PI/8);
}
Die if-else-Anweisung ermöglicht eine Wenn-Dann-Sonst Aussage. Wenn die Bedingung nicht erfüllt ist, werden alternative Anweisungen durchlaufen.
Die allgemeine Schreibweise ist:
if (Bedingung) {
Anweisung 1;
...
Anweisung n;
}
else {
Anweisung 1;
...
Anweisung n;
}
Bewegen Sie die Maus über obigem Sketch und ergänzen Sie folgenden Satz:
Wenn ........., dann ........., sonst ......... .
Der Pacman wird abhängig von der y-Koordinaten der Maus gezeichnet. Ist die Systemvariable mouseY grösser als die Häfte der height-Systemvariable (Fensterhöhe), so schaut der Pacman nach unten, sonst nach oben.
Codeausschnitt:
if (mouseY > height/2) {
arc(xPos, height/2, 70, 70, HALF_PI + PI/8, TWO_PI + 3*PI/8);
}
else {
arc(xPos, height/2, 70, 70, PI + 5*PI/8, 3*PI + 3*PI/8);
}
Setzen Sie diese Codezeilen in das voherige if-Beispiel ein.
int xPos = 0;
int geschwindigkeit = 5;
void setup() {
size(660, 100);
smooth();
}
void draw() {
background(230);
fill(0, 0, 200);
xPos = xPos + geschwindigkeit;
if (xPos > width) {
xPos = 0;
}
if (mouseY > height/2) {
arc(xPos, height/2, 70, 70, HALF_PI + PI/8, TWO_PI + 3*PI/8);
}
else {
arc(xPos, height/2, 70, 70, PI + 5*PI/8, 3*PI + 3*PI/8);
}
}
Die if-else-if-Anweisung ermöglicht mehrere aufeinanderfolgende Bedingungen. Ist eine Bedingung wahr, werden die zugeordneten Anweisungend durchlaufen und anschliessend die if-else-if-Anweisung beendet. Nur bei false wird die nächste Bedingung getestet.
Die allgemeine Schreibweise ist:
if (Bedingung) {
Anweisung 1;
...
}
else if (Bedingung) {
Anweisung 1;
...
}
else if (Bedingung) {
Anweisung 1;
...
}
else {
Anweisung 1;
...
}
Es können beliebig viele else if Blöcke eingefügt werden.
Bewegen Sie die Maus über dem obigen Sketch in die drei Felder. Formulieren Sie nach dem Muster:
Wenn ........., dann ........., sonst falls ......... , sonst ......... .
Wenn die Maus im ersten Drittel liegt, so bewegt sich der Pacmann nach links, sonst falls die Maus im mittleren Drittel liegt, steht er still und sonst bewegt sich der Pacman nach rechts.
Codeausschnitt:
if (mouseX < 220) {
geschwindigkeit = -5;
}
else if (mouseX < 440) {
geschwindigkeit = 0;
}
else {
geschwindigkeit = 5;
}
Setzen Sie diesen Codeauschnitt in Ihren eigenen Sketch ein. So dass sich Ihre Form analog verhält. Variieren Sie die Grenzwerte.
int xPos = 0;
int geschwindigkeit = 5;
void setup() {
size(660, 100);
smooth();
}
void draw() {
background(230);
fill(0, 0, 200);
if (mouseX < 220) {
geschwindigkeit = -5;
}
else if (mouseX < 440) {
geschwindigkeit = 0;
}
else {
geschwindigkeit = 5;
}
xPos = xPos + geschwindigkeit;
if (xPos > width) {
xPos = 0;
}
if (xPos < 0) {
xPos = width;
}
arc(xPos, height/2, 70, 70, PI/8, TWO_PI - PI/8);
}
Die switch-Anweisung ermöglicht eine Mehrfachverzweigung abhängig vom Wert einer Variablen. Der Datentyp dieser Variable kann byte, char, short oder int sein.
Die allgemeine Schreibweise ist:
switch (Variablenname) {
case KONSTANTE1:
Anweisung 1;
...
Anweisung n;
break;
case KONSTANTE2:
Anweisung 1;
...
Anweisung n;
break;
default:
Anweisung 1;
...
Anweisung n;
break;
}
Es können beliebig viele case-Abschnitte eingefügt werden. Der default-Abschnitt ist nicht zwingend.
Bewegen Sie die Maus über die Felder des obigen Sketch. Formulieren Sie, wie der Pacman reagiert.
Je weiter rechts das berührte Feld, desto schneller bewegt sich der Pacman.
Im Code wird mit einer Division der x-Koordinate durch die Felbreite ermittelt, in welchem Feld die Maus sich befindet. Das Resultat der Division wird mit der int()-Funktion in eine Ganzzahl vom typ int umgerechnet. Das Ergebnis ist im Bereich [0..5] und wird in der Variable feldNr vom Datentyp int gespeichert. Diese Variable wird mit einer switch-Anweisung ausgewertet:
feldNr = int(mouseX / feldBreite);
switch (feldNr) {
case 0:
geschwindigkeit = 1;
break;
case 1:
geschwindigkeit = 3;
break;
case 2:
geschwindigkeit = 5;
break;
case 3:
geschwindigkeit = 7;
break;
case 4:
geschwindigkeit = 9;
break;
case 5:
geschwindigkeit = 11;
break;
default:
geschwindigkeit = 0;
}
Bauen Sie eine ähnliche Geschwindigkeits-Steuerung in Ihren Sketch ein.
int xPos = 0;
int geschwindigkeit = 5;
int feldBreite = 110;
int feldNr;
void setup() {
size(660, 100);
smooth();
}
void draw() {
background(230);
fill(0, 0, 200);
feldNr = int(mouseX / feldBreite);
switch (feldNr) {
case 0:
geschwindigkeit = 1;
break;
case 1:
geschwindigkeit = 3;
break;
case 2:
geschwindigkeit = 5;
break;
case 3:
geschwindigkeit = 7;
break;
case 4:
geschwindigkeit = 9;
break;
case 5:
geschwindigkeit = 11;
break;
default:
geschwindigkeit = 0;
}
xPos = xPos + geschwindigkeit;
if (xPos > width) {
xPos = 0;
}
arc(xPos, height/2, 70, 70, PI/8, TWO_PI - PI/8);
}
Schreiben Sie einen Sketch nach folgendem Vorbild:
Hinweise:
color gespeichert.i berechnet.if-Verzweigung wird entschieden, ob die Farbe aus dem Array oder die rote Standardfarbe zur Anwendung kommt (s. Zeilen 24 bis 29).int feldSeite= 60;
int anzFelder = 11;
int feldNr;
color[] feldFarben;
void setup() {
feldFarben = new color[anzFelder];
for (int i=0; i < anzFelder; i=i+1) {
feldFarben[i] = color(255-i*10, 200, 42);
}
size(660, 120);
smooth();
}
void draw() {
background(230);
stroke(210);
feldNr = int(mouseX / feldSeite);
for (int i=0; i < anzFelder; i=i+1) {
fill(feldFarben[i]);
rect(i*feldSeite, 0, feldSeite, feldSeite);
}
if (mouseY < height/2) {
fill(feldFarben[feldNr]);
}
else {
fill(180, 40, 40);
}
rect(0, 60, width, 60);
}