Adventuregame Folge 1

Applets, Gegenstände und UML

Wir werden am Ende dieses Exkurses (der mehrere Folgen umfasst) ein Adventuregame geschrieben haben, welches aus einem Helden besteht, der durch einen Dungeon herumirrt, dabei auf Monster trifft, die er bekämpfen muss und denen er Gegenstände abnehmen kann. Andere Gegenstände liegen auf den Feldern des Dungeons herum und können vom Helden aufgenommen werden. Auf diese Weise wandern die Gegenstände in das Inventar des Helden. Neben normalen Gegenständen gibt es auch noch Zauberrollen, die einen Zauber enthalten. Findet der Held einen solchen Zauberspruch, nimmt er ihn in sein Zauberbuch auf. Dieses hilft dem Helden beim Kampf gegen die Monster. Erst wenn der Held alle Monster besiegt hat, wird der Ausgang des Dungeons sichtbar, und der Held kann den Dungeon siegreich verlassen. Das Spiel ist dann beendet. Falls der Held vorher im Kampf stirbt, ist das Spiel natürlich auch beendet.

Alle orange unterlegten Begriffe stehen schon einmal für Java-Klassen. Sie sehen, das Spiel wird recht komplex. Aber keine Angst, in der heutigen Folge wollen wir nur eine einzige Klasse programmieren, und noch nicht einmal dies werden wir ganz schaffen. Aber zumindest bekommen wir so einen Einstieg in das Spiel.

Das Adventure-Projekt

1 Das Adventure-Projekt, Version 1.01

In Abb. 1 sehen Sie die allererste Version des Adventure-Projektes. Sie benötigen eine Klasse Gegenstsand sowie ein neues, leeres Java-Applet. Fall Sie noch nie zuvor mit Java-Applets gearbeitet haben, so können Sie den Exkurs "Java-Applets" machen. In diesem Exkurs lernen Sie, was man unter einem Applet versteht, und sie lernen die wichtigsten Zeichenbefehle für Java-Applets kennen. Wenn Sie eine schnelle Auffassungsgabe haben, können Sie auf diesen Exkurs allerdings auch verzichten, in diesem Adventure-Projekt wird Ihnen auch das Nötigste zum Umgang mit Applets erklärt.

Das Applet Spiel

Schauen wir uns mal den Quelltext der Klasse Spiel an. Wenn Sie mit BlueJ ein neues Applet erzeugen, wir immer ziemlich viel Quelltext erzeugt. Ich habe hier das meiste gelöscht und nur die wirklich wichtigen Sachen übrig gelassen. Aber sehen Sie selbst:
import java.awt.*;
import javax.swing.*;

public class Spiel extends JApplet
{
   Gegenstand schwert;

   public void init()
   {
      schwert = new Gegenstand("Excalibur");
   }

   public void paint(Graphics g)
   {
      g.drawString("Spiel V 1.01", 20, 20);
      schwert.anzeigen(g,20,50);
   }
}

2 Quelltext der Klasse Spiel - komplett

Sie können in BlueJ jetzt ein Applet "Spiel" erzeugen, sämtlichen Quelltext ausschneiden und über die Zwischenablage den Quelltext aus Abb. 2 einsetzen. Natürlich wird das Applet noch nicht funktionieren, weil Sie ja die Klasse Gegenstand noch nicht programmiert haben. Aber dazu später.

Quelltextanalyse

Die Quelltextanalyse ist doch etwas umfangreicher geworden, als ich anfangs dachte. Daher habe ich sie in eine eigene HTLM-Seite ausgelagert. Wenn Sie den Quelltext der Abb. 2 aber schon verstanden haben, können Sie die Quelltextanalyse gerne überspringen.

Die Klasse Gegenstand

Attribute der Klasse Gegenstand

Die Gegenstände liegen im Dungeon auf bestimmten Feldern herum oder werden von den Monstern mitgeführt und können dann vom Helden erbeutet werden, wenn er ein solches Monster besiegt hat.

In unserer allerersten Version hat die Klasse Gegenstand nur ein einziges Attribut - nämlich die Bezeichnung. Aber vielleicht schauen wir uns auch hier einfach den kurzen Quelltext der Klasse an, damit Sie etwas schneller in die Spiele-Progammierung hereinkommen:

import java.awt.*;

public class Gegenstand
{
   String bezeichnung;

   public Gegenstand(String bez)
   {
      bezeichnung = bez;
   }

   public void anzeigen(Graphics g, int x, int y)
   {
      g.drawString(bezeichnung,x,y);
   }
}

3 Quelltext der Klasse Gegenstand - komplett

Wenn Sie wollen, können Sie jetzt eine leere Klasse Gegenstand erzeugen und diesen Quelltext über die Zwischenablage hineinkopieren. Ihr Java-Projekt müsste dann eigentlich reibungslos funktionieren.

Quelltextanalyse

Auch hier lagern wir die Analyse des Quelltextes wieder in eine eigene HTML-Seite aus, so dass Sie diesen langen Abschnitt bei Bedarf lesen oder im Falle des Sofortverstehens auch überspringen können.

Darstellung von Klassen in UML

