Modularität – Woche 7
Aufgaben
G1: drawCircles()
Lösung
Programmiere eine Funktion drawCircles()
, die drei konzentrische Kreise an die Mausposition zeichnet und rufe diese Funktion in draw() auf.
(Die Funktion drawCircles()
hat weder Parameter noch einen Rückgabewert)

Erweitere die Funktion dann so, dass sie zwei Fließkomma-Parameter für die x und für die y-Position übergeben bekommt.
Ruf sie dann einmal mit drawCircles(mouseX, mouseY)
und einmal mit drawCircles(100, 100)
auf.
G2: Stars & Stripes
LösungErstelle eine dynamische Form, die "Stars & Stripes" thematisch umsetzt.
Fang an, in dem du eine Funktion drawStar(x, y)
schreibst, die einen einzelnen Stern zeichnet.
Schau dafür in der Processing-Referenz die Zeichenanweisung triangle()
an.

Beispielhafte Umsetzung

Variante: Variiere die Farben interaktiv.
Modularität & Wiederverwendbarkeit
Functions break large computing tasks into smaller ones, and enable people to build on what others have done instead of starting over from scratch. Appropriate functions hide details of operation from parts of the program that don't need to know about them, thus clarifying the whole, and easing the pain of making changes.Kernighan und Ritchie
Um diese Vorteile zu erlangen, so dass Programme modular und wieder verwendbar werden, ist eine Aufteilung von Programmabschnitten mit Hilfe von Funktionen sinnvoll. Neben dem, dass uns Modularität dazu bringt, weniger Code schreiben zu müssen, hilft es
- Wiederholungen zu vermeiden
- Komplexe Probleme in einfachere, kleinere aufzuteilen
- Struktur und Übersichtlichkeit in den Code bringen und dadurch Lesbarkeit zu erhöhen
- eigenen Code und den von Anderen wieder zu verwenden
Funktionen 2
Funktionen sind ein wichtiges Mittel zur Modularisierung, indem oft benötigter Code in einer Funktion zusammengefasst wird und über
den Funktionsnamen wiederholt aufgerufen werden kann. So kann die Funktion beliebig oft wieder eingesetzt werden. (Siehe hierzu auch
nochmal Funktionen 1)
Eine Funktion besteht aus vier Teilen:
- Name - der Funktionsname
- Code, der in der Funktion zusammen gefasst wurde (ein Programmblock, etwa mit Anweisungen und Ausdrücken)
- Parameter die die Funktion beeinflussen, und schließlich einem
- Rückgabewert, der von der Funktion zurück gegeben wird.
Funktion definieren
Nun können wir nicht nur Processings interne Funktionen benutzen, sondern auch eigene schreiben. Dazu muss eine Funktion definiert werden — ähnlich wie eine Variable. Dies geschieht durch die Angabe der genannten vier Teile; in folgender Reihenfolge: Rückgabewert Name(Parameter) { Code }, also beispielsweise:
In der ersten Zeile steht zunächst void
. Wenn eine Funktion keinen Wert zurückgeben soll, dann muss statt dessen void
(englisch für "nichts, leer") angegeben werden.
Als nächstes steht dort sayHello
, der Name der Funktion. Wir können hier beliebige Namen verwenden, sollten aber — wie auch bei Variablen — "sprechende", d.h. sinnvoll beschreibende Namen einsetzen.
In den runden Klammern steht nichts, was bedeutet, dass diese Funktion parameterlos ist.
Und diese Art einer Funktion haben wir bereits häufig angewendet, nämlich wenn wir die beiden (Spezial-)Funktionen setup()
und draw()
definierten.
Alle Anweisungen innerhalb der geschweiften Klammern gehören zu dieser Funktionen und werden ausgeführt, wenn die Funktion aufgerufen wird.
Ein Funktionsaufruf geschieht, in dem der Funktionsname mit Klammern im Code geschrieben wird. Alle Anweisungen, wie etwa
point(100, 200);
sind solche Aufrufe. Die oben stehende Funktion ruft man also mit sayHello();
auf.
Parameter
Um die konkrete Ausführung einer Funktion zu beeinflussen, können wir Parameter verwenden. So wie wir durch Parameter beeinflussen,
wo eine Linie gezeichnet wird, so können wir auch unsere eigenen Funktionen parametrisieren.
Beim Aufrufen der Linienfunktion line(10, 10, 200, 200);
geben wir die vier Werte als Parameter mit, die die Position der Linie bestimmen.
(vgl. nochmal line()
)
Wieder sagen wir mit void
als Erstes, dass es keinen Rückgabewert hat.
Dann steht dort der Funktionsname drawEyes
.
Und schließlich haben wir etwas zwischen den Klammern stehen. Dies sind die Parameter (auch Argumente genannt). Von den Parametern
können wir beliebig viele für eine Funktion definieren; wichtig ist, dass diese Parameter innerhalb der Funktion ganz normale lokale Variablen mit dem
angegebenen Datentyp sind. (Wir deklarieren die Parameter-Variablen also direkt in der ersten Funktionszeile.)
Rückgabewert
Funktionen können Rückgabe zurück geben, damit in der Funktion berechnete Werte weiter verwendet werden können (siehe auch Verwendung von Rückgabewerten).
Dies geschieht, in dem wir zum Einen in der Funktionsdefinition statt void
einen Datentyp (wie float
) angeben, und zum Anderen mit der Anweisung return
einen Wert vom definierten Datentyp zurück geben.
In diesem Beispiel wird nun ein Rückgabewert definiert, und zwar vom Typ int
. Die Funktion heisst add
und nimmt die beiden int-Parameter
a und b entgegen. Diese werden in dem Ausdruck addiert und in der lokalen Variable sum
gespeichert, deren Wert durch return sum
zurück gegeben wird.
Genau so sind auch die bisher bekannten Processing-Funktionen intern programmiert, zum Beispiel random()
, sqr()
, oder min()
.
Um dies zu verdeutlichen folgt hier die Funktionsdefinition der (bereits vorhandenen) Funktion min()
.
mousePressed() & keyPressed()
Neben den beiden boolean
-Variablen mousePressed
und keyPressed
gibt es in Processing
auch noch zwei gleichlautende Funktionen. Während die Variablen von Processing (wie mouseX
und mouseY
)
ständig den aktuellen Wert besitzen, also ob eine Taste gedrückt ist, werden die Funktionen
genau in dem Moment aufgerufen, in dem der Nutzer eine Taste drückt.
Diese Funktionen werden von Processing einmal aufgerufen. In dem obigen Beispiel wird die Strichfarbe also nur einmal pro Mausklick geändert, im Gegensatz zu dem folgenden, bei dem sich die Farbe solange ändert, solange man die Maustaste gedrückt hält.
Desweiteren gibt es die beiden Funktionen mouseReleased()
und keyReleased()
, die aufgerufen werden,
wenn eine Taste losgelassen wird. Mit Hilfe der Funktion mousePressed()
können wir also erkennen, wann der Nutzer
eine Maustaste drückt, und mit mouseReleased()
, wann er sie wieder loslässt.