Hi,

ja, heute geht's um Klassen. Komplizierte Angelegenheit für manche, dennoch, wenn man das Prinzip einmal verstanden hat ist es nicht nur einfach sondern es erleichtert vieles und bietet viel mehr Möglichkeiten wirklich etwas mit Processing anzufangen. Du kannst dir zuallererst eine Übersicht über dieses Thema verschaffen wenn du dir die beiden Wikipedia-Artikel zu Klassen und Objektorientierter Programmierung (OOP) durchliest. Klassen sind auch im Zusammenhang mit Arrays eine praktische Sache.

Sehen wir uns hierzu folgendes Beispielprojekt an:

<pre> <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>setup</b></span>() { <span style="color: #CC6600;">smooth</span>(); <span style="color: #CC6600;">size</span>(300, 300); <span style="color: #CC6600;">background</span>(#000000); ax = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">width</span> - 10)); ay = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">height</span> - 10)); bx = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">width</span> - 10)); by = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">height</span> - 10)); cx = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">width</span> - 10)); cy = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(10, <span style="color: #006699;">height</span> - 10)); } <span style="color: #CC6600;">int</span> ax, ay, bx, by, cx, cy; <span style="color: #CC6600;">int</span> adx = 1; <span style="color: #CC6600;">int</span> ady = 1; <span style="color: #CC6600;">int</span> bdx = 1; <span style="color: #CC6600;">int</span> bdy = 1; <span style="color: #CC6600;">int</span> cdx = 1; <span style="color: #CC6600;">int</span> cdy = 1; <span style="color: #CC6600;">int</span> r = 10; <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>draw</b></span>() { <span style="color: #CC6600;">background</span>(#000000); ax+=adx; ay+=ady; bx+=bdx; by+=bdy; cx+=cdx; cy+=cdy; <span style="color: #CC6600;">if</span>(ax>=<span style="color: #006699;">width</span>-r||ax<=r){adx*=-1;} <span style="color: #CC6600;">if</span>(ay>=<span style="color: #006699;">height</span>-r||ay<=r){ady*=-1;} <span style="color: #CC6600;">if</span>(bx>=<span style="color: #006699;">width</span>-r||bx<=r){bdx*=-1;} <span style="color: #CC6600;">if</span>(by>=<span style="color: #006699;">height</span>-r||by<=r){bdy*=-1;} <span style="color: #CC6600;">if</span>(cx>=<span style="color: #006699;">width</span>-r||cx<=r){cdx*=-1;} <span style="color: #CC6600;">if</span>(cy>=<span style="color: #006699;">height</span>-r||cy<=r){cdy*=-1;} <span style="color: #CC6600;">fill</span>(255); <span style="color: #CC6600;">noStroke</span>(); <span style="color: #CC6600;">ellipse</span>(ax, ay, r, r); <span style="color: #CC6600;">ellipse</span>(bx, by, r, r); <span style="color: #CC6600;">ellipse</span>(cx, cy, r, r); } </pre>

Es funktioniert. Abgesehen davon ... schau dir mal an wieviel Schreibarbeit das ist. Stell dir vor du würdest hier nun 10 Kugeln haben wollen, dann bräuchtest du für die Richtung noch 7 weitere Variablen, und 14 weitere für die Koordinaten. Ich würde da sicher bald den Überblick verlieren. Und genau dafür sind Klassen da, damit soetwas nicht passiert, bzw. gar nicht erst nötig ist. Eine Klasse zu erstellen ist nichts anderes als die Definition und Funktionalität des Objektes in einen eigenen Bereich auszulagern. Dieses Objekt wird dann im Projekt instanziiert, beliebig oft wenn man es möchte.

Um die Funktionalität und die Eigenschaften dieser Kugeln in eine eigene Klasse auszulagern müssen wir erst einmal eine erstellen. Das geht entweder direkt im Code oder du legst für die neue Klasse gleichzeitig auch eine neue .pde-Datei an. Vorteilhafter ist es wenn man es in eine neue Datei packt, allein schon wegen der Übersichtlichkeit.

[caption id="attachment_2172" align="aligncenter" width="300" caption="Klasse erstellen - so wird's gemacht"]Klasse erstellen - so wird's gemacht[/caption]

Eine Klasse wird mit "class" eingeleitet, allerdings kommen dahinter keine Klammern, da an eine Klasse direkt keine Werte übergeben werden. Warum? Weil eine Klasse keinen Rückgabewert (return) hat, auf die Variablen und Eigenschaften der Klasse greifen wir über Klassenname.Variable zu, und das geht erst nachdem wir eine Instanz der Klasse im Projekt instanziiert haben -> Objektinstanz.

Schreiben wir also alles was wir benötigen um dasselbe Ergebnis zu bekommen, nur eben diesmal ausgelagert in eine Klasse. Wir brauchen wieder die X/Y Koordinaten und die Richtung, dann noch eine Funktion für die Kollision. So sieht die Klasse nun aus:

<pre> <span style="color: #CC6600;">class</span> ball { <span style="color: #CC6600;">int</span> posX, posY; <span style="color: #CC6600;">int</span> dx, dy; <span style="color: #CC6600;">int</span> kugel_radius = 25; <span style="color: #CC6600;">void</span> einstellungen() { dx = 1; dy = 1; posX = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(kugel_radius, <span style="color: #006699;">width</span> - kugel_radius)); posY = <span style="color: #CC6600;">int</span>(<span style="color: #CC6600;">random</span>(kugel_radius, <span style="color: #006699;">height</span> - kugel_radius)); } <span style="color: #CC6600;">void</span> zeige_kugel() { <span style="color: #CC6600;">fill</span>(#FFFFFF); <span style="color: #CC6600;">noStroke</span>(); <span style="color: #CC6600;">ellipse</span>(posX, posY, kugel_radius * 2, kugel_radius * 2); } <span style="color: #CC6600;">void</span> kollision() { <span style="color: #CC6600;">if</span>(posX >= <span style="color: #006699;">width</span> - kugel_radius || posX <= kugel_radius) { dx *= -1; } <span style="color: #CC6600;">if</span>(posY >= <span style="color: #006699;">width</span> - kugel_radius || posY <= kugel_radius) { dy *= -1; } posX += dx; posY += dy; } } </pre>

Du siehst, Funktionalität, Kollision und Anzeige der ellipse sind allesamt eingestellt. Die Funktion einstellungen() ist nur dafür da um die Startparameter festzulegen, kann man aber auch gleich bei der Deklaration machen. Daher wird später diese Funktion auch nur einmal aufgerufen, und zwar in void setup().

Schön, damit können wir kaum was anfangen, schließlich wird in Processing void setup() und void draw() ausgeführt, und dort ist noch keine Instanz der Klasse erstellt worden. Folglich wird also gar nichts passieren.

Wir wollen aber ja, dass was passiert. Die Klasse ist bei der Instanziierung selbst Datentyp mit dem das Objekt instanziiert wird. Das heißt, die Variable die erstellt wird ist vom Typ ball (zumindest hab Ich die Klasse bei mir so genannt). Eine Zahl ist vom Typ int oder float, wir deklarieren also int variable = 12; Bei der instanziierung ist es beinahe genauso, wir schreiben

<pre> ball balls; </pre>

Was die Deklaration(bei normalen Variablen) von einer Instanziierung unterscheidet ist das Schlüsselwort new. Erst dadurch wird das deklarierte balls auch Instanz der Klasse. Die Deklaration erfolgte global, die Instanziierung möchte Ich aber lieber in void setup() schreiben:

<pre> balls = <span style="color: #CC6600;">new</span> ball(); </pre>

Jetzt haben wir alles was wir brauchen. Ich habe die Instanz der Klasse ball einfach balls genannt. Nun können wir über Klassenname.Funktionsname einfach die Funktionen aus Klasse ball aufrufen. Funktion einstellungen() rufen wir in void setup() auf, den Rest in void draw().

Der komplette Code:

<pre> <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>setup</b></span>() { <span style="color: #CC6600;">smooth</span>(); <span style="color: #CC6600;">size</span>(300, 300); <span style="color: #CC6600;">background</span>(#000000); balls = <span style="color: #CC6600;">new</span> ball(); balls.einstellungen(); } ball balls; <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>draw</b></span>() { <span style="color: #CC6600;">background</span>(#000000); balls.zeige_kugel(); balls.kollision(); } </pre>

So, das war's, führe den Code bei dir aus und schau was passiert :-)
Das mit den Klassen ist eine tolle Sache, aber was habe Ich vorhin gesagt? Sie ergeben erst in Verbindung mit Arrays richtig Sinn. Arrays haben wir im letzten Artikel behandelt. Und wie können wir das hier nutzen? Nun, ganz einfach, wir machen aus balls ein Array (die Kreise werde Ich im nächsten Schritt etwas kleiner gestalten). So können wir soviele Bälle durchs Fenster fliegen lassen wie wir möchten, und müssen dabei alles nur ein einziges mal schreiben.

Die Klasse ball bleibt dieselbe, an dieser ändert sich ja nicht. Nur in unserem Hauptfenster ändert sich die deklaration geringfügig. Wir schreiben also die Deklaration in ein Array um, in void setup() müssen wir anschließend in einer Schleife das Array durchgehen und jedes Objekt instanziieren.

Wenn jeder Wert im Array (Objektinstanzen) instanziiert wurde, kann jederzeit eine Funktion der Klasse ball über balls[index].funktionsname() und jede Variable über balls[index].variable geändert werden. So können beispielsweise Zufallswerte für Geschwindigkeit und Farbe einzelner Kugeln festgelegt werden.

<pre> <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>setup</b></span>() { <span style="color: #CC6600;">smooth</span>(); <span style="color: #CC6600;">size</span>(500, 500); <span style="color: #CC6600;">background</span>(#000000); <span style="color: #CC6600;">for</span> (<span style="color: #CC6600;">int</span> i = 0; i < balls.<span style="color: #CC6600;">length</span>; i++) { balls[i] = <span style="color: #CC6600;">new</span> ball(); balls[i].einstellungen(); } } ball[] balls = <span style="color: #CC6600;">new</span> ball[20]; <span style="color: #CC6600;">void</span> <span style="color: #CC6600;"><b>draw</b></span>() { <span style="color: #CC6600;">background</span>(#000000); <span style="color: #CC6600;">for</span> (<span style="color: #CC6600;">int</span> i = 0; i < balls.<span style="color: #CC6600;">length</span>; i++) { balls[i].zeige_kugel(); balls[i].kollision(); } } </pre>

So einfach geht das. Mit balls[i] können wir nun auf alle Variablen, Funktionen und Eigenschaften der Klasse ball zugreifen. Wir haben in dem Beispiel 20 mal eine Objektinstanz der Klasse ball erstellt die alle aus dem Array heraus über balls[index] angesprochen werden können, so kann zum Beispiel die 3 Kugel vergrößert werden wenn wir schreiben balls[2].kugel_radius = 20; (Index 2 = dritte Kugel, da ja index 0 = 1. Kugel, index 1 = 2. Kugel, index 2 = 3. Kugel etc..).

Du siehst, mit Klassen zu arbeiten macht Spaß und es lassen sich vielerlei Ergebnisse praktischer realisieren als ohne. Du musst die Funktionalität eines Objektes (wie hier beispielsweise die Bewegung und das abprallen an den Wänden etc..) nur einmal schreiben, die Klasse ist somit ein Programm für sich. Und über das Hauptprogramm kannst du Objektinstanzen der Klasse erstellen und beliebig viele Objekte erzeugen.

Wir werden in den nächsten Projekten noch viel mit Klassen umsetzen und herumexperimentieren. Versuche zur Übung doch einmal, 5 Rechtecke mit Füllfarbe deiner Wahl irgendwo auf dem Fenster zu platzieren (sie sollen sich nicht bewegen). Schreibe dazu dann eine Funktion mit der du ein Rechteck mit Mausklick nehmen und per Drag&Drop an eine andere Stelle platzieren kannst. Auch immer gut zum nachforschen sind die Samples die Processing von sich aus mitbringt, diese kannst du im Menü über "File->Examples..." erreichen. Lade dir ein paar Projekte hieraus und schau an wie sie funktionieren, wie das Ergebnis aussieht und versuch das nach eigenem ermessen ohne nachschauen im Quellcode umzusetzen, mir persönlich macht das Spaß, man kommt automatisch auf neue Ideen die man umsetzen möchte und verliert so auch nicht den Spaß wenn mal was nicht gleich so klappt wie man's gern hätte.

Bis demnächst Marius