UML ist eine Art Sprache zur anschaulichen Darstellung von Klassen, Objekten und Beziehungen zwischen Klassen und Objekten. In diesem ersten Teil des Adventure-Games werden wir uns auf die Darstellung von Klassen beschränken.Eine Klasse wird durch ein Rechteck dargestellt, das durch waagerechte Striche in drei Abschnitte unterteilt wird. Oben schreiben wir den Namen der Klasse hinein, in den mittleren Abschnitt die Attribute, und in den unteren Abschnitt die Methoden der Klasse:

4 UML-Darstellung der Klasse Gegenstand

Die Klasse Gegenstand hat hier drei weitere Attribute erhalten, nämlich angriffswert, verteidigungswert und goldwert. Zunächst werden diese drei Attribute als int-Zahlen deklariert. Später werden wir feststellen, dass man sinnvoller mit double-Zahlen rechnet.

So ein UML-Diagramm ist recht schnell geschrieben, allerdings ist die Syntax eine etwas andere als die Darstellung in Java. UML ist unabhängig von einer bestimmten Programmiersprache und hat daher eine eigene Syntax.

Die Plus- und Minus-Zeichen vor den Attributen und Methoden besagen, ob ein Attribut oder eine Methode nach außen hin sichtbar (+) oder unsichtbar (-) ist. In der Sprache Java drückt man dies durch die Schlüsselworte public (+) bzw. private (-) aus. Wir sehen also: Alle Attribute sind nach außen hin verborgen (Datenkapselung). Die Methode ausgeben() ist dagegen nach außen hin sichtbar, man spricht hier auch von einer öffentlichen Methode (public).

Konstruktoren sind ganz besondere Methoden und werden daher mit einem C gekennzeichnet. Achten Sie darauf, dass der Konstruktor in der Abb. 4 vier Parameter erwartet, schließlich müssen jetzt vier Attribute mit Anfangswerten ausgestattet werden.

Genug der Theorie - jetzt wollen wir erstmal ein bisschen programmieren.

Übung Adventure 1.1 (2 Punkte)

Stellen Sie die Klassen Spiel und Gegenstand soweit wie oben beschrieben fertig, erzeugen Sie in der BlueJ-Umgebung mehrere konkrete Gegenstände und testen Sie den Konstruktor sowie die von Ihnen programmierte Ausgabe-Methode eingehend.

Hinweis

Sie müssen sowohl den Konstruktor wie auch die anzeigen()-Methode erweitern, um diese Aufgabe zu lösen.

Übung Adventure 1.2 (4 Punkte)

Ergänzen Sie die Klasse um ein weiteres Attribut zustand sowie eine neue Methode beschaedigen(int prozent), welche den Gegenstand um die angegebene Prozentzahl beschädigt. Die alten Attributwerte dürfen Sie dabei nicht speichern! Also keine neuen Attribute anlegen wie z.B. angriffswertAnfang oder goldwertAnfang.

Beispiel:

Vor dem Aufruf von beschaedigen haben die Attribute unseres Beispiel-Objektes folgende Werte:

  • bezeichnung = "Excalibur"
  • angriffswert = 20
  • verteidigungswert = 0
  • goldwert = 150
  • zustand = 100

Nun soll dieser Gegenstand um 75% beschädigt werden. Nach dem Aufruf von beschaedigen(75) müssen die Attribute also folgende Werte haben:

  • bezeichnung = "Excalibur"
  • angriffswert = 5
  • verteidigungswert = 0
  • goldwert = 38
  • zustand = 25

Das Attribut zustand erfüllt hier eine sehr wichige Funktion. Es speichert, zu wieviel Prozent ein Gegenstand überhaupt einsatzbereit ist. Wenn der Zustand den Wert 0 erreicht haben sollte, so kann der Gegenstand weder verwendet noch repariert werden.

Hinweis zu den Datentypen

Vielleicht ist es an dieser Stelle der Programmierung sinnvoll, die Typen der int-Attribute auf double zu ändern; die Berechnungen sind dann doch etwas leichter zu realisieren. Entsprechend sollten Sie auch für das Attribut zustand den Datentyp double wählen.

Hinweis zur Entwicklung der Formel zur Berechnung der Attributwerte

Hauptschwierigkeit bei dieser Aufgabe ist nicht die Programmierung der Methode an sich, sondern das Entwickeln einer Formel zur Neuberechnung der Attributwerte. Ich sehe immer wieder Schüler und Schülerinnen, die einfach schreiben:

zustand = zustand - prozent;

Diese Rechnung ist nur dann korrekt, wenn der Zustand des Objektes vor dem Beschädigen den Wert 100 hat. Was aber ist, wenn das Objekt zweimal hintereinander mit 50% beschädigt wird? Nach der ersten Beschädigung hat es den Zustand 50, nach der zweiten Beschädigung aber den Zustand 25 (50% von 50). Die Formel muss also wohl etwas komplizierter sein!

Allgemeine Frage zur Methode beschaedigen()

Man hätte das Beschädigen der Gegenstände rein theoretisch auch völlig anders lösen können, nämlich ohne Veränderung der Attributwerte des Gegenstandes.

Entwickeln Sie eine sinnvolle Idee, wie man dies bewerkstelligen könnte!




Hinweis zu den Hinweisen

Wenn Sie die Hinweise zur Lösung der Aufgaben nicht lesen, so ist das Ihr Problem!

Übung Adventure 1.3 (4 Punkte)

Ergänzen Sie die Klasse Gegenstand um zwei Methoden reparieren() und reparaturKosten(), welche Folgendes leisten:

int reparaturKosten():
Die Funktion liefert als Rückgabewert den Betrag zurück, den die Reparatur kosten würde. Dieser Betrag ist einfach der Goldwert-Zuwachs, den die Reparatur erbringt. Unser defektes Schwert aus Übung 3.2 hat zum Beispiel den Goldwert 38, nach der Reparatur beträgt der Goldwert aber wieder 150. Also würde die Reparatur 112 (150 minus 38) Goldstücke kosten.

reparieren():
Der Gegenstand wird vollständig repariert, d.h. alle Attribute werden wieder auf den ursprünglichen Wert gesetzt. Ein teilweises Reparieren eines Gegenstandes ist nicht möglich, da es gegen die Ehre der Schmiede in unserem Abenteuerland gehen würde, ein Schwert oder einen Schild nur halb zu reparieren.

Wichtiger Hinweis (siehe Hinweis zu den Hinweisen rechts neben den Hinweisen zu Übung 3.2)

Vielleicht haben Sie schon selbst festgestellt, dass sowohl bei der Berechnung der Reparaturkosten wie auch beim eigentlichen Reparieren das Gleiche gemacht werden muss: Neuberechnung der Attributwerte aus den aktuellen Attributwerten und dem aktuellen Zustand. Die ursprünglichen Attributwerte durften Sie ja nicht speichern. Vielleicht können Sie diese mathematische Aufgabe in eine eigene private-Methode auslagern, die dann von den beiden Methoden, die Sie programmieren sollen, aufgerufen wird.

Übung Adventure 1.4 (2 Punkte)

Ergänzen Sie die Klasse Gegenstand ein zusätzliches Attribut typ, welches die vier int Werte 1, 2, 3 oder 4 haben kann. Dabei haben die Zahlen folgende Bedeutung:

1 = Waffe
2 = Schild
3 = Rüstung
4 = Sonstiges

Den Konstruktor von Gegenstand müssen Sie entsprechend um einen weiteren Parameter ergänzen, damit der Typ gleich beim Erzeugen des Gegenstandes festgelegt werden kann.

Ergänzen Sie die Klasse Gegenstand außerdem um eine sondierende Methode

public int gibTyp()

welche eine Zahl zwischen 1 und 4 zurückliefert, jenachdem, welchen Typ der Gegenstand hat.

Weil Waffen, Schilde und Rüstungen besonders wichtige Gegenstände sind, sollen Sie auch noch drei sondierende Methoden schreiben:

public boolean istWaffe()

public boolean istSchild()

public boolean istRuestung()

die den Wert true oder false zurückliefern, jenachdem ob der Gegenstand eine Waffe, ein Schild oder eine Rüstung ist.

Hinweis zum Sinn dieser Aktion

Haben Sie schon einmal ein richtiges Adventure-Game wie z.B. Diablo oder Sacred oder Dungeon Siege gespielt? Dann werden Sie festgestellt haben, dass der Held meistens nur eine Waffe, eine Rüstung und einen Schild gleichzeitig verwenden kann. Das wollen wir bei unserem Spiel genauso halten. Wenn wir dem Helden also eine neue Waffe in die Hand drücken wollen, so müssen wir erstens sicherstellen, dass es sich bei diesem Gegenstand tatsächlich um eine Waffe handelt, und zweitens müssen wir irgendwie sicherstellen, dass der Held nur eine Waffe gleichzeitig in der Hand hält. Dazu ist es sehr sinnvoll, wenn man im Quelltext eine Abfrage wie

if (neuerGegenstand.istWaffe()) ...

programmieren kann.

Extra-Übung für Fortgeschrittene (2 Punkte)

Erkundigen Sie sich in Büchern oder im Internet, wie man in Java Konstanten deklariert und verwendet, so dass Sie in Zukunft schreiben können:

if (typ == Gegenstand.WAFFE)...

oder

typ = Gegenstand.SCHILD;

Es hilft nichts, wenn die Konstanten nur innerhalb der Klasse Gegenstand gültig sind. Auch andere Klassen müssen überprüfen können, ob ein Gegenstand eine Waffe ist, daher müssen die Konstanten projektweit gültig sein.

Stellen Sie Ihr Java-Projekt dann entsprechend um. Die zwei Punkte werden Ihnen dann zu Übung 1.4 dazugezählt.

Übung Adventure 1.5 (2 Punkte)

Zeichnen Sie ein UML-Diagramm der Klasse Gegenstand, in dem auch die neuen Attribute und Methoden der Übungen 1 bis 4 berücksichtigt sind.

Weiter mit Folge 2: Der Held

Diese HTML-Seite wurde erstellt von Ulrich Helmich am 21. Januar 2006.





IMPRESSUM