<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://wiki.stageing.freitagsrunde.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=130.149.236.90</id>
	<title>FreitagsrundenWiki - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.stageing.freitagsrunde.org//api.php?action=feedcontributions&amp;feedformat=atom&amp;user=130.149.236.90"/>
	<link rel="alternate" type="text/html" href="wiki.stageing.freitagsrunde.org//Spezial:Beitr%C3%A4ge/130.149.236.90"/>
	<updated>2026-11-02T16:00:22Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.45.6</generator>
	<entry>
		<id>wiki.stageing.freitagsrunde.org//index.php?title=Javakurs/%C3%9Cbungsaufgaben/AsciiCraft&amp;diff=17712</id>
		<title>Javakurs/Übungsaufgaben/AsciiCraft</title>
		<link rel="alternate" type="text/html" href="wiki.stageing.freitagsrunde.org//index.php?title=Javakurs/%C3%9Cbungsaufgaben/AsciiCraft&amp;diff=17712"/>
		<updated>2012-03-09T11:55:58Z</updated>

		<summary type="html">&lt;p&gt;130.149.236.90: /* Installation */  tar file geupdated&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Eine Komplexe Aufgabe, die Codelesen vertiefen soll, den Kurs zusammenfasst und einen etwas größeren Umfang als andere Aufgaben bietet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Aufgabe =&lt;br /&gt;
