OOP

In der heutigen Einheit haben wir mit objektorientierter Programmierung (OOP) und Animation zwei große Themenbereiche.

Die Grundbausteine von OOP, sprich Objekte, habt ihr bereits kennen gelernt. Auch sind Euch Variablen und Funktionen ein Begriff.

OOP - für was?

Wie bereits das Verteilen und Ausgliedern von Code auf einzelne Funktionen und Dateien ist das größte Ziel von OOP (im Rahmen des Kurses) die bessere Strukturierung und Vereinfachung von Programmieranweisungen.

Wir wollen Funktionsaufrufe zusammenfassen und für eine bessere Lesbarkeit auslagern. Das visuelle Ergebnis bleibt das gleiche, aber wir finden uns später besser in unseren Code-Bibliotheken zurecht, somit steigert es die Wiederverwendbarkeit und Wartbarkeit.

Aufbau einer Klasse

Ein wichtiger Bestandteil von OOP ist das Erstellen von eigenen Klassen, die als sogenannter Bauplan dienen. Eine Klasse besteht aus einer Hülle, einem Konstruktor und je nach Bedarf aus Eigenschaften und Methoden.

Als Beispiel hierfür wollen wir uns einen Fisch vorstellen. Der Fisch hat die Eigenschaften location und speed. Die Eigenschaft location hält die aktuelle Position in einer Instanz vom Typ PVector für x und y fest. Die Eigenschaft speed beinhaltet die Geschwindigkeit, die pro Frame auf die Eigenschaft location addiert wird. Außerdem kann man im Bauplan Tätigkeiten für den Fisch definieren. Ein Beispiel hierfür wäre die Methode move().

Eine Klasse, also der Bauplan, könnte somit wie folgt aussehen:

Beispiel:

// Definition der Hülle
class Fish
{
 
 PVector location;
 PVector speed;
 
 // Konstruktor -> wird aufgerufen, 
 // wenn eine Instanz vom Fish erstellt wird
 Fish()
 {
 }
 
 void move()
 {
 }
 
}

Konstruktor

Sobald man von der Klasse eine neue Instanz erstellt, was man sich als existierendes Objekt auf Basis des Bauplanes vorstellen kann, wird durch den Aufruf new MyClass(), der Konstruktor innerhalb dieser Klasse aufgerufen. Der Konstruktor ist somit der Startpunkt, in dem man alle initialen Eigenschaften definieren sollte.

Eigenschaften / Variablen

Eigenschaften sind nichts anderes als die bisher bekannten Variablen. Sie definieren ein Objekt im Rahmen der vorgegebenen Möglichkeiten durch den Bauplan. Somit können Eigenschaften z.B. das visuelle Erscheinungsbild eines Objektes auf Datenebene repräsentieren. Wichtig ist dabei, dass Objekte nicht zwingend visuelle Einheiten sind, sie können auch reine Datencontainer sein. In der letzten Woche hatten wir z.B. Instanzen vom Typ PVector erstellt, die erst durch andere Methoden visuell repräsentiert wurden.

Funktionen / Methoden

Neben Eigenschaften kann eine Klasse auch Methoden zur Verfügung stellen, mit denen man von außen das Verhalten und Aussehen von Instanzen manipulieren kann. Der Fisch kann dabei Methoden haben, um sich zu bewegen. Methoden werden in der Regel verwendet, um von außen die Instanz zu verändern. Somit greift man eher selten direkt auf Eigenschaften zu, sondern stellt Methoden zur Verfügung, die dann wiederum Eigenschaften verändern.

Zum Beispiel ruft man die Methode move() auf und verändert dann intern die Eigenschaft location, um das Objekt (die Instanz einer Klasse) zu bewegen.

Sichtbarkeit von Eigenschaften und Methoden

Weil die Frage während der Vorlesung aufkam: man kann die Sichtbarkeit von Methoden nach außen hin steuern. Dieses Thema werden wir aber erst in einer der folgenden Einheiten besprechen.

Das Aquarium befüllen

Die Hauptdatei für unser Beispiel ist die aquarium.pde, die als Container bzw. als Raum für unsere Fische dient. In dieser Datei erstellen wir erst einmal 50 Fische für das Aquarium.

Beispiel:

void createFishList()
{
 fishList = new Fish[ fishAmount ];
 
 int count = 0;
 int countMax = fishAmount;
 
 while( count < countMax )
 {    
   fishList[ count ] = new Fish();
   count++;     
 }
}

Wichtig dabei ist aber, dass das Aussehen der Fische in der Klasse Fish definiert wird. Die ganze Komplexität des Fisches ist somit in der Klasse und im Aquarium erstellt man lediglich Instanzen davon.

Bewegung der Fische

Der erste Schritt, um Leben in das Aquarium zu bekommen ist, dass man eine einfache Bewegung für die Fische programmiert. Jeder Fisch besitzt eine Methode move(). In dieser Methode wird auf die aktuelle Position, die Eigenschaft location, die Geschwindigkeit, also die Eigenschaft speed, addiert.

Durch die Erzeugung von zufälligen Geschwindigkeiten zwischen 0 und 1 in der Methode setupProperties() bewegen sich die Fische unterschiedlich schnell.

Um die neu berechnete Position auch visuell zu sehen, muss am Ende der move() Methode auch die Optik über die Methode drawLook() aktualisiert werden.

Überprüfung der Bewegung

Damit die Fische auch im Aquarium bleiben, muss man konstant die Position der Fische überprüfen, also ob sie sich noch im definierten Rahmen befinden. Sollten sie auf eine Seitenwand stoßen, tauscht man das Vorzeichen ihrer aktuellen Geschwindigkeit, um ihre Richtung zu verändern.

Die move()-Methode sieht dann wie folgt aus:

void move()
{
 
 location.x = location.x + speed.x;
 location.y = location.y + speed.y;
 
 if( location.x > width || location.x < 0 )
 {
   speed.x = speed.x * - 1; 
 }
 
 if( location.y > height || location.y < 0 )
 {
   speed.y = speed.y * - 1; 
 }
 
 // Nach Bewegung, Optik aktualisieren
 drawLook();
 
}

Neu ist hierbei die Verknüpfung von if-Abfrage. Mit dem Zeichen || kann man abfragen, ob eine Abfrage wahr ist. Hingegen überprüft man mit && ob alle verknüpften Abfragen wahr sind.

Hausaufgabe

Erstellt zwei Arbeiten, die auf dem Aquarium-Beispiel basieren. Ihr seid dabei in der Gestaltung von Raum und Inhalt komplett frei.

Der dritte Teil der Hausaufgabe ist, dass ihr innerhalb der nächsten zwei Wochen Skizzen und Ideen für eure Abschlussarbeit sammelt, die ihr vor der Umsetzungsphase im Kurs vorstellen sollt.

Informationen zum Dateiformat, der Bezeichnung und zum Upload der Dateien sind unter dem Punkt Prüfungsleistung zu finden.

Die Beispiele der Woche können hier herunter geladen werden.