Creative Coding

btk

Till Nagel

Modularität – Woche 7

Aufgaben

G1: drawCircles()

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

Erstelle 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.

Projekt 1: Kontrast

Erstelle einen Sketch zum Thema "Kontrast". Deine Grafik oder dein interaktives Programm soll den Gegensatz zweier Ideen vermitteln. Zum Beispiel: - Hase und Igel (schnell und langsam) - Tag und Nacht (hell und dunkel) - Krieg und Frieden (aggresiv und sanft) - Regen und Sonne (dunkel/naß und hell/trocken) - Im Auge des Sturms (ruhig und wild)

Dokumentation

Schreibt als Kommentar am Anfang in euren Code:

  • Vollständige Namen aller Gruppenmitglieder
  • Projektbeschreibung: Was ist die Idee/der Hintergrund? Was macht das Programm?
  • Eventuelle Schwierigkeiten, bzw. Unvollständigkeiten in der Umsetzung

Style

Achtet darauf, dass ihr den Code formattiert, sinnvolle, aussagekräftige Variablennamen verwendet und – vor allem – gut kommentiert. (Siehe auch den Style Guide)

Abgabe

Die Projekte müssen im Intranet der BTK eingereicht werden. Archiviert euren Sketch (Processing Menü > Tools > Archive Sketch) und ladet diese Zip-Datei bei der entsprechenden Aufgabe hoch.

Letzter Abgabetermin ist Donnerstag, 07.06.07 um 23:59 Uhr.


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.

Creative Commons Lizenz: Namensnennung-NichtKommerziell-Weitergabe unter gleichen Bedingungen 2.0 (Deutschland)

© 2007 Till Nagel, All rights reserved – Alle Rechte vorbehalten.