&lt;br /&gt;
Im Folgenden wird Schritt für Schritt erklärt werden, wie das Spiel AsciiCraft, eine Anlehnung an [http://www.minecraft.net/ Minecraft], geschrieben wurde. Ziel ist es in dieser Aufgabe Quellode zu lesen, diesen zu verstehen und diesen durch Erweiterungen an eigene Vorlieben anzupassen. Dazu wirde es keine Konkreten Aufgaben geben, ziel ist es eher euch einen Plattform für eigene Experimente zu geben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
[[Bild:asciicraft.png|thumb|280px|Javakurs 2011 - AsciiCraft]]&lt;br /&gt;
Um das Programm zu verstehen, ist es wichtig, dass man eine Vorstellung bekommt, was es eigentlich tun soll. Daher bietet es sich an, dieses auf seinem Rechner/Account zu installieren. Bitte ladet euch dafür&lt;br /&gt;
das [http://docs.freitagsrunde.org/Veranstaltungen/javakurs_2011/uebungen/Javakurs2011-AsciiCraft_V2.tar.gz Archiv von unserem Server] herunter.&lt;br /&gt;
&lt;br /&gt;
In diesem Archiv (zu entpacken mittels &#039;&#039;tar -xf&#039;&#039;, oder per grafischer Oberfläche (Linkklick auf das Archiv)) findet ihr einen Ordner und drei Skripte. Die Skripte sind zum compilieren, ausführen und löschen der Kompilate da und sollten selbsterklärend sein. Der Ordner &#039;&#039;src&#039;&#039; beinhaltet den Quellcode und wird später für uns sehr interessant werden.&lt;br /&gt;
&lt;br /&gt;
Ihr solltet nun das Projekt kompilieren (&#039;&#039;./build.sh&#039;&#039;) und es dann einmal starten (&#039;&#039;./run.sh&#039;&#039;, von der Kommandozeile aus).&lt;br /&gt;
&lt;br /&gt;
Nun solltet ihr ein ähnliches Bild wie das hier abgebildete zu sehen sein. &lt;br /&gt;
&lt;br /&gt;
Ist dies nicht der Falls, solltet ihr die Ausgaben kontrollieren und eventuelle Fehler einem Tutor melden. Auch könntet ihr probieren die Kommandozeilen Optionen euch anzusehen: &lt;br /&gt;
 &lt;br /&gt;
 ./run.sh -h&lt;br /&gt;
&lt;br /&gt;
= Ziel des Spieles: ❁ =&lt;br /&gt;
&lt;br /&gt;
Nach dem ihr im letzten Abschnitt erfolgreich das Spiel installiert und kompiliert habt, ist es nun an der Zeit die Aufgabe des Spieles kennen zu lernen: Euer Ziel ist es mit dem kleinen Pfeil (meist in der Mitte der Konsole) den Diamanten aus dem Bergwerk zu fördern. &lt;br /&gt;
&lt;br /&gt;
Dieses Ziel erreicht ihr, in dem ihr mit den Tasten &#039;&#039;A&#039;&#039; und &#039;&#039;D&#039;&#039; euch nach &#039;&#039;links&#039;&#039; oder &#039;&#039;rechts&#039;&#039; bewegt. Da ihr an der Oberfläche den Diamanten nicht finden können wird, müsst ihr mit den folgen Tasten euch in den Berg eingraben:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;E&#039;&#039; .. baut das Feld direkt über dem Spieler ab&lt;br /&gt;
* &#039;&#039;R&#039;&#039; .. gräbt das Feld ein Feld über dem das ihr anschaut an.&lt;br /&gt;
* &#039;&#039;F&#039;&#039; .. gräbt in die Richtung in die ihr gerade schaut.&lt;br /&gt;
* &#039;&#039;C&#039;&#039; .. Analog zu &#039;&#039;R&#039;&#039; legt das Feld eins unter dem Feld das ihr anschaut frei.&lt;br /&gt;
* &#039;&#039;X&#039;&#039; .. Gräbt das Feld direkt unter euch ab (&#039;&#039;Achtung: Mit Vorsicht zu genießen!!!&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
Damit ihr auch evtl. wieder nach oben gelangen könnt, kann der Spieler mit der Leertaste (&#039;&#039; &#039;&#039;) springen, aber nur, wenn dafür genug Platz frei ist.&lt;br /&gt;
&lt;br /&gt;
Die &#039;&#039;Pfeiltasten&#039;&#039; und &#039;&#039;Esc&#039;&#039; sorgen dafür, dass sofort das Programm beendet wird und der GameOver-Bildschirm angezeigt wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sobald ihr euch einen Weg zum Diamanten gegraben habt, müsst ihr ihn nur noch ausgraben, um zum Ende des Spieles zu kommen.&lt;br /&gt;
&lt;br /&gt;
= Konzept des Codes =&lt;br /&gt;
&lt;br /&gt;
Um diese Aufgabe erfolgreich und sinnvoll zu bearbeiten, ist es am besten, wenn ihr diesen Aufgabentext parallel zum Code offen lasst, damit ihr schnell zwischen der Beschreibung und dem Code hin und her schalten könnt.&lt;br /&gt;
&lt;br /&gt;
Dieser Code wurde designed, damit er möglichst viele Techniken einsetzt, die ihr schon kennen solltet. Es wurde des Weiteren versucht den Code zu dokumentieren und zu kommentieren. So werdet ihr nicht nur die Vererbeung wiederfinden, sondern auch die Kapselung, Schleifen, Arrays, Ausgabe, Variablen und eigentlich Alles was ihr wissen müsst.&lt;br /&gt;
&lt;br /&gt;
Basisidee ist die der Wiederverwendung. Es wurde versucht alle Klassen die an dem Programm beteiligt sind so zu gestallten, dass sie möglichst leicht auszutauschen sind. So lässt sich ohne großen Aufwand weitere Felder hinzufügen. Doch nun zu den bereits vorhandenen Klassen. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Pakete ==&lt;br /&gt;
Die Klassen die an dem Spiel beteiligt sind, findet ihr unter &#039;&#039;src/...&#039;&#039; alle Klassen sind unter dem gleichen Paket gespeichert: &#039;&#039;javakurs2011.asciicraft&#039;&#039;. Wobei ein Paket eine Unterteilung von Klassen ist. So ist es möglich, dass es Klassen gibt, die gleich heißen, aber in anderen Paketen definiert wurden. &lt;br /&gt;
&lt;br /&gt;
Eine Klasse markiert man als zu einem Paket gehörend, in dem man es in einen Unterordner der Form &#039;&#039;paket/unterpaket&#039;&#039; steckt. Des Weiteren muss jede Klasse am Anfang seiner .java Datei einen Eintrag wie folgt haben: &#039;&#039;package paket.unterpaket;&#039;&#039;, welches dafür sorgt, dass die Klasse auch als zu dem Paket gehörig erkannt wird.  (bitte beachtet, dass der &#039;&#039;/&#039;&#039; in der JavaDatei durch einen Punkt (&#039;&#039;.&#039;&#039;) ersetzt wurde.) Die Technik der Pakete wird meist in größeren Produktionen eingesetzt und wird euch in eurem weiteren Studium bestimmt noch häufiger begegegen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Abstrakte Klasse &#039;&#039;Tile&#039;&#039; ==&lt;br /&gt;
[[Bild:AsciiCraftTiles.png|thumb|280px|Invisible, Player, Diamond, Coal, Iron und Dirt &#039;&#039;Tile&#039;&#039;s]]&lt;br /&gt;
&lt;br /&gt;
Jedes der Felder, die ihr im Spiel seht, ist abgeleitet von der &#039;&#039;&#039;abstrakten&#039;&#039;&#039; Klasse &#039;&#039;Tile&#039;&#039; (konkret &#039;&#039;AirTile.java  CoalTile.java  DiamondTile.java  DirtTile.java  IronTile.java&#039;&#039;, in allen steht bei der Klassendefinition die Zeile &#039;&#039;extends Tile&#039;&#039;). Der Sinn dahinter ist, dass ihr in der abstrakten Klasse Methoden angebt, die von allen Unterklassen implementiert werden &#039;&#039;müssen&#039;&#039;. Dieser Mechanismus macht es möglich, dass man im Folgenden von der genauen Implementierung der Klasse (bspw. &#039;&#039;IronTile&#039;&#039;) abstrahiert und dieses nur noch als &#039;&#039;Tile&#039;&#039; auffasst.&lt;br /&gt;
&lt;br /&gt;
Dies wird etwas deutlicher, wenn man sich vor Augen hält, wie das Spielfeld aussieht: In der Datei &#039;&#039;World.java&#039;&#039; wird in &#039;&#039;Zeile 14&#039;&#039; ein Feld von mehreren Objekten der Klasse &#039;&#039;Tile&#039;&#039; erzeugt. Das bedeutet, dass man in diesem Array alle Unterklassen, also alle Klassen, die von &#039;&#039;Tile&#039;&#039; erben, speichern kann, und alle mindestens die Funktionalitäten von &#039;&#039;Tile&#039;&#039; anbieten. In unserem Fall ist dies noch sehr wenig, da lediglich eine Methode, die &#039;&#039;toString&#039;&#039;-Methode, von Tile als zu implementieren gekennzeichnet wurde. Vorstellbar ist aber, dass in einem späteren Zeitpunkt jedes &#039;&#039;Tile&#039;&#039; einen neue Funktionalität haben soll, wie dass beim Abbauen des Tiles eine bestimmte Methode ausgeführt werden soll. Diese Methode könnte zum Beispiel &#039;&#039;mine()&#039;&#039; heißen und könnte dafür sorgen, dass das &#039;&#039;IronTile&#039;&#039; zwei Versuche braucht um abgebaut zu werden.&lt;br /&gt;
&lt;br /&gt;
== Die Welt ==&lt;br /&gt;
Wie bereits im vorherigen Kapitel erwähnt, speichert die Klasse &#039;&#039;World&#039;&#039; alles was zur Spielwelt gehört. Dies ist nicht nur die Größe des Spielfeldes, die Spielfelder selbst, sondern auch den Spieler. Der Spieler ansich ist auch nur ein klügeres &#039;&#039;Tile&#039;&#039;. So kann er zwar genau wie anderer &#039;&#039;Tiles&#039;&#039; auch angezeigt werden, siehe &#039;&#039;toString()&#039;&#039;, aber er kann auch in der Methode &#039;&#039;simulate()&#039;&#039; sich den aktuellen Gegebenheiten anpassen. So wird gegenwärtig diese Methode dazu genutzt den Spieler auf den Boden fallen zu lassen, sobald er auf einem &#039;AirTile&#039;&#039;-Feld steht. Damit das Programm diese Entscheidung treffen kann, muss es wissen auf welcher Welt er sich befindet, also wird der &#039;&#039;simulate&#039;&#039;-Methode die Welt als Parameter mit angegeben.&lt;br /&gt;
&lt;br /&gt;
Dies Welt ist des Weiteren auch für das Anzeigen und Erstellen der neuen Spielwelt zuständig. Anzeigen tut sie, indem sie zuerst durch das Feld der &#039;&#039;Tiles&#039;&#039; geht und jedes aus dem Array heraus nimmt und dessen &#039;&#039;toString()&#039;&#039;-Methode implizit aufruft. (vgl. Zeile 154 in World.java, dort wird nicht .toString() benutzt, sondern implizit das Tile in einen String durch addieren des Tiles zu einem String, aufgerufen). Das ganze passiert jedoch nur, falls das Tile überhaupt sichtbar (&#039;&#039;.isVisible()&#039;&#039; liefert &#039;&#039;true&#039;&#039;) ist. Ist dies nicht der Fall wird lediglich ein graues Viereck angezeigt. Das Tile ist nur dann nicht sichtbar, wenn es bisher noch nicht entdeckt worden ist und unterhalb der Oberfläche liegt.&lt;br /&gt;
&lt;br /&gt;
Dies führt uns zur Erstellung des Spielfeldes. Das Spielfeld wird in der Zeile 48 der Datei &#039;&#039;World.java&#039;&#039; erzeugt. Das Erstellen des Feldes basiert sehr stark auf &#039;&#039;kontrolliertem&#039;&#039; Zufall: So wird in Zeile 50 zunächst das gesamte Spielfeld auf &#039;&#039;Luft&#039;&#039; gesetzt. Dies wird erreicht, indem an jedem Index des Feldes ein neues Element vom Typ &#039;&#039;AirTile&#039;&#039; erstellt wird. Ein Teil dieser Luft-Teile wird im Folgenden durch zufällige &#039;&#039;DirtTiles&#039;&#039; ersetzt. Basis dafür ist dass innerhalb der for-Schleife in Zeile 56 an einer zufälligen Höhe nahe der Hälfte des Spielfeldes für jeden Spalteneintrag neu bestimmt wird, ob das Tile nach oben oder unten plaziert werden soll. Nachdem die Höhe des &#039;&#039;Horizontes&#039;&#039; erstellt wurde, werden alle folgenden Teile auch als &#039;&#039;DirtTiles&#039;&#039; erstellt.&lt;br /&gt;
&lt;br /&gt;
Sobald alle &#039;&#039;DirtTile&#039;&#039;s erstellt wurden, werden erneut alle &#039;&#039;DirtTiles&#039;&#039; angefasst (Zeile 72) und zufällig durch entweder ein &#039;&#039;IronTile&#039;&#039; oder ein &#039;&#039;CoalTile&#039;&#039; ersetzt.&lt;br /&gt;
&lt;br /&gt;
Nun sind prinzipiell alle &#039;&#039;normalen&#039;&#039; Tiles erstellt und die Welt ansich ist einsatzbereit. Nun der Spaß des Programmes beginnt dann, wenn man die Welt langsam anfängt zu erforschen. Daher müssen noch alle Tiles auf &#039;&#039;unsichtbar&#039;&#039; gesetzt werden, die nicht direkt an der Oberfläche liegen. Das passiert, in dem für alle Spalten des Feldes gezählt wird, wieviele nicht-&#039;&#039;AirTiles&#039;&#039; bereits gefunden wurden. Ist diese Zahl größer als eins, bedeutet dies, dass wir unterhalb der Oberfläche sind, und somit, zumindest initial alle Tiles unsichtbar sind. Diese Annahme gilt nur, wenn wir keine Überhänge in der Oberwelt zulassen.&lt;br /&gt;
&lt;br /&gt;
Nun wird der Diamant plaziert. Dies passiert auch wieder sehr zufällig, indem einfach eine zufällige Position eines &#039;&#039;DirtTile&#039;&#039;s gesucht wird, die nahe am unteren Ende des Spielfeldes liegt. &lt;br /&gt;
&lt;br /&gt;
Nach dem Der Diamant gesetzt wurde, wird versucht, den Spieler leicht mittig auf dem Feld zu plazieren, indem nach einem &#039;&#039;AirTile&#039;&#039; in der Mittleren Spalte gesucht wird. Wurde kein Leeres Tile gefunden, so wird es bei der nächsten Spalte weiter probiert. Vorstellen kann man sich dies wie bei dem alten &#039;&#039;VierGewinnt&#039;&#039;-Spiel: Der Spieler wird in einer Spalte herein geworfen und geschaut, ob er gleich wieder oben heraus fällt. Ist dies der Fall wird er einfach bei der nächsten Spalte eingeworfen und das ganze nochmal probiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Interaktion == &lt;br /&gt;
&lt;br /&gt;
Nachdem nun die Welt erstellt wurde, wir nun wissen wie wir sie anzeigen können, ist das Einzige was noch fehlt die Interaktion mit ihr. Zum Anfang des Programmes wird, wie bereits bekannt, die &#039;&#039;main&#039;&#039;-Methode ausgeführt (siehe &#039;&#039;Main.java&#039;&#039;). Diese sorgt dafür, dass wir auf dem gesamten Terminal schreiben können. Siehe dazu auch die [http://jline.sourceforge.net/ benutzte Bibliothek &#039;&#039;JLine&#039;&#039;], da diese genauer beschreibt wie genau es funkioniert. Nachdem die Bibliothek JLine initialisiert wurde, werden die Variablen von Benutzer eingelesen (Mittels der Kommandozeilen Parameter) und das Spielfeld erstellt. Folgend wird die Hauptschleife, also die, die das gesamte Programm kontrolliert gestartet. Die Idee ist, dass nach dem die Methode &#039;&#039;runMainLoop(..)&#039; zurück gekommen ist, das Programm beendet werden soll. Daher ist der letzte Aufruf der &#039;&#039;main&#039;&#039;-Methode ein Reset des Terminals, damit Alles wieder auf seinen initialen Zustand zurück gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Das eigentlich Spannende passiert in der &#039;&#039;runMainLoopMethode(..)&#039;&#039;. Hier werden zunächst einige statistische Variablen erzeugt, die speichern wieviele &#039;&#039;Tile&#039;&#039; von den unterschiedlichen Typen abgetragen worden sind. Nach der Initialisierung dieser Variablen wird die Schleife gestartet, die erst beendet wird, wenn das Spiel beendet werden soll (also, entweder wenn der Diamant gefunden wurde, oder aber sobald eine der Pfeiltasten oder ESC gedrückt wurde.)&lt;br /&gt;
&lt;br /&gt;
Zu Allererst wird die Welt aktualisiert, indem w.simulate() aufgerufen wird. Diese Methode aktualisiert zur Zeit lediglich den Player, aber könnte Theoretisch auch für allgemeinere Situationen benutzt werden. Nachdem die SpielWelt aktualisiert wurde, ist es an der Zeit die Welt anzuzeigen. Nach dem Anzeigen wird ausgewertet, ob der Benutzer einer der Tasten gedrückt hat. Ist dies der Fall, wird geschaut, ob eines der Tile gemined werden soll. Die Überprüfung passiert in der bereits erwähnten &#039;&#039;mine()&#039;&#039;-Methode, die das Tile zurück liefert, welches gerade gemined wurde (dabei kann es sich prinzipiell auch um ein &#039;&#039;AirTile&#039;&#039; handeln.) Als nächstes wird diese Tile in der runMainLoop() ausgewertet, und die loop beendet, wenn ein &#039;&#039;DiamondTile&#039;&#039; gefunden wurde. Sonst werden einfach die Zähler der passenden Typen hochgesetzt. Nun beginnt die Schleife wieder von vorne, in dem sie zuerst die Welt aktualisiert, dann sie anzeigt und letztlich erneut die Eingaben des Benutzers auswertet.&lt;br /&gt;
&lt;br /&gt;
Nach dem die Schleife verlassen wurde, wird der &#039;&#039;GameOver&#039;&#039;-Bildschirm angezeigt, der die statistischen Variablen ausgibt.&lt;br /&gt;
&lt;br /&gt;
= Ende =&lt;br /&gt;
[[Bild:asciicraft-score.png|thumb|280px|Javakurs 2011 - AsciiCraft GameOver]]&lt;br /&gt;
&lt;br /&gt;
Damit sind wir auch schon am Ende des kurzen Überblicks über das Spiel angelangt. Jetzt bleibt euch nur zu tun, das eben gelesene noch mal revue passieren zu lassen und evtl. eigenen Erweiterungen zu schreiben (Wie wäre es zum Beispiel mit einem Mehrspielermodus, oder mit Lava, welche dem Spieler Schaden zufügt). Auch könntet ihr einfach von vorne Anfangen und ein ganz eigenes Spiel schreiben.&lt;/div&gt;</summary>
		<author><name>130.149.236.90</name></author>
	</entry>
</feed>