Greenfoot: Einführung
Basierend auf dem Greenfoot Tutorial von Michael Kölling (Deutsche Übersetzung: Claus Eikemeier); angepasst von Nicolas Ruh und Dieter Koch.
MATERIALIEN
Um mit Greenfoot arbeiten zu können, sollte man zuerst seine Benutzeroberfläche kennen. Danach lässt es sich gut damit programmieren.
A) Die Benutzeroberfläche
1. Ein Greenfoot-Projekt öffnen
Laden Sie das Kara-Szenario von hier herunter: Kara.zip
Speichern Sie den Zip-Ordner auf Ihrem Home-Laufwerk (nicht in einem Cloud-Speicher) und entpacken Sie ihn: Rechtsklick → Alle extrahieren… (oder falls Sie 7-Zip installiert haben: Rechtsklick → 7-Zip → Hier entpacken).
Öffnen Sie das Szenario, indem Sie im Ordner „Kara“ auf die Datei doppelklicken.
Das System sollte dann ähnlich wie in obenstehender Abbildung aussehen. (Normalerweise sollten zu dem Zeitpunkt noch keine Blätter und aber genau ein Käfer in der „Welt“ existieren.)
Das grosse hinterlegte Gitter, welches den grössten Teil des Fensters überdeckt, stellt „die Welt“ (World) dar. Da wir es in diesem Projektbeispiel mit Marienkäfern namens „Kara“ zu tun haben, sieht man hier die „KaraWelt“ (KaraWorld).
Rechts vom Fenster sieht man die Klassen-Anzeige. Hier werden alle Java-Klassen dargestellt, die am Projekt beteiligt sind. Die Klassen „World“ (Welt) und „Actor“ (Akteur) sind in jedem Projekt vorhanden – sie werden automatisch vom Greenfoot-System angelegt und angezeigt. Alle anderen (Unter-)Klassen gehören speziell zum Kara-Projekt, und sind daher in anderen Projekten in der Regel auch anders (andere Anzahl, Struktur und Bezeichnung).
Unter der Welt sind die Steuer-Elemente (Execution Controls) angeordnet: dieses ist der Bereich mit der „Act“-, der „Run“- und der „Reset“-Schaltfläche und dem Schieberegler („Speed“/Geschwindigkeit).
2. Objekte in der Welt platzieren
Nun werden Objekte in der Welt platziert: Machen Sie einen Rechts-Klick auf die Kara-Klasse in der Klassenanzeige auf der rechten Seite. Ein Pop-Up-Menü erscheint. Aus diesem wählt man „new Kara()“ aus und kann dann irgendwo in die „Welt“ klicken. Dieser Vorgang hat ein neues Objekt vom Typ „Kara“ erzeugt und dieses dann in der Welt platziert.
Karas essen Klee (clover), daher kann man jetzt auch ein paar Blätter in gleicher Weise in der Welt platzieren: Ein Rechts-Klick auf die „Clover“-Klasse erzeugt ein neues Objekt und ein (Links-)Klick in die Welt legt das Objekt an der Stelle ab. Hält man während des Klickens die Umschalt-Taste (shift) gedrückt, kann man mehrere Objekte ablegen.
3. Objekte „zum Leben erwecken“
Klicken Sie nun auf die „Act“-Schalfläche in der Steuer-Elemente-Leiste. Sie sehen, dass einige Objekte agieren. Dies bedeutet: Jedes Objekt macht das, was ihm per Code als Aktion vorgegeben wurde.
Was genau ein Objekt macht, hängt davon ab, wie das Objekt definiert wurde – dazu kommen wir später. In unserem Beispiel ist den Kleeblättern (Klasse „Clover“) keine Aktion zugeordnet, Objekte der Klasse „Kara“ bewegen sich im Gegensatz dazu in der „Welt“. Falls noch nicht gemacht, platzieren Sie jetzt ein paar Karas, d.h. Objekte der Klasse „Kara“ auf der Welt und drücken Sie die „Act“-Schaltfläche noch einmal. Alle Kara-Objekte bewegen sich.
Karas essen gerne Blätter. Wenn also ein Blatt auf ihrem Weg liegt, werden sie es essen. Beobachten Sie dieses Verhalten. Eventuell müssten Sie noch ein Blatt vor einem Käfer positionieren, damit Sie sehen können, wie es wieder verschwindet.
4. Ein Szenario ablaufen lassen
Klicken Sie auf die „Run“-Schaltfläche. Das ist äquivalent zum wiederholten schnellen Anklicken der „Act“-Schaltfläche. Man stellt fest, dass die Bezeichnung der „Run“-Schaltfläche sich zu „Pause“ verändert. Anklicken der „Pause“-Schaltfläche stoppt den Ablauf wieder.
Der Schieberegler neben den Schaltflächen „Act“ und „Run“ steuert die Geschwindigkeit des Programms, also wie schnell ein Act auf das nächste folgt. Wenn man das Szenario mittels der „Run“-Schaltfläche startet und dann den Schieberegler verändert, sieht man die Auswirkung sofort.
5. Objekt-Methoden direkt aufrufen
Anstatt das gesamte Szenario ablaufen zu lassen, kann man auch einzelne Objekt-Methoden aufrufen. Eine Methode ist eine einzelne Aktion, die ein Objekt ausführen kann:
Stoppen Sie die Animation, falls sie noch läuft. Dann klicken Sie mit der rechten Maustaste auf den Käfer. Man sieht, dass jedes Objekt der „Kara-Welt“ ein eigenes Kontextmenü besitzt (s. Abbildung).
Nun können Sie eine der angegebenen Methoden im Kontext-Menü anwählen; das Objekt führt die zugehörige Aktion aus. Wählen Sie zum Beispiel turnLeft()
durch Anklicken aus. Diese Methode lässt den Käfer eine Linksdrehung ausführen. Versuchen Sie nun die Methode move()
.
Einige Methoden geben Rückgabewerte aus. Probieren Sie zum Beispiel die Methode getCloversEaten(). Diese Methode gibt aus, wie viele Blätter der Käfer bis jetzt gefressen hat.
Vielleicht haben Sie bemerkt, dass auch eine Methode act()
vorhanden ist. Diese Methode wird jedes Mal aufgerufen, wenn man auf die „Act“-Schaltfläche klickt. Wenn man also die act()
-Methode nur eines Objektes aufrufen möchte, kann man das durch direkten Aufruf im Kontext-Menü des jeweiligen Objektes tun.
Für das Verständnis ist wichtig zu erwähnen, dass das Ausführen einzelner Methoden per Kontext-Menü eigentlich nur zum Testen des Programms gedacht ist. Später wird es darum gehen, die besagten Methoden per Code aufzurufen, so dass das gesamte Programm eigenständig ablaufen kann.
6. Eine neue Welt erzeugen
Falls man mehrere Objekte in der Welt platziert hat und diese Objekte nicht mehr haben möchte, d.h. man von ganz vorne anfangen möchte, gibt es einen einfachen Weg: Man kann die ganze Welt „aufgeben“ und einfach eine neue erzeugen. Dieses wird in der Regel durch Anklicken der „Reset“-Schaltfläche (unten) erreicht. Die alte Welt wird automatisch verworfen (und damit auch alle Objekte, die darin waren) und eine neue Welt wird erstellt.
7. Eine Methode der Welt aufrufen
Wir haben eben gesehen, dass die Objekte in der Welt eigene Methoden besitzen, welche über das jeweilige Kontextmenü aufgerufen werden können. Die Welt selber ist auch ein Objekt mit eigenen Methoden, die Sie ebenfalls direkt aufrufen können – dazu genügt ein Rechts-Klick irgendwo in der Welt, wo sich kein anderes Objekt befindet.
Eine der Methoden in diesem Menü ist populate()
. Probieren Sie die Methode einfach mal aus. Es ist eine Methode, die mehrere Blatt- und mehrere Kara-Objekte erzeugt und sie auf der Fläche, sprich in der Kara-Welt, platziert. Man kann nun die Animation wieder mittels der „Run“-Schaltfläche starten.
Eine andere Methode des World-Objektes ist randomClovers(int howMany)
. Diese Methode setzt einige Blätter an zufällig gewählten Positionen auf die Welt. Man beachte, dass der Methodenaufruf einen sog. Parameter („howMany“ / wie viele) vom Typ int
(= Ganze Zahl / Integer) besitzt. Das bedeutet, dass man zusätzliche Informationen angeben muss, wenn man die Methode aufrufen will. Der „Name“ des Parameters – hier howMany
(„wie viele“) – deutet an, dass man eingeben muss, wie viele Blätter in der Welt positioniert werden sollen – probieren Sie es aus.
Eventuell stellen Sie fest, dass die Anzahl der erschaffenen Blätter nicht genau mit der eingegebenen übereinstimmt. Das kommt daher, dass einige Blätter an gleichem Ort abgelegt wurden und sich somit überdecken.
Gut, jetzt haben Sie vielleicht genug davon, den Karas zuzuschauen, wie sie letztlich einfach im Kreis laufen (und ggf. Blätter fressen). Wir kommen jetzt zu interessanteren Dingen: der Programmierung von interessantem Verhalten für unsere eigenen Karas.
B) Programmieren
8. Verändern des Verhaltens von Objekten
Man kann eigene Objekte – Käfer, oder irgendetwas anderes, was man möchte – einfach durch das Schreiben von etwas Java Quellcode für die Klasse dieses Objektes programmieren. Man kann aber auch bereits bestehenden Objekte der Beispiel-Szenarios verändern, und damit wollen wir anfangen.
Klicken Sie die Kara-Klasse in der Klassenanzeige doppelt an. Ein Texteditor erscheint und man sieht den Quellcode der Kara-Klasse. Dieser Code ist geschrieben in Java, also muss jeder Programmierer (also Sie) sich in einer für den Computer verständlichen Weise ausdrücken, wie das Programm funktionieren soll – also wie sich der Käfer verhalten soll.
Verändern wir also das Verhalten des Käfers. Wir wollen, dass er nicht immer nach links dreht, wenn er nicht weiter kann – statt dessen soll er in eine zufällig ausgewählte Richtung weiter laufen. Um dies zu erreichen, fügen wir zu den Methoden der Kara-Klasse eine Methode hinzu, die wir „turnRandom()“ (drehe in zufällig gewählte Richtung) nennen. Öffnen Sie dafür die Kara-Klasse im Editor und fügen Sie den folgenden Code an einer geeigneten Stelle ein – wenn Sie die grobe Struktur des neuen Codes mit dem bereits existierenden vergleichen, sollten Sie sehen können, wo der neue Code hin passt (Achtung: Dabei bitte nichts anderes ersetzen oder löschen!):
/**
* Turn in a random direction.
*/
public void turnRandom() {
int turns = Greenfoot.getRandomNumber(4); // get a random number between 0 and 3...
for(int i=0; i<turns; i++) { // ...and turn left that many times.
turnLeft();
}
}
Hinweis: Beim Kopieren gehen evtl. die Zeilenumbrüche verloren. Diese müssen Sie ggf. von Hand wieder einfügen. Sorgen Sie dabei bitte auch dafür, dass der Code korrekt eingerückt ist und damit übersichtlich bleibt – unter „Edit“ gibt es dafür übrigens eine Auto-Layout-Funktion (am besten merken Sie sich gleich den Shortcut). Da die Einrückung von den geschweiften Klammern bestimmt wird, funktioniert das automatische Layout nur dann richtig, wenn die geschweiften Klammern korrekt gesetzt sind.
Jetzt verändern wir noch die Methode act()
, welche die neu erstellte Methode turnRandom()
nun verwenden soll. Die act()-Methode sieht derzeit so aus:
public void act()
{
if(foundClover()) {
eatClover();
}
else if(canMove()) {
move(1);
}
else {
turnLeft();
}
}
Ersetzen Sie den in obiger Abbildung sichtbaren Aufruf von turnLeft()
durch den Aufruf der neuen Methode turnRandom()
.
Bevor Sie es ausprobieren können braucht es allerdings noch einen weiteren Schritt: Der Computer versteht den soeben geschriebenen Code nicht direkt, er muss zuerst in eine spezielle „Maschinensprache“ übersetzt werden (das ist bei den meisten Programmiersprachen so, aber nicht bei allen). Diesen Übersetzungsprozess nennt man „Kompilierung“, er wird hier normalerweise automatisch durchgeführt. Wenn der Code noch nicht kompiliert wurde, sind die entsprechenden Klassen in der Greenfoot-Oberfläche mit einer blauen Schraffur hinterlegt. Klicken Sie dann links oben auf die Schaltfläche „Compile“ um den Code zu übersetzen, die Schraffur sollte verschwinden. Falls Fehler angezeigt werden, beheben Sie diese (achten Sie auf die Fehlermeldung). Wiederholen Sie dies so lange, bis sich die Klasse ohne Fehler übersetzen lässt. Nach der erfolgreichen Kompilierung wird automatisch eine neue Welt erzeugt, die Sie jetzt ausprobieren können.
9. Bilder / Icons verändern
Es gibt zwei verschiedene Arten, wie man die Bilder von Objekten verändern kann: Man kann das Bild einer Klasse verändern und somit das normale Aussehen der Bilder für alle Objekte der Klasse. Oder ein Objekt kann per Code das eigene Bild verändern. Dieses verändert dann das Bild von nur diesem einen Objekt. Jedes Objekt kann sein Bild verändern, so oft es möchte.
Um das Bild für eine ganze Klasse zu setzen, wählen Sie „Set Image…“ aus dem Kontextmenü der Klasse aus. Sie können dieses mit der Klasse „Clover“ (Klee) ausprobieren – verändern Sie das Bild z.B. in eine Banane, und der Käfer wird die Bananen essen (so, wie er vorher den Klee gefressen hat). Greenfoot hat eine Sammlung von Bildern eingebaut, die hier genutzt werden können. Sie können aber auch eigene Bilder in den „images“-Ordner im aktuellen Projekt ablegen (hier: „Kara“) und dann verwenden.
Die zweite Möglichkeit besteht darin, dass das Objekt selbst das Bild durch Ausführen eines Programmstückes tauscht. Dazu muss die Methode setImage()
, die das Objekt von der Klasse ‘Actor’ erbt, aufgerufen werden. Man könnte beispielsweise die Zeile
setImage("kara_yellow.png");
benutzen, um das Bild eines gelben Käfers für ein Objekt festzulegen.
10. Weiteres zu den Klassen des Greenfoot-Systems
Um Veränderungen am Verhalten der Objekte zu machen, muss man häufig auf einige Standardklassen des Greenfoot-Systems zugreifen. Das Greenfoot-System hat vier wichtige Grundklassen, die Sie kennen sollten:
- die Welt (‘World’),
- den Akteur (‘Actor’),
- das Bild (‘GreenfootImage’),
- und das System selbst (‘Greenfoot’).
Prägen Sie sich hier am besten die englischen Begriffe ein, da wir sie im Text und natürlich in den Programmstücken verwenden werden.
Die ersten beiden Klassen, d.h. ‘World’ und ‘Actor’, haben Sie bereits in der grafischen Benutzeroberfläche gesehen. Sie bilden die Oberklassen für die Welt und die darin enthaltenen Objekte. Die Klasse ‘GreenfootImage’ wird verwendet, wenn man mit Bildern arbeitet. Die Klasse ‘Greenfoot’ bietet Zugang zu den Interna des Greenfoot-Systems. Der einfachste Weg, diese Klassen kennen zu lernen, ist ein Blick in die Dokumentation/API (Anwendungs-Programmier-Schnittstelle) von Greenfoot:
- https://www.greenfoot.org/files/javadoc/ – online, englisch, aktuellste Version
- Rechts-Klick auf Actor oder World – offline, englisch, passend zur installierten Version
- http://www.greenfoot-center.de/doc/javadoc/index.html – online, deutsch, nicht immer ganz aktuell
Klassendokumentationen sind sehr wichtig, denn sie sagen dem Programmierer, was die Bausteine (d.h. die Klassen) können, die er zur Verfügung hat. Greenfoot stellt die oben beschriebenen Klassen zur Verfügung, und Sie werden in Zukunft viel mit diesen Klassen und deren Methoden arbeiten.
Natürlich ist das Programmieren in Greenfoot nicht auf diese Klassen beschränkt, es stehen Ihnen sämtliche Klassen der Programmiersprache Java zur Verfügung. Zwar werden wir noch eine Weile ohne diesen grossen und allgemeinen Werkzeugkasten auskommen, aber Sie können ja mal einen kurzen Blick darauf werfen und sich überzeugen, dass diese Bausteine sehr ähnlich aussehen (und benutzt werden) wie die Greenfoot-spezifischen Klassen:
- https://docs.oracle.com/javase/8/docs/api/ Java-API von Oracle, englisch
11. Dokumentation eigener Klassen
Auch für selbst programmierte Klassen ist eine Dokumentation verfügbar – vorausgesetzt man versieht die Methoden und Eigenschaften/Attribute mit entsprechenden Kommentaren. Kommentare werden im Editor in grau (nach //
) oder dunkelblau (zwischen /*
und */
) dargestellt, sie dienen allein dem Verständnis des Programmierers und werden vom Computer nicht ausgeführt. Manche Kommentare werden allerdings dazu benutzt, die Dokumentation einer Klasse automatisch zu generieren.
Im Greenfoot-Editor gibt es rechts oben eine Auswahlliste, mit der man zwischen dem Quellcode und der automatisch generierten Dokumentation einer Klasse wechseln kann. Schauen Sie sich das in der Kara-Klasse mal an – sehen Sie, aus welchen Informationen die Dokumentation generiert wird?
12. Eine neue Klasse erstellen
Nun ist es Zeit, das Leben unserer Käfer etwas aufregender zu gestalten: Wir werden ein paar Hindernisse einführen, nämlich Bäume (’trees’), und das Programm dann so abändern, dass die Käfer um die Bäume herumlaufen müssen.
Als erstes müssen wir dafür eine neue ‘Actor’-Klasse erstellen. Dazu wählt man den Menüpunkt ‘New subclass’ (Neue Unterklasse) aus dem Kontextmenü der Klasse ‘Actor’. Wenn der Name gefragt wird, geben Sie ‘Tree’ (=Baum) ein (Klassennamen schreibt man gross!). Zusätzlich muss man auch noch ein Bild für die Klasse auswählen, damit sie in der „Welt“ auch sichtbar ist.
Man kann Bilder aus dem Internet herunterladen oder in einem Grafikprogramm erstellen und dann im Unterverzeichnis ‘images’ (= Bilder) ablegen. Wenn man das vor der Erstellung der Klasse durchführt, wird das Bild auch in diesem Dialog angeboten. Für dieses Beispiel haben wir diese Arbeit schon gemacht und ein Bild eines Baumstrunks im entsprechenden Verzeichnis abgelegt. Das Bild heisst ‘tree.png’. Damit sollte das Problem für dieses Beispiel erledigt sein: Wählen Sie dieses Bild aus, klicken Sie auf die ‘OK’-Schaltfläche und schon wird eine neue Klasse mit Namen ‘Tree’ erzeugt.
Nun öffnen Sie den Editor für diese Klasse. Sie sehen, dass das Programm-Skelett schon automatisch erzeugt wurde. Tatsächlich müssen wir an dieser Stelle für die Klasse ‘Tree’ überhaupt keinen Programmcode schreiben, da Bäume kein besonderes Verhalten haben, sondern lediglich im Weg liegen.
Schliessen Sie daher den Editor, kompilieren und testen Sie das ganze System: erzeugen Sie zusätzlich zu Karas und Klee auch einen Baum und platzieren Sie ihn in der Welt – am besten natürlich so, dass ein Käfer darüber stolpern wird. Klicken Sie dann auf „Run“ – funktioniert alles wie gewünscht?
Sie werden feststellen, dass sich die Käfer derzeit noch nicht um die Bäume kümmern: sie laufen einfach über die Bäume hinweg, oder besser: durch sie hindurch. Naja, es wäre auch zu schön, wenn es tatsächlich so einfach gewesen wäre. Wir müssen noch etwas tun, damit die Käfer die Bäume erkennen und vor ihnen die Richtung ändern: Öffnen Sie den Editor mit der ‘Kara’-Klasse und suchen Sie die Methode ‘canMove’ (= kann sich bewegen). Derzeit prüft diese Methode einzig und alleine, ob der Käfer am „Rand“ der Welt steht, d.h. ob er beim nächsten Schritt „von der Welt fallen“ würde. Wir müssen diese Methode so verändern, dass sie auch dann den Wert ‘false’ (=falsch) zurückgibt, wenn ein Baum vor dem Käfer liegt.
Dazu fügen wir ein zusätzliches Stück Code vor der letzten ‘return’-Anweisung ein:
List trees = myWorld.getObjectsAt(x, y, Tree.class);
if(!trees.isEmpty()) { //es liegt ein Baum im Weg
return false;
}
return true;
Dieses Programmstück holt eine Liste aller Baum-Objekte in der Zelle vor uns (man kann mehrere Objekte auf einem Feld ablegen). Falls diese Liste nicht leer ist, kann der Käfer sich nicht bewegen.
Das Beispielszenario Kara2.zip enthält alle vorgestellten Änderungen und sollte somit mit dem von Ihnen verbesserten ‘Kara’-Projekt übereinstimmen. Sie können auch dort nachschauen, welche Veränderungen an den Programmstücken durchgeführt wurden.
13. Und weiter?
Die wichtigsten Grundlagen des Programmierens in Greenfoot haben Sie nun kennen gelernt – ab jetzt gibt es keine Schritt-für-Schritt Anleitungen mehr, sondern nur noch Problemstellungen, an deren Lösung Sie sich versuchen können.
Beispiele für schon etwas fortgeschrittenere Problemstellung im Kontext des Kara-Szenarios wären die folgenden:
- Verändern Sie das Verhalten des Käfers so, dass er ab und zu (z.B. in 30% der Fälle) in eine zufällige Richtung abbiegt, obwohl er auch geradeaus hätte laufen können.
- Programmieren Sie das Verhalten eines Käfers so, dass alle Felder nacheinander besucht werden, und somit alle Blätter garantiert gefressen werden.
Für die erste Variante können Sie den Käfer an einen geeigneten Startpunkt setzen – z.B. oben links - (Erweiterung von 2) Können Sie auch ein Programm schreiben, das von allen Startpunkten aus funktioniert?
- (Erweiterung von 2 oder 3) Geht das auch in einer Welt mit Bäumen?
14. Zusatzaufgabe (schwierig!)
Falls Sie bisher keinerlei Probleme hatten, vielleicht weil Sie schon ein wenig Vorwissen zum Programmieren mit Java mitbringen, hier noch eine echte Knacknuss – auch wenn es nicht so scheint.
Voraussetzung: Eine Welt kann Futter und/oder Hindernisse enthalten, dazu mindesten 2 Käfer, die sich manchmal in eine zufällige Richtung drehen (s. Aufgabe 1 oben). Man weiss nicht, wo die Käfer und die anderen Akteure sich zu Beginn befinden – z.B. weil sie mit der Methode populate() erzeugt wurden.
Programmieren Sie die Käfer so, dass sich nie zwei Käfer auf demselben Feld aufhalten können. Das ist nicht einfach, weil man nicht weiss (und auch nicht herausfinden kann), welcher der Käfer zuerst agiert.
Wenn (oder vielleicht eher: falls) Sie eine allgemeine Lösung für diese Aufgabe finden, dann haben Sie höchstwahrscheinlich verstanden, wie ein Betriebssystem verhindert, dass zwei Prozesse (~Programme) gleichzeitig auf die CPU eines Computers zugreifen können.