<style>H3{color:steelblue;}</style>
# Lerntagebuch zur Bearbeitung von PMDungeon
- Niklas Rettinger (nrettinger@fh-bielefeld.de)
- Marius Warning (mwarning@fh-bielefeld.de)
- Tristan Nentwig (tnentwig@fh-bielefeld.de)
## Blatt 1
### Aufgabe
In dieser Aufgabe soll mittels des angeboten Frameworks pmdunegon.jar ein lauffähiges Spiel entwicklet werden, bei dem sich ein einzelner Held im Dungeon bewegt und bei Erreichen einer Leiter ins nächsthöhere Level springt.
### Ansatz und Modellierung
Zur Erreichung der Aufgabe sind zwei Klassen zu erstellen, zum einen ein erweiterter MainController, der den Spielfluss steuert und zum anderen eine Klasse MyHero, die das Verhalten und das Aussehen des Helden kontrolliert.
#### MainController
Als Basisklasse wird der MainController des Frameworks verwendet, dessen Funktionen setup, onLevelLoad und endframe mittels Dekoratoren überschrieben werden.
* **setup** : Wird einmalig ausgeführt. Unser Held wird instanziiert und dem entityController hinzugefügt
* **onLevelLoad**: Wird bei Erreichen eines neues Levels aufgeführt. Der Held bekommt die Information über das neue Level.
* **endframe**: Wird am Ende jeden Frames ausgeführt. Hier wird überprüft, ob sich der Held auf der Position der Leiter befindet. Wenn ja, wird das Level iteriert.
#### Held
Unser Held muss die beiden Interfaces IAnimatable und IEntity implementieren. Die zu implementierenden Funktionen werden mittels Dekorator Pattern überschrieben.
* **Konstruktor**: Die einzelnen Animationen werden als Bildfolgen in einer Liste gespeichert und als Animation instanziiert. In diesem Fall die Idlebewegung, Horizontalbewegung und Vertikalbewegung.
* **getActiveAnimation**: Funktion zur Rückgabe der aktuelle Animation aufgrund von Statusvariablen.
* **update**: Diese Funktion wird vom EntityController aufgerufen. Hier wird die aktuelle Position und die jeweilige anzuzeigene Antimation bestimmt, sowie die Draw-Funktion aufgeufen.
* **setLevel und findRandomPosition**: setLevel wird vom MainController aufgerufen wenn der Held eine Leiter erreicht hat. Im Zuge dessen wird die funktionRandomPosition aufgerufen, die dem Helden eine zufällige Position im neuen Level zuweist.
### Umsetzung
Die Umsetzung erfolgte nach dem im letzten Abschnitt gezeigten Verfahren. Auf aufwendige Modellierungen mittels Diagrammen wurde aufgrund der noch geringen Komplexität verzichtet.
### Postmortem
In diesem Teil des Lerntagebuches soll noch einmal auf die Umsetzung und das Vorgehen bezüglich der Aufgabenstellung zurückgeblickt werden.
#### Erfüllte Funktionen
Rückblickend lässt sich zusammenfassen, dass sämtliche Aufgabenstellungen zufriedenstellend erfüllt werden konnten. Konkret umfasst das:
* Einfügen des Spielsetups
* Das zum Laufen bringen der Game-Loop
* Erstellen der Heldenklasse mit sämtlichen Animationen (idle, run)
* Implementation des LevelControllers mit zufälligem Spawnpunkt des Helden
* Builden der jar-Datei aus den java-Dateien des Spiels mittels ant
#### Vorgehen
Prinzipiell war das Vorgehen an sich als effektiv einzustufen. Dies konnte unter anderem durch das Arbeiten mit einem Gruppen-Repository zur dynamischen Projektbearbeitung erreicht werden. Als hinderlich erwies sich lediglich, dass die Zeit recht knapp bemessen war. Sämtliche Gruppenmitglieder sind "Quereinsteiger" aus dem Fachbereich der Elektrotechnik und und haben dieses Fach zusätzlich zum Masterstudium auferlegt bekommen.
#### Herausforderungen
Eine Herausforderung war die Einarbeitung in ant, da sämtliche Gruppenmitglieder lediglich mit dem Gebiet der hardwarenahen Programmierung in C/C++ (und Python) vertraut sind. Dadurch musste sich dieses Wissen noch selber angeignet werden. Außerdem waren keine Java-Kenntnisse vorhanden.
# Blatt 2
In dieser Aufgabe sollen Loggingmechanismen implementiert und zusätzlich zum Helden mindestens zwei Monster erstellt werden. Befindet sich ein Monster in der Nähe des Heldes soll es zu einem Kampf kommen.
## Ansatz und Modellierung
### Monster und Kampf
Analog zum erstellten Helden werden zwei weitere Objekte erstellt, der Daemon und der Zombie. Die Animationen werden analog zu dem des Helden angelegt.
Bei jedem Levelwechsel werden noch vorhandene Monster aus der Entity entfernt und im nächsten Level wieder erstellt. Damit sollen zu einem späteren Zeitpunkt zufällige Monster pro Level erstellt werden können. Die Erstpositionierung erfolgt wieder zufällig in der Ebene. Die den Monster zuordnenbaren Attribute sind:
Strength: Stärke des Monsters, wird bei Ausfechten eines Kampfes verwendet
Speed: Geschwindigkeit mit dem sich das Monster bewegt
Health: Lebenspunkte des Monsters. Verringern sich bei erfolglosem Kampf und erhöhen sich bei erfolgreichen Kampf
Die Monster erhalten eine Objektreferenz zum Helden und berechnen aus dessen Position und einer festgelegten Range, ob sie sich in Richtung des Helden bewegen oder stationär verbleiben. Befinden sie sich auf der gleichen Position wie der Held, wird ein Flag gesetzt, der vom GameController ausgelesen wird. Der Held kann von sich aus ein Monster in seiner Reichweite attackieren und setzt dann ebenfalls ein Flag. Die Initiierung erfolgt mittels eins Maustastendrucks.
Der GameController führt eine Funktion calcCombat am Ende des Frames aus und überprüft, ob ein Flag gesetzt ist. Als rudimentäres Kampfsystem zieht der Angreifer dem Angegriffenen seine Stärke von dessen Lebenspunkte ab. Ist der Angriff von der anderen Seite initiiert, erfolgt der Abzug in anderer Richtung.
Um zu überprüfen, ob ein Objekt seine Lebenspunkte verloren hat wird die Funktion checkForDeath ausgeführt. Besitzt ein Moster keine Health-Punkte mehr wird das Monster von der Entity entfernt. Wird der Held getötet wird Game Over gelogt und das Spiel beendet. Alle Monster und Helden werden entfernt, das Level auf 1 gesetzt und so das Spiel resettet.
### Logging
Das Logging wird mit einer statischen Klasse umgesetzt. Diese Klasse wird über eine init Funktion initialisiert und erhält dabei ein Log-Level aus den folgenden möglichen Log-Levels:
- DEBUG: Zeigt alle Logs an, inklusive Bewegungen aller Charactere
- INFO: Informationen bezüglich des Spielverlaufs und der Charactere
- WARNING: Warnungen
- ERROR: kritische Fehler
- FATAL: Fatale Fehler, bei denen das Spiel gestoppt werden muss
Der Logger gibt immer alle Meldungen heraus, die das gleiche oder ein höheres Log-Level haben wie das gesetzte Log-Level. Diese Meldungen werden zum einen auf der Konsole ausgegeben und zum anderen in einer Datei gespeichert. Zu diesem Zeitpunkt werden das Log-Level und der Name der Log Datei im Controller des Spiels festgelegt. Hier soll in Zukunft noch eine json-Konfiguration entstehen, aus welcher diese Daten gelesen werden.
Jedes Paket, welches Meldungen loggen will kann hierzu den Logger einbinden und die Funktion *message* mit dem entsprechenden Log-Level, einem Fehler-Code, dem Klassennamen und einem Text aufrufen. Fehler-Code und Text sind hierbei optional. Dieser Zusammenhang ist in der folgenden Abbildung dargestellt.

Der Logger wird zum Spielstart initialisiert und bleibt über den gesamten Spielverlauf erhalten.
### Umsetzung und Herausforderungen
Die Implementierung erfolgte nach vorheriger Planung der umzusetzenden Aufgaben. Leider hat sich gezeigt, dass einige unvorteilhafte Designentscheidungen getroffen wurden. Zum Beispiel, Objektreferenzen keinen eineindeutigen Fluss besitzen. So werden teilweise aufeinander aufbauende oder abhängige Funktionalitäten aufgrund von Flags gesetzt, die der GameController aus verschiedenen Objekten holen und überprüfen muss. Ziel ist es, diese Abhängigkeiten zu optimieren.
## Umsetzung
### Monster und Kampf
### Logging
Die Klasse Logger enthält das LogLevel logLevel, welches als enum realisiert ist. Dieses enum enthält Funktionalität, um verschiedene LogLevel zu vergleichen. Ausderdem enthält der Logger den String logFileName. Beide werden zur Initialisierung gesetzt. Ebenfalls gesetzt wird das flag isInitialized, welches bei jedem Log Vorgang geprüft wird. Das letzte Attribut des Loggers ist ein timeStamp, welche verwendet wird, um die aktuelle Zeit mit Millisekunden Genauigkeit anzugeben.
Die Methode *message* wird aus verschiednen Klassen heraus aufgerufen um Nachrichten zu loggen. Sie ist überladen, damit bei Meldungen unter dem LogLevel *ERROR* auf den Fehler-Code verzichtet werden kann. Ebenfalls verzichtet werden kann auf einen Text, wenn ein generischer Fehler auftritt.
## Postmortem
In diesem Teil des Lerntagebuches soll noch einmal auf die Umsetzung und das Vorgehen bezüglich der Aufgabenstellung zurückgeblickt werden.
### Erfüllte Funktionen
Rückblickend lässt sich zusammenfassen, dass sämtliche Aufgabenstellungen zufriedenstellend erfüllt werden konnten. Konkret umfasst das:
* Das Hinzufügen eines Loggers
* Das Hinzufügen von Log-Nachrichten auf verschiedenen Ebenen
* Die Implementierung zweier verschiedener Monster
* Demon
* Zombie
* Die Implementierung der automatischen Verfolgung des Spielers innerhalb einer bestimmten Reichweite
* Die Implementierung eines Kampfsystems
* Das Hinzufügen von Attributen
* Health
* Strength
* Das automatische Entfehrnen von Characteren beim Tod
# Blatt 3
## Aufgabe
Die Aufgabe dieses Praktikums ist die Implementierung eines Item-Systems für das zu entwickelnde Spiel. Konkret bedeutet das, dass:
* Items in einer festzulegenden Form erschaffen werden
* Ein Iventarsystem erschaffen wird, so dass Items gespeichert werden können
* Items aus dem Inventar aufgenommen werden können und dort wieder abgelegt werden können
* Truhen implementiert werden, mit denen Items aufgesammelt werden können
* Die Items in diesen Truhen zufällig sind
* Truhen Items nur in einer bestimmten Reichweite zum Helden ausgeben/ aktivierbar sind
---
## Ansatz und Modellierung
### Items
Es werden drei verschiedene Item-Typen implementiert. Diese haben grundsätzlich die gleiche Funktion. Sie manipulieren die Attribute des Spielers (Stärke, Leben, Resistenz und Geschwindigkeit). Es wird die Möglichkeit offen gehalten später noch weitere Attribute hinzuzufügen, wie zum Beispiel Glück (erhöht Trefferwahrscheinlichkeit). Die drei Item-Typen sind
* Waffe (Schwert): Erhöht den Schaden des Helden
* Trank: Kann alle Attribute positiv oder negativ beeinflussen (z.B. +20 Stärke -5 Leben)
* Schild: Erhöht die Resistenz des Helden
Die jeweiligen Funktionen der einzelnen Items sind in der jeweiligen Item-Klasse implementiert. Alle Items erben von der Mutter-Klasse *Item* welche die Attribute
* name: Der Name des Items
* addSpeed: die Geschwindigkeit, welche das Item dem Spieler gibt
* addStrenght: die zusätzliche Stärke, welche das Item dem Spieler gibt
* addHealth: die Lebenspunkte, welche das Item dem Spieler gibt
und die generische Methode use().
Ein Schwert könnte dem Spieler so beispielsweise *+20* Strenght geben, solange es ausgerüstet ist.
Jedes Item kann sich entweder in einer Kiste, oder im Inventar des Spielers befinden. Die Modelle des Inventars und der Kiste werden im nächsten Abschnitt beschrieben. Waffen und Schilder befinden sich im Inventar des Helden, solange bis sie vom Spieler abgelegt werden. Sie werden nicht verbraucht. Tränke hingegen können nur einmal verwendet werden. Die Effekte des Trankes bleiben für eine bestimmte Zeit erhalten. Gegenstände können ausschließlich vom Helden aufgenommen werden. Effekte sind nicht auf Monster anwendbar.
Die OOP-Implementierung ermöglicht es, weitere Gegenstandstypen zu implementieren. Dies beinhaltet vor allem Fähigkeiten, welche sich ähnlich ausprägen wie Tränke. Sie bleiben jedoch dauerhaft bestehen und sich dafür etwas schwächer. Vorstellbar wäre ein Fähigkeiten-Buch, z.B. *Kunst des starken Schlags* welches nach dem lesen +5 Stärke verleiht.
### Inventar
Das Inventar des Helden besteht aus einer Liste an Gegenständen. Es können Gegenstände einzeln hinzugefüht und herausgenommen werden. Außerdem gibt es neben der Liste der Gegenstände noch zwei Ausrüstungsslots des Helden, in die jeweils ein Gegenstand gelegt werden kann. Die Effekte dieses Gegenstandes werden sofort angewendet. Der Held kann jederzeit die Gegenstände aus dem Inventar in einen Ausrüstungs legen oder andersherum. Solange sich ein Gegenstand in einem Ausrüstungsslot befindet werden dessen Effekte auf den Helden übertragen. Tränke, die ausgerüstet werden, werden sofort verbraucht. Das bedeutet, dass der jeweilige Effekt angewandt und der Gegenstand gelöscht wird. Der Slot ist dann wieder frei. Der Effekt des Trankes hält also nicht solange der Gegenstand ausgerüstet ist, sondern für eine gewisse Zeit.
Wenn das Inventar voll ist können keine weiteren Gegenstände mehr aufgenommen werden. Es ist nicht möglich Gegenstände des gleichen Typs auf einander zu legen. Jeder Gegenstand benötigt seinen eigenen Platz im Inventar. Wenn ein Spieler einen Gegenstand ablegt wird dieser gelöscht und kann nicht wieder aufgenommen werden. Die Zusammenhände zwischen Inventar, Held, Items und den weiteren Klassen ist in der folgenden Abbildung noch einmal visualisiert.

### Schatzkisten
Schatzkisten sind Gegenstands-Behhälter, welche sich im Dungeon verteilt befinden und unbeweglich sind. Sie haben in Grundzügen ähnliche Eigenschaften wie Charactere. Sie werden beim laden des Levels erzeugt und zufällig verteilt. Eine feste Anzahl an Schatzkisten pro Level ist nicht definiert. Beim Laden des Levels wird daher her eine in einem bestimmten Bereich liegende Anzahl an Schatzkisten erzeugt und verteilt. Die Gegenstände jeder Kiste werden ebenfalls zufällig erzeugt. Dabei ist nicht definiert, welchen Typs die Gegenstände sind, oder wie viele Gegenstände in einer Kiste liegen. Dies wird zufällig innerhalb festgelegter Parameter entschieden.
Der Held kann mit Ihnen interagieren, indem er an sie heran tritt, und Sie öffnet. Beim Öffnen einer Schatzkiste werden alle Gegenstände, welche sich in der Kiste befinden in das Inventar des Helden übertragen, aber nicht ausgerüstet. Die Kiste ist leer und bleibt dies auch bis zum Neustart des Levels. Es ist nicht möglich, Gegenstände wieder in Schatzkisten zurück zu legen. Der Held kann Gegenstände fallen lassen, welche damit verloren gehen.
### Taschen
Taschen verhalten sich wie kleine Inventare. Sie können eine bestimmte Anzahl an Gegenständen aufnehmen und wieder abgeben. Sowohl das Inventar des Helden, als auch Schatzkisten können Taschen enthalten. Sie weisen daher starke parallelen zu Gegenständen (Schwert,...) auf. Unterschiedlich von anderen Gegenständen ist der *Bag* jedoch, da er keine Effekte auf den Helden überträgt, sondern dessen Inventar erweitert. In diese Erweiterung können ausschließlich Items des selben Typs gelegt werden. Beispielsweise kann eine Tasche mehrere Schwerter enthalten, aber kein Schwert und einen Trank. Eine Tasche kann keine weitere Tasche enthalten. Gegenstände können frei zwischen dem Inventar des Spielers und einer Tasche verschoben werden, solange die Bedingungen dafür stimmen.
* Das Inventar des Spielers muss genug Platz für den Gegenstand bieten, der aus der Tasche genommen werden soll
* Die Tasche muss genug Platz für den Gegenstand haben, wenn dieser in die Tasche gelegt werden soll
* Der Typ des Gegenstands muss mit den anderen Gegenständen in der Tasche übereinstimmen
* Der Gegenstand, welcher in die Tasche gelegt werden soll ist selbst keine Tasche
## Umsetzung
Die Umsetzung erfolgte nach dem im letzten Abschnitt gezeigten Verfahren.
Das Inventar hat 10 belegbare Slots. Eine Tasche hat 5 belegbare Slots. Alle Kisten werden zum Spielstart an zufälligen Positionen erzeugt und enthalten zufällige Gegenstände. Dazu zählen auch leere Taschen. Jede Kiste kann zwischen 2 und 5 Gegenständen unbestimmten Typs enthalten.
---------
### Inventarwechsel
Das Inventar hat keine graphische Oberfläche, sondern kann in der Konsole eingesehen werden. Mit einem Rechtsklick wird der Inhalt des Inventars ausgegeben. Die Folgende Funktionalität wurde dazu in der update-Funktion des Helden eingebunden.
if (Gdx.input.isButtonJustPressed(Input.Buttons.RIGHT)){
if (inventar.printInventar()){
Scanner scan = new Scanner(System.in);
System.out.print("Gebe den Ausrüstungspaltz ein! (0 oder 1)\n");
String eingabe = scan.nextLine();
int ausruestungsPlatz = Integer.getInteger(eingabe);
if ((eingabe == "0") || (eingabe == "1")){
System.out.print("Gebe den Inventarplatz ein!\n");
String inventarplatz = scan.nextLine();
int index = Integer.getInteger(inventarplatz);
if (inventar.checkIndex(index)){
if (ausruestungsPlatz == 0){
inventar.swapItem(index, firstItem);
} else {
inventar.swapItem(index, secondItem);
}
}
}
scan.close();
}
}
##### printInventar()
* Gibt das Inventar des Helden aus beziehungsweise eine Meldung, wenn dieses leer ist
* Gehört der Klasse Iventar an
Die Eingaben *0* und *1* stehen dabei für die Item-Slots der Handgegenstände des Helden. Und können über die Konsole angegeben werden.
##### checkIndex()
+ Überprüft, ob es sich um einen gültigen Inventarplatz handelt
+ Gehört der Klasse Iventar an
##### swapItem()
+ Swapt Item aus Inventar mit Item aus den Handgegenstände des Helden
+ Gehört der Klasse Iventar an
---
Der Inhalt einer Kiste wird ausgegeben, wenn sich der Held nah an die Kiste bewegt. Dabei werden automatisch alle Items dem Iventar des Helden hinzugefügt.
## Postmortem
In diesem Teil des Lerntagebuches soll noch einmal auf die Umsetzung und das Vorgehen bezüglich der Aufgabenstellung zurückgeblickt werden.
### Positive Aspekte
Rückblickend lässt sich zusammenfassen, dass sämtliche Aufgabenstellungen zufriedenstellend erfüllt werden konnten. Konkret umfasst das:
* Vorläufige Planung und Modellierung der Praktikumsaufgabe
* Refactoring gewisser Codeanteile
* Das Erschaffen einer Item-Klasse, auf der das Item-System basiert
* Einbinden einer Inventar-Klasse für den Helden
* Erschaffen von Truhen, welche Items an den Helden ausgeben
* Ausgeben der Inventarliste des Helden in der Konsole
* Ausrüsten des Helden mit den Items aus dem Inventar
* Verstärken der Heldenfähigkeiten beim Aufnehmen dieser Items
* Einbinden eines Angriffs mit dem Helden bei einer Benutzereingabe (linke Maustaste)
### Gelernte Aspekte
+ Noch konkretere Verteilung der Arbeitsparkete
+ So kann die Effizienz noch weiter gesteigert werden
### Herausforderungen
Als Herausforderung stellte sich heraus, dass sich die Wissenslücken in Java zum Teil bemerkbar machen und bezüglich der Entwicklungsarbeit zusätzliche Motivation erfordern. Dies ist nicht zuletzt dem Fakt geschuldet, dass die Vorlesungsinhalte dieses Moduls sich naträglich erarbeitet werden müssen, da aufgrund von Vorlesungsüberschneidungen im Master und Bachelor, die Vorlesung nicht wahrgenommen werden kann.
# Blatt 4
## Aufgabe
In diesem Aufgabenblatt soll ein Head-Up-Display und Fallen implementiert werden. Zusätzlich soll der Held nun in der Lage sein, Erfahrungspunkte und Skills zu erlangen, indem Monster getötet werden.
## Ansatz und Modellierung
### HUD
Die HUD besteht aus mehreren Elementen die jeweils in eigenen Klassen definiert sind. Dazu gehören
- die Lebensanzeige
- die Anzeige der Erfahrungspunkte
- die Anzeige des Levels des Helden
- das Inventar
- der Inhalt geöffneter Kisten
- die Ausrüstung des Helden
von diesen Elementen sollen nur die ersten drei dauerhaft angezeigt werden. Das Inventar des Helden wird, genau so wie eine Kiste, auf Knopfdruck geöffnet.
Die Lebensanzeige so wie die Anzeige der Erfahrungspunkte (XP-Anzeige) funktionieren gleich. Die Positionen der Anzeigen sind über den gesamten Spielverlauf festgelegt, Sie befinden sich unten rechts im Bild, übereinander liegend. Da sich sowohl der Gegenstand der Anzeige (Lebens- oder Erfahrungspunke), als auch der jeweils maximale Wert ändern kann muss die Länge der Anzeige selbst, sowie der Container, in welchem sich die Anzeige befindet, Variabel sein.
Das HUD des Inventar, sowie das der Kisten wird im Spiel beliebig oft angezeigt und wieder gelöscht. Dabei sollen die einzelnen Inventar-/Kistenplätze als Slots übereinander angezeigt. Diese sind mit dem entsprechenden Item gefüllt, welches der Spieler bzw. die Kiste im entsprechenden Inventarplatz hat. Wenn der Spieler/Kiste kein Item im Inventar-Platz hat, dann ist der Slot leer. Eine besondere Rolle spielen Taschen im Inventar des Helden, da sich hier noch weitere Gegenstände befinden können. Daher werden neben einem Inventarplatz, in welchem sich eine Tasche befindet, noch weitere vier Slots mit den entsprechenden Gegenständen der Tasche angezeigt.
Die Gegenstände, welche der Held in der Hand hält werden immer angezeigt. Es muss möglich sein, bei geöffnetem Inventar Gegenstände zwischen Inventar und Ausrüstung zu tauschen und dies anzuzeigen, ohne das Inventar neu zu laden.
### Erfahrung und Skills
Das Erfahrungen- und Skillssystem wird direkt in der MyHero-Klasse realisiert, da die Monster diese Attribute nicht besitzen sollen. Das heißt es wird explizit nicht die bereits vorgestellte Klasse *Attributes* verwendet.
*Grundsätzliche Idee:*
Grundlegend soll das Erfahrungspunktesystem so funktionieren, dass der Held Erfahrungspunkte bekommt, sofern dieser ein Monster tötet. Ist eine bestimmte Anzahl an Erfahrungspunkten erreicht, so erhöht sich das Level des Helden und dieser hat nur noch die überschüssigen Erfahrungspunkte, welche für das *Level-Up* nicht verwendet wurden.
Mit jedem Level sollen sich die Attribute des Helden (Angriff, Leben und Resistance) aufbessern. Dabei hängt das Ausmaß der Verbesserung vom erreichten Level des Helden ab. Gleiches gilt allerdings auch für die Erfahrungspunkte des Helden, welcher dieser für ein erneutes Aufleveln benötigt. So soll ein Aufleveln immer schwieriger werden.
Zuletzt wurde sich noch überlegt dem Helden spezielle Fähigkeiten zu übergeben, wenn dieser die Level 2 und 5 erreicht hat.
*Ansatz*
Prinzipiell ist es wichtig bei dem System darauf zu achten, dass der Held nur in dem Moment Erfahrungspunkte bekommt, in dem das Monster auch gestorben ist. Es darf also nicht konstant Erfahrung generiert werden, wenn ein Monster tot ist, das Leben also auf 0 ist. Eine Art Zustand *just died* bezüglich der Monster ist also von Bedeutung, um ein einmaliges generieren von Erfahrungspunkten zu erzeugen.
Ferner gilt es eine Unterscheidung zwischen Monstertypen vorzunehmen, wenn es um die Anzahl der vergebenen Erfahrungspunkte geht. Die Fähigkeiten, welcher der Held freischalten kann, soll der Held ebenfalls schon von Anfang an in seiner Klasse besitzen. Er kann nur erst auf diese zugreifen, wenn sein Level groß genug ist. In dem Fall wird ein Flag gesetzt und die Fähigkeit soll genutzt werden können. Als spezielle Fähigkeiten wurden sich sprinten und teleportieren überlegt.
### Fallen
Fallen werden als eigene Klassen erstellt, die jeweils wieder IAnimatable und IEntity implementieren. Im Rahmen dieses Blattes werden Spikes und ein Loch implementiert.
*Grundsätzliche Idee:*
Betritt der Held ein Loch, so verliert dieser sein gesammtes Inventar bzw. lässt dieses im Loch zurück. Betritt der Held ein Spikes-Feld, wird ihm pro Frame ein gewisser Anteil von Lebenspunkte genommen. Verlässt der das Feld wieder, ist der negative Effekt nicht mehr vorhanden.
*Ansatz:*
Der jeweiliegn Falle wird, wie im Falle der Truhe, eine Referenz auf die Position des Helden gegeben. Bei jedem Aufruf der update-Funktion wird von der Falle überprüft, ob sich der Held auf ihr befindet und führt dann die jeweilige Aktion aus.
*Spezielle Referenzen:*
Dem Loch muss zusätzlich einmalig eine Referenz auf das Inventar-Objekt des Helden übergeben werden. Wird durch Betreten des Feldes die Aktion ausgeführt, wird die clearInventar Methode der Inventar-Klasse ausgeführt.
Die Spikes benötigen eine Referenz auf das Objekt der Attribute des Helden, das diesen einmalig im setup- Aufruf mitgegeben wird.
*Sonstiges:*
Die Fallen werden wie die Kiste bei Start eines neuen Levels zufällig im Dungeon verteilt. Hierzu wird eine Methode implementiert, sie in der onLevelLoad Methode des mainControllers ausgeführt wird.Die Spikes werden als Animation ausgeführt, das Loch besitzt keine Animation.
## Umsetzung
### HUD
Die Lebens- und XP-Anzeige basieren auf der gleichen Klasse *Bar*. Zum Spielstart werden die jeweiligen Anzeigen mit den entsprechenden Containern an der gewünschten Position und mit der start-Länge erzeugt. Es wird dann in jedem Frame überpräft, ob sich die Attribute des Helden verändert haben. Die Werte werden dann im entsprechenden Objekt verändert. Ist dies für alle Elemente geschehen, dann wird die HUD gezeichnet. Dieser Ablauf ist in der folgenden Abbildng dargestellt.

Das Inventar soll nur dargestellt werden, wenn der Held den Tastendruck der Taste "I" registriert. Es wird dann ein Flag gesetzt, welches im MainController ausgewertet wird. Wenn das Inventar neu gezeichnet werden soll, dann werden Informationen über den Inhalt des Inventars vom Helden abgerufen. Diese Informationen werden an die Funktion *build* der Klasse *InventoryHUD* übergeben. Diese Klasse ist dafür zuständig, das Inventar komplett zu bauen. Es wird eine Liste erzeugt, an die alle zu zeichnenden Elemente angehängt werden. Dies wird in einer Schleife getan, in der zunächst der Slot erzeugt wird und dann das entsprechende Item. Ist dieses Item eine *Tasche*, dann werden die vier Slots der Tasche mit den entsprechenden Items ebenfalls erzeugt. Der Ablauf ist in der folgenden Abbildung dargestellt.

Die Texturen werden im MainController in einer Liste gespeichert, um sie später auf Knopfdruck wieder zu löschen.
Analog dazu funktioniert auch die HUD der Kisten. Diese wird mit *White_space* geöffnet und schließt sich automatisch, wenn der Held sich entfernt
### Fallen
Die Fallen konnten ohne weitere Probleme wie in der Modellierung geplant umgesetzt werden. Kern der Implementierung ist die Trigegrung der Falle, die wie unterhalb dargestellt, durch Berechnung der euklidischen Distanz zum Helden berechnet wird.
public void checkTrigger()
{
//Mindestabstand
float collisionThreshhold = 0.8f;
float euclidDis;
//Distanz zur Falle
float DisX = position.x - this.HeroPosition.x;
float DisY = position.y - this.HeroPosition.y;
euclidDis = (float) Math.sqrt(Math.pow(DisX, 2) + Math.pow(DisY, 2));
if (euclidDis < collisionThreshhold) {
this.triggered = true;
} else {
this.triggered = false;
}
}
### Erfahrung und Skills
In diesem Codebeispiel soll ersichtlich werden, wie das System umgesetzt wurde. Mit *SkillUnlock* können besagte Flags gestzt werden und der Hero kann in seiner Update-Funktion auf die genannten Fähigkeiten zugereifen. Der *LevelUpBuff* berechnet die Aufbesserung der Heldenattribute in Abhängigkeit des Levels. Die Funktion *calcLevel* würde im Moment des Sterbens eines Monster im MainController aufgerugen und einen Monstertyp als String übergeben bekommen. Abhängig von diesem Typ würde die Erfahrung durch eine HashMap aufgelöst und auf die Erfahrung des Helden addiert. Dann wird in der Schleife geschaut, ob der Held genügend Erfahrung für ein LevelUp hat, sofern dies der Fall ist wird die Level-Up-Erfahrung konstant abgezogen, bis diese für ein Level-Up nicht mehr ausreicht. Gleichzeitig erhöht sich dabei die benötigte Erfahrung beziehungsweise der Held bekommt ein neues Level. Mit diesem Level wird dann die *LevelUpBuff*-Funktion aufgerufen, um die Attribute entsprechend aufzubessern. Ein eventuelles Setzen der Skill-Flags wird ebenfalls überprüft, dazu wird *SkillUnlock* in der Schleife überprüft.
private void SkillUnlock(int lvl)
{
if(lvl >= 2)
{
LevelTwoSkill = true;
}
if(lvl >= 5)
{
LevelFiveSkill = true;
}
}
private void LevelUpBuff(int lvl)
{
this.heroStats.setStrength(this.heroStats.getStrength()+(lvl*2));
this.heroStats.increaseMaxHealth(lvl*30);;
this.heroStats.setResistance((float)(this.heroStats.getResistance()+(lvl*0.01)));
}
public void calcLevel(String MonsterType)
{
int LevelUpExp = 10 * this.HeroLevel;
this.experience = this.experience + MonsterExpIndex.get(MonsterType);
while(this.experience >= LevelUpExp)
{
this.experience = this.experience - LevelUpExp;
this.HeroLevel++;
LevelUpBuff(this.HeroLevel);
SkillUnlock(this.HeroLevel);
LevelUpExp = 10 * this.HeroLevel;
}
}
}
## Postmortem
In diesem Teil des Lerntagebuches soll noch einmal auf die Umsetzung und das Vorgehen bezüglich der Aufgabenstellung zurückgeblickt werden.
### Positive Aspekte
Rückblickend lässt sich zusammenfassen, dass sämtliche Aufgabenstellungen zufriedenstellend erfüllt werden konnten. Konkret umfasst das:
* Implementierung einer übersichtlichen HUD mit Lebensanzeige und Erfahrungspunkten
* Erfahrungspunktesystem für den Helden
* Verbessern der Heldenattribute durch Aufleveln
* Freischalten von Fähigkeiten durch das Aufleveln (In diesem konkreten Fall Level 2 und 5)
* Implementierung dieser konkreten Fähigkeiten
* Einbinden von Fallen in den regulären Spielfluss
* Interaktionen der Fallen mit Helden
### Gelernte Aspekte
+ Aneignen des Arbeiten mit Branches bzw. Branchingstrategien
+ Dadurch verbessertes Zeitmanagment und effizientere Aufteilung der Arbeitspakete
+ Erkannt, dass die universelle Vergabe von Objektreferenzen, sowohl lesend als auch schreiben, ab einer gewissen Komplexität des Gesamtsystems ohne vorherige Systemmodellierung recht aufwendig und in gewisser Weise "nicht sauer" ist. Die Anwednung von Design Pattern, wie des Fabric Pattern, könnte diese Referenzen zentral vergeben.
### Herausforderungen
Als Herausforderung stellte sich heraus, dass sich die Wissenslücken in Java zum Teil bemerkbar machen und bezüglich der Entwicklungsarbeit zusätzliche Motivation erfordern. Dies ist nicht zuletzt dem Fakt geschuldet, dass die Vorlesungsinhalte dieses Moduls sich naträglich erarbeitet werden müssen, da aufgrund von Vorlesungsüberschneidungen im Master und Bachelor, die Vorlesung nicht wahrgenommen werden kann.
# Blatt 5
## Aufgabe
In diesem Aufgabenblatt soll ein Questsystem erarbeitet werden. Dieses Sytem soll verschiedene Quests beinhalten und in dem HUD angezeigt werden können. Außerdem soll mit JUnit Testfälle erstellt und durchsimuliert werden.
## Ansatz und Modellierung
### Quests
**Grundsätzliche Idee:**
Für die Quests muss sich zunächst überlegt werden, was sich überhaupt als Aufgabe für den Helden im Dungeon anbietet. Dies müssen Aufgaben sein, die zum einen definitiv erfüllbar seien müssen, zum anderen müssen diese dem Spieler in einer geeigneten Form angeboten werden können. Es ist also von Relevanz die Quests sorgfältig zu designen und dem Spiel eine zusätzliche Insatnz hinzuzufügen, die dem Spieler die Quests anbietet. Die aktuelle Quest soll dem Helden ebenfalls über das HUD angezeigt werden.
**Ansatz:**
Für die ersten Versuche wurde sich dazu entschieden vorerst möglich einfache Quests zu implementieren, um das gesamte Questsystem an sich erst einmal grundlegend validieren zu können. In diesem Rahmen wurde sich dazu entschieden eine kampfabhängige und eine kampfunabhängige Quest dem Spiel hinzuzufügen. Das bedeutet konkret, dass eine Quest eingebaut wurde, bei der 3 Monster getötet werden müssen und eine Quest, bei der Dungeon-Level 3 erreicht werden muss.
Bezüglich des Questsystems an sich müssen die Quests in einer Art angenommen werden können und sollen danach unter "Kontrolle" stehen, der aktuelle Stand wird dazu also "getrackt". Ist eine Quest abgeschlossen wird eine Art "Flag" gesetzt und die Quest wird nicht weiterhin "getrackt". Dieses Flag dient auch dazu dem Helden seine Belohnung zu überreichen.
Das Annehmen der Quests soll durch einen weiteren Nebencharakter im Dungeon geschehen. Dem sogenannten "Questmaster". Mit diesem kann ein Dialog begonnen werden, sobald sich der Spieler in dessen Nähe befindet. Die Quest kann dann ausgewählt werden und angenommen werden und der Fortschritt wird durch den Questmaster überwacht. Um die Fortschrittsüberwachung möglichst dymamisch für alle Quests zu implementiern wird Observer-Pattern verwendet.
### Tests
Das Testkonzept sieht Modul, Integration und System-Tests vor.
In den Modultests werden einzelne Klassen und deren Funktionen getestet. Die getesteten Klassen sind *MyHero*, *Demon*, *Zombie* und *Attribute*. Die Klasse *Inventar* wird im Test für *MyHero* mitgetestet und die Klasse *Item* wird in den Tests zu den Attributen mitgetestet. Bei den Tests werden die Attribute der verschiedenen Klassen abgefragt, bevor und nachdem sie durch die verschiedenen Funktionen verändert worden sind.
Die Integrationstests stellen die Korrektheit der Zusammenarbeit verschiedener Klassen sicher. Dabei werden zum Beispiel die Attribute des Helden abgefragt, wenn er ein Levelup nach einem Kampf erhält.
Die Systemtests sind dafür gedacht, die Funktion des Systems als ganzem zu Testen. Dabei wird nicht mehr auf einzelne Funktionen geachtet, sondern der Verlauf des Spiels selbst untersucht. Das generelle Verhalten des Spiels ist dabei relevant. Testgegenstand ist die Klasse *TheAwesomeGame*
## Umsetzung
In der nachstehenden Grafik ist einmal grundlegend das Konzept hinter dem Questsystem dargestellt. Das Interface "Observer" würde dort einmal in beiden Quest-Klassen implementiert, diese haben dann ihrerseits die "update"-Funktion. Über die update-Funktionen würde dann jedes Mal ein Fortschritt bezüglich einer Quest signalisiert. Das heißt, wenn ein für die Quest relevantes Ereignis passiert (Level-Fortschritt, Monster getötet), würden über notifyObservers des Questmasters alle update-Funktionen aufgerufen und je nach Ereignis die geeignete Quest um einen Schritt vorangebracht. Das heißt es würde entweder monsterKilled oder levelReached geupdated. Dies passiert mit der questProgress-Fuktion im Obeserver, welche je nach Quest-Typ die richtige Quest aktualisiert. Im nächsten Schritt wird in den update-Funktionen dann geschaut, ob die Quest damit erfüllt wurde. Dies passiert mit checkForQuestEnd. Ist die Quest erfüllt, wird an die übergebene MyHero-Insatnz die Belohnung überreicht. Im aktuelleb Fall sind das Erfahrungspunkte.
Der Questmaster verwaltet sämtliche Quests. Kommt der Held im Dungeon zu diesem und akezeptiert eine Quest, so wird diese mit register unter Aufsicht gestellt und kann dann beim entsprechend Event über notifyObservers geupdatet werden.

### JUnit-Einbindung
Die Tests werden in JUnit4 implementiert und in ant integriert. Dabei sollen mit dem Befehl *ant test* alle Tests automatisiert ausgeführt werden. Die Testberichte werden für die Tests einzeln erzeugt und müssen in **xml** vorliegen. Sie werden in das output-Verzeichnis in den Ordner *test-results* gelegt. Die Tests selbst werden so umgesetzt, wie in der Modellierung beschrieben. An dieser Stelle soll noch einmal an die unsterblichen Worte von BIG SHAQ erinnert werden:
> "Man can never be hot" -Big Shaq
Die umgesetzten Testklassen sind:
- ModuleTests.AttributeTests
- ModuleTests.HeroTests
- ModuleTests.DemonTests
- ModuleTests.ZombieTests
- IntegrationTests
- Systemtests
## Postmortem
In diesem Teil des Lerntagebuches soll noch einmal auf die Umsetzung und das Vorgehen bezüglich der Aufgabenstellung zurückgeblickt werden.
### Positive Aspekte
Rückblickend lässt sich zusammenfassen, dass sämtliche Aufgabenstellungen zufriedenstellend erfüllt werden konnten. Konkret umfasst das:
* Das Einbauen des Questsystems
* Das anbieten unterschiedlicher Quests
* Das updaten der Quests sowie das Überprüfen eines erfolgreichen abschließens
* Anzeigen der Quests in dem HUD
* Das verwenden des Oberserver-Patterns diesbezüglich
* Erstellen von Testfällen mit JUnit
* Das erfolgreiche Testen mit diesen Tests
### Gelernte Aspekte
+ Motivation und Ehrgeiz zahlen sich aus (Junits-Tests liefen nach mehreren Anläufen)
+ Testen ist genauso wichtig wie coden