Sitzung: Jeden Freitag in der Vorlesungszeit ab 16 Uhr c. t. im MAR 0.005. In der vorlesungsfreien Zeit unregelmäßig (Jemensch da?). Macht mit!

Javakurs/Übungsaufgaben/Doom

ASCII-DOOM

In Ascii Doom geht es darum ein kleines Spiel zu implementieren, mit ASCII Grafiken. Es wird möglich sein mit einer Spielfigur auf dem Spielfeld zu laufen, später könnt ihr auch Items, Waffen und Liv Tyler einbauen! Wir werden Klasse für Klasse das Spiel implementieren.



class GameMain Teil 1

  • Die Klasse GameMain ist die Klasse, die die main Methode enthalten wird und somit ausführbar ist.
  • Sie wird die Schnittstelle zur Außenwelt sein und das printen auf die Konsole tätigen.
  • Erstellt zunächst nur diese Klsse. Sobald ihr Klassen aus den späteren Aufgaben implentiert habt, könnt ihr in der main Methode ihre Funktionalität testen.




class Position Teil 1

  • Position repräsentiert eine Position auf einem 2D Spielfeld.
  • Enthält eine private x und eine y Variable gekapselt mit gettern/settern.
  • Implementiert eine equals Methode, die 2 Positions vergleicht.
  • TESTET euer equals!




class GameTile Teil 1

  • GameTile repräsentiert ein Tile ( ein Feld ) im späteren Spiel.
  • Enthält eine private Variable, die für den Typ des Feldes steht ( am besten ein int ).
    • 1 entspricht wand
    • 2 entspricht leer
  • Also auch hier braucht ihr getter und setter.
  • Enthält außerdem eine private Variable vom Typ Position, welche die Position des GameTiles auf dem Feld speichert.
  • Implementiert eine toString methode, die jedem GameTile einen String mit Länge 1 zuordnet.
    • wand = "x"
    • leer = " "
  • TESTET euer toString.


class GameField Teil 1

  • GameField ist eine zentrale Klasse in diesem Spiel, sie repräsentiert das Spielfeld als ganzes und besteht aus GameTiles.
  • Enthält eine private Variable für das Level ( 2D Array aus GameTiles ).
  • Über den Konstruktor wird ein String dieser Form übergeben:
		  ######## 
		  #      # 
		  #      #
		  ###    #
		  #      #
		  ########	  
    • Es soll mit einer Schleife der String Zeichen für Zeichen ausgelesen werden und aus jedem Zeichen ein neues GameTile ( fest oder leer ) erzeugt werden Diese GameTiles werden dann in dem Array gespeichert!
    • Wie man Strings Zeichen für Zeichen ausliest, findet ihr in der API ( java.lang.String ).
    • Implementiert ein toString, dieses soll folgenden String liefern:
		  12345678
		1 ######## 
		2 #      #
		3 #      #
		4 ###    #
		5 #      #
 		6 ########
    • tip: "\n" steht in einem String für Zeilenumbruch.
    • Es soll also aus dem GameField-Array wieder ein String generiert werden.
    • Die toString Methode von GameField soll die toString Methode von GameTile verwenden um diese Ausgabe zu erzeugen.
  • TESTET euer Programm mit verschiedenen Levels




class World Teil 1

  • World ist die Klasse die alles verbinden wird, Spieler, Items, Spielfeld etc.
  • Zunächst einmal gibt es nur das GameField, was wir einbinden können ( später der Spieler ).
  • Die Main Klasse erzeugt ab jetzt nur noch eine Instanz von World nicht mehr von GameField. Denn World selbst soll sich das GameField erzeugen ( im Konstruktor ).
  • Bei Java funktioniert es bei grafischen Anwendungen etwa so: Man hat ein Objekt, das eine Leinwand repräsentiert ( Canvas ), man darf auf diesem Objekt Sachen malen. In einem Spiel wird das Objekt in jedem Frame leer gemacht, danach werden alle beteiligten grafischen Objekte ( Spieler, Spielfeld, Gegner ) nacheinander auf diese Leinwand gemalt. Letzendlich wird die Leinwand auf dem Bildschirm ausgegeben. Das hat den Vorteil, dass jede Klasse die darauf Zugriff bekommt irgendetwas malen kann ohne zu wissen, was bereits darauf ist oder noch darauf kommt. ( Jedes Objekt kümmert sich selbst um seine grafische Entsprechung. )

Das werden wir hier auch machen, allerdings mit Strings, da uns die Grundlagen für Grafisches noch fehlen.

  • Definiert eine solche Canvas Variable, die für die grafische Repräsentierung des Spielfelds stehen wird.
    • Das soll ein 2D Array aus Strings der Länge 1 sein. Ein String pro Feld, dieses enthält dann "#" oder " ".




class GameField Teil 2

  • Wir brauchen nun eine draw Methode, die eine solche Leinwand (String[][]) aus World übergeben bekommt und sich selbst darauf malt. Diese Methode funktioniert nun ähnlich wie unsere toString Methode, sie gibt nur nichts zurück, sondern modifiziert direkt unser Leinwand Array und malt dort Zeichen für Zeichen die Felder rein.( Arrays sind keine primitiven Datentypen daher wird hier nicht mit einer Kopie gearbeitet )
public void draw( String[][] canvas ){ }
 
  • Was passiert eigentlich wenn das GameField größer ist als unser String[][] ??




class World Teil 2

  • Nun kommt unsere wichtigste Methode public void draw(). Draw soll alle Inhalte ( bisher nur GameField ) auf unser Canvas Objekt malen, indem es die draw Methode von GameField aufruft und das Canvas Array übergibt. Der Code beschränkt sich hier also auf eine Zeile.
    • Später fügen wir hier mehr ein.
  • Implementiert auch eine toString Methode, diese sollte das aktuelle Canvas Array in der richtigen Form für die Konsolenausgabe liefern.
  • TESTET nun euere Grafik Ausgabe und euer toString().




class GameMain Teil 2

  • Die Klasse GameMain enthält als einzige eine Instanz der Klasse World und kann somit das Spielfeld zeichnen.
  • Sofern ihr beim Testen versucht habt das Spielfeld mehrmals auf die Konsole auszugeben, seht ihr, dass das alte Spielfeld noch immer sichtbar ist über dem neuen. Das sieht irgendwie blöd aus.
  • Zählt nach wieviele Zeilen euere Konsole hat.
  • Bevor man das Level ausgibt kann man soviele leere Zeilen ausgeben lassen, dass das alte Level nicht mehr sichtbar ist. System.out.println(""); gibt eine leere Zeile aus.
  • TESTEN ob das klappt und gut aussieht




class Player Teil 1

  • Der Spieler wird die Möglichkeit haben auf dem Spielfeld rumzulaufen und je nachdem wie weit ihr kommt noch viel mehr ...
  • Der Spieler besitzt eine Position ( Variable vom Typ Position ), wie immer private mit getter/setter
  • Der Spieler wird durch ein "*" auf dem Spielfeld repräsentiert. Implementiert eine draw Methode, die genau so wie die draw Methode aus GameField den Spieler auf unsere Leinwand malt, an die Position die inder positions Variable gepseichert ist.
  • Player soll auch vier Methoden haben
    • public void moveLeft()
    • public void moveRight()
    • public void moveUp()
    • public void moveDown()
  • Welche einfach nur die X oder Y Position um 1 erhöhen oder dekrementieren




class World Teil 3

  • Im Konstruktor soll nun auch eine Spielerinstanz erzeugt werden und zunächst an einer bel. Position gesetzt werden
  • Erweitert die draw Methode so, dass nun auch der Spieler angezeigt wird.
  • TESTET ob das funktioniert. Was passiert eigentlich, wenn man den Spieler an der Position -1 | -1 setzt ?




class World Teil 4

  • Implementiert eine Methode public boolean onKeyPressed( String key ){ ... } Sie wird dann aufgerufen werden wenn eine Taste gedrückt wurde und soll true zurückgeben wenn der Spieler sich bewegt hat, ansonsten false.
  • Zunächst müssen wir in onKeyPressed prüfen ob key einer der Strings "a" (links) , "s"(unten) , "d"(rechts) , "w"(oben) ist. ( equals benutzen! ) Falls ja wurde schonmal sicherlich eine gültige Taste gedrückt. Falls nein können wir false zurückliefern.
  • Wir müssen als nächstes prüfen ob der Spieler durch die Bewegung nicht in eine Mauer reinläuft, dazu müssen wir die Spielerposition vergleichen und schauen in welchem Tile er stehen würde wenn wir rechts/links/hoch/runter liefen. Sofern dieses Tile leer ist. Dürfen wir in diese Richtung laufen.
  • Nun wo wir das alles geprüft haben bewegen wir den Spieler mit einer der 4 Bewegungsfunktionen und geben true zurück
  • TESTET unbedingt manuell diese Methode, sie muss korrekt funktionieren!




class GameMain Teil 2

  • Nun kommt alles zusammen.
  • Fügt am Ende eurer main Methode folgenden Code für das Lesen von der Tastatur:
	while( true ){
		InputStreamReader reader = new InputStreamReader(System.in);
		BufferedReader lineReader =	new BufferedReader(reader);
		System.out.print(">");
		
		char[] line = new char[1];		
		try {						
			line[0] = (char)lineReader.read();			
		} catch (IOException e) {
			e.printStackTrace();
		}
		String s = new String( line );
		if( s.equals("x") ){
			return;
		}else if(  s.equals("a") || s.equals("s") 
			 ||s.equals("d") || s.equals("w") ){
 			 /*TODO: MODIFIZIERT DEN NAMEN DER WORLD INSTANZ HIER! */
			 if( world.onKeyPressed( s ) ){
			 	/*TODO: HIER MUSS NEUGEMALT WERDEN, DER SPIELER HAT SICH BEWEGT*/
			 }
			 
			
		}
	}
  • Ihr müsst "world" durch den Namen, den ihr euerer World Instanz gegeben habt ersetzen.
  • In die if-Anweisung am Ende fügt ihr euren Code für das neuzeichnen des Levels. Also viellciht soetwas wie : System.out.println( world ).




  • Nun kann der Spieler im Level rumlaufen und es gibt eine Art interaktion...Das ist das Basisgerüst für ein Spiel, ihr könnt nun weitere Sachen einfügen wie zB items die man einsammeln kann. Wie könnte man das machen ?? Was hat Liv Tyler in diesem Spiel für eine Aufgabe?





Kommentare

Wenn du Anmerkungen zur Aufgabe hast oder Lob und Kritik loswerden möchtest ist hier die richtige Stelle dafür. Klicke einfach ganz rechts auf "bearbeiten" und schreibe deinen Kommentar direkt ins Wiki. Keine Scheu, es geht nichts kaputt ;)