Teddy - das Spiel
Spielregeln
Die Spielidee zum Teddy-Spiel lautet folgendermaßen:
- Der Spieler - ein kleines Baby - möchte alle Teddies fangen. Je schneller er alle Teddies fängt, desto mehr Punkte erhält er. Der Spieler kann mit den Pfeiltasten gesteuert werden.
- Wenn der Spieler einen Teddy trifft, verliert der Teddy ein Leben. Ein Teddy hat fünf Leben.
- Sollte der Teddy sich auf einem der klebrigen Flecken befinden, werden ihm sofort alle fünf Leben abgezogen.
- Solange der Teddy noch Leben hat, springt er bei Berührung mit dem Spieler davon.
- Ein gefangener Teddy ist für den Spieler zu Beginn des Spiels 100 Punkte wert, verliert aber mit jedem Ausführungsschritt des Spiels einen Punkt an Wert.
- Der Spieler verliert mit jedem Ausführungsschritt des Spiels einen Punkt. Man sollte also auch schnell sein, wenn die Teddies keine Punkte mehr geben, da das Spiel erst beendet ist, wenn man alle Teddies gefangen hat.
Ein vollständiger Spielablauf könnte also z.B. folgendermaßen aussehen:
Vorlage zum Spiel
Einige Teile des Spiels sind schon fertig implementiert. Was noch fehlt, ist
die die Implementierung der Teddy
-Klasse.
Aufgabe 1 - Vorbereitungen
Lade das Projekt herunter, und entpacke es.
Öffne das Projekt in Greenfoot dann durch Doppelklick auf die Datei "project.greenfoot".
Starte das Spiel. Der Spieler lässt sich steuern und die Punkte laufen herunter.
Mehr passiert noch nicht. Dazu musst Du erst die Teddy
-Klasse mit Leben füllen.
Aufgabe 2 - Basis-Teddy
Die Klasse Teddy
existiert schon, enthält aber noch kaum Funktionalität.
Experimentiere mit den Teddies, indem Du rechts auf sie klickst und den Objektinspektor
sowie verschiedene Methoden ausführst.
Öffne den Quelltext der Klasse durch Doppelklick auf die Klasse (oder Rechtsklick → Editor öffnen).
Erkläre anhand des Quellcodes welche Attribute und Methoden ein Teddy schon hat.
Modell eines Teddy
Im Folgenden müssen wir die Eigenschaften und Fähigkeiten eines Teddy-Bären im Computer implementieren. Wir müssen also ein Modell eines Teddy's für den Computer bilden. Ein Teddy kann Eigenschaften wie z.B. einen Preis, eine Stoffart, eine Marke etc. besitzen. In unserem Fall soll der Teddy aber einen grafischen Teddy für unser Spiel repräsentieren. Deshalb modellieren wir die Eigenschaften und Fähigkeiten, die für unser Spiel relevant sind.
Attribute
Unser Teddy soll ein Alter und die noch verbleibenden Leben als Attribute besitzen. Da er schon springen kann, hat das Klassendiagramm damit folgende Form:
Während man in Klassendiagrammen der UML (Unified Modeling Language) den Datentyp üblicherweise durch Doppelpunkt hinter einer Variablen angibt, wird der Datentyp in Java bei der Definition einer Variablen vorangestellt. Anweisungen müssen in Java mit einem Semikolon abgeschlossen werden. Wir definieren ein Attribut in Java also folgendermaßen:
int alter;
Attribute werden üblicherweise oben in einer Klasse definiert. Eine einfache Teddy
-Klasse hätte damit also
folgende Form:
class Teddy {
int alter;
}
Die weiteren Teile des Codes der Vorlage hängen in erster Linie damit zusammen, dass wir eine Unterklasse von Actor bilden wollen.
Was das Wort public
bedeutet, musst Du noch nicht verstehen.
Im Wesentlichen erlauben wir damit den Zugriff auf eine Methode außerhalb der Klasse.
Momentan schreiben wir es einfach am besten vor alle Methoden.
Im nächsten Projekt wirst Du genauer lernen was public
bedeutet.
Insgesamt sieht unsere Klasse nun folgendermaßen aus:
import greenfoot.*;
class Teddy extends Actor
{
int leben;
int alter;
public void springen() {
// ... Implementierung der Methode
}
}
Aufgabe 3 - Attribute
Ergänze die Vorlage entsprechend. Teste, ob alles funktioniert hat, indem Du den
Objektinspektor eines Teddy's aufrufst.
Die Attribute leben
und alter
müssen hier erscheinen.
Compilieren
Greenfoot compiliert den Code automatisch, sobald Du eine Zeile wechselst. Das bedeutet Greenfoot übersetzt dann das Programm in eine für den Computer ausführbare Form. Enthält Dein Programm syntaktische Fehler werden diese rot unterstrichen. Syntaktische Fehler sind z.B. fehlende Klammern oder ein fehlendes Semikolon, also alle Fehler, die dafür sorgen, dass Dein Programm kein gültiges Java-Programm ist.
Aufgabe 4 - Syntaxfehler
Sorge z.B. durch ein fehlendes Semikolon dafür, dass Dein Programm nicht compilierbar ist und beobachte wie Greenfoot dies Dir anzeigt.
Konstruktoren
Beim Betrachten der Attribute im Objektinspektor ist Dir möglicherweise aufgefallen, dass die Attribute zwar vorhanden sind, aber noch keine sinnvollen Werte enthalten. Wir benötigen also eine Möglichkeit beim Erzeugen eines Objektes bestimmte Operationen, wie z.B. die Initialisierung der Attribute vorzunehmen. Diese Möglichkeit bieten einem Konstruktoren. Der Konstruktor einer Klasse wird immer dann aufgerufen, wenn ein neues Objekt der Klasse erzeugt werden soll. In Java heißt der Konstruktor immer genau so wie die Klasse selbst und kann - ähnlich wie Methoden - Parameter erhalten. Eine vereinfachte Teddy-Klasse könnte also so aussehen:
class Teddy {
int leben;
Teddy() {
leben = 5;
}
}
Man kann an diesem Beispiel auch sehen wie Zuweisungen funktionieren: Auf der rechten Seite muss ein Ausdruck stehen,
der während der Ausführung des Programms einen bestimmten Wert besitzt.
Im einfachsten Fall ist dies eine Konstante wie die Zahl 5.
Hier wären auch komplexere Ausdrücke wie 5 + 3
, leben * 2
oder (leben - 4) * (leben +5)
möglich.
import greenfoot.*;
class Teddy extends Actor
{
int leben;
int alter;
Teddy() {
leben = 5;
alter = 0;
}
public void springen() {
// ... Implementierung der Methode
}
}
Aufgabe 5 - Konstruktor
Ergänze die Vorlage entsprechend. Teste, ob alles funktioniert hat, indem Du den Objektinspektor eines Teddy's aufrufst.
Die Attribute sollten nun korrekt initialisiert sein.
(Hinweis: alter
müsste man im Konstruktor nicht unbedingt auf 0 setzen, da dies
der Standardwert für Attribute vom Typ int
ist.
Es ist aber besserer Stil dies trotzdem zu tun, da man damit den gewünschten Wert explizit dokumentiert.)
Methoden
Das Alter eines Teddy's soll mit jedem Ausführungsschritt des Spiels erhöht werden.
In Greenfoot gibt es eine besondere Methode, die automatisch
für jedes Objekt ausgeführt wird: Die act
-Methode.
Diese besitzt keine Parameter und gibt keinen Wert zurück.
Methoden schreibt man üblicherweise unterhalb des Konstruktors auf. Die Anweisungen, die beim Ausführen einer Methode ausgeführt werden sollen, werden in geschweiften Klammern angegeben. Eine vereinfachte Teddy-Klasse könnte also folgende Form haben:
class Teddy {
int leben;
Teddy() {
leben = 5;
}
void act() {
// ... hier steht was beim Ausführen von act passieren soll ...
}
}
Die act
-Methode muss in unserem Fall als public
definiert sein,
womit unsere Klasse so aussieht:
import greenfoot.*;
class Teddy extends Actor
{
int leben;
int alter;
Teddy() {
leben = 5;
alter = 0;
}
public void springen() {
// ... Implementierung der Methode
}
public void act() {
// ... hier soll das Alter um eins erhöht werden
}
}
Aufgabe 6 - act
Ergänze die act
-Methode.
Ergänze innerhalb der Methode eine Anweisung, die das Alter um eins erhöht.
Teste die Implementierung mit Hilfe des Objektinspektors und dem Act- bzw. Run-Button in Greenfoot
in der folgenden Art:
Methoden mit Parametern
Damit der Teddy beim Treffen auf einen Kleberfleck oder den Spieler Leben verliert, müssen diese
ihm Leben abziehen können. Wir benötigen also eine Methode verringereLeben
, welche die
noch verbleibenden Leben um einen bestimmten Betrag verringern. Zusammen mit den bisher
implementierten Methoden ergibt sich folgendes Klassendiagramm:
Da bisher keine der Methoden etwas zurück gibt, könnte man das Klassendiagramm auch folgendermaßen darstellen:
In der Praxis wählt man aber oft die obere Variante, auch wenn diese nicht ganz eindeutig ist, da nicht sicher ist, ob die Methode nichts zurück gibt, oder der Rückgabetyp im Klassendiagramm nur nicht dargestellt ist.
public void verringereLeben(int betrag) {
// ... leben um betrag verringern
}
Aufgabe 7 - verringereLeben
Ergänze die Methode mit der entsprechenden Anweisung zum Verringern des Lebens-Attributes.
Teste mit Hilfe des Objektinspektors
(Dass leben
negativ werden kann, ist für unser Spiel nicht störend):
Methoden mit Rückgabe
Schließlich soll der Teddy noch Methoden besitzen, um Informationen über den eigenen Wert zu liefern.
Dieser wird für den Punktestand des Spielers benötigt.
Der Wert ergibt sich aus 100 - alter
.
Da der Spieler nur positive Werte berücksichtigen möchte, benötigt der Teddy noch eine Methode hatWert
,
die zurückgibt, ob der Wert des Teddy's noch im positiven Bereich ist.
Im Klassendiagramm ergibt sich folgendes Bild:
Methoden geben einen Wert mit Hilfe des Schlüsselwortes return
zurück.
Sobald bei einer Methode eine return-Anweisung ausgeführt wird, wird die Methode beendet.
In Java können die beiden Methoden dann folgendermaßen definiert werden:
public int getWert() {
return 100 - alter;
}
public boolean hatWert() {
return getWert() > 0;
}
Beachte, dass die Methode getWert
innerhalb der Methode hatWert
aufgerufen wird.
Ein Objekt kann also eigene Methoden aufrufen.
Aufgabe 8 - Wert
Erkläre die Funktionsweise der beiden Methoden. Ergänze die Methoden und teste mit Hilfe des Objektinspektors und durch Methodenaufrufe.
Spiel fertig stellen
Die Teddy-Klasse ist nun fertig. Da die Spieler-Klasse und die Kleber-Klasse auf Funktionalität des Teddy zugreifen, dieser aber zu Beginn nicht fertig war, wurden dort Teile des Codes auskommentiert. Dies soll nun rückgangig gemacht werden.
Aufgabe 9 - Spiel fertig stellen
Öffne den Code der Klassen Spieler
und Kleber
.
Entferne die beiden Schrägstriche, mit denen Kommentare eingeleitet werden.
Tipp: Du kannst alle auskommentierten Zeilen markieren und über das Menü (Bearbeiten)
oder über die Tasten F7 bzw. F8 Kommentare aus- oder einschalten.
Teste abschließend das Spiel. Das bedeutet: Spiele :-)