|
|||||||||||||||||||||||||||||||||||||||||
| ISBN: 3897215462 ISBN: 3897215462 ISBN: 3897215462 ISBN: 3897215462 | |||||||||||||||||||||||||||||||||||||||||
|
|
Wir empfehlen: | ||||||||||||||||||||||||||||||||||||||||
Die Entwicklung unseres ersten SpielsDie SpielideeIn unserem Spiel soll der Spieler zwei Bälle (einen roten und einen blauen), die sich, per Zufallsgenerator bestimmt, in verschiedene Richtungen bewegen, durch einen Mausklick auf den Ball abschießen. Läßt der Spieler einen Ball aus dem Spielfeld fliegen, ohne ihn getroffen zu haben, so verliert er eines von anfangs 10 Leben. Trifft er den Ball, so erhält er eine gewisse Zahl von Punkten (abhängig von der Geschwindigkeit des Balles) und ein neuer Ball erscheint auf dem Spielfeld. Das Spiel soll außerdem Sounddateien bei einem Schuss, bei einem Treffer und wenn ein Ball das Spielfeld verlassen hat abspielen. Die verwendeten Klassen und ihre MethodenDie Klasse MainIn dieser Klasse sollen alle Methoden, die das Applet und die Animation direkt betreffen, implementiert werden. Dazu gehören die Methoden init(), start(), stop(), paint(), update(), run() und die mouseDown() - Methode zum Auffangen von Benutzerereignissen. Die Klasse verwaltet zudem alle für das Spiel nötigen Objekte (zwei Ball Objekte und ein Spieler Objekt) sowie den Thread.
Die Klasse PlayerDiese Klasse verwaltet Punktestand und Leben des Spielers. Dazu verfügt sie über die Methoden getScore() und getLives(), die die aktuellen Werte an die Main - Klasse übergeben, ebenso wie die addScore(int plus) und looseLife() - Methoden, mit denen man Leben abziehen und Punkte hinzufügen kann. Die Klasse BallDiese Klass enthält die kompliziertesten Methoden des Spiels. Sie definiert alle wichtigen Funktionen eines Ball Objektes. Diese sind:
Zusammenspiel der einzelnen Methoden:Bei jedem Threaddurchlauf in der Main - Methode wird die move - Methode jedes Balles aufgerufen. Diese legt die neuen Koordinaten des Balles fest und testet zudem selbstständig, durch den Aufruf der Methode isOut(), ob der Ball im Aus oder noch im Spielfeld ist. Ist der Ball im Aus, so ruft isOut() die looseLife() - Methode des Player - Objektes auf und der Spieler verliert ein Leben. Bevor wir richtig starten noch ein HinweisZu allererst ist es wichtig, dass ihr euch den gesammten SourceCode des Spiels (am Ende der Seite) als *.zip - Archiv runterladet und immer im Auge habt, während ich den Code erkläre. Dabei werde ich nur auf bestimmte Teile des Programmes eingehen und ihr solltet in der Lage sein bzw. es bald lernen, den restlichen Sourcecode (mit Hilfe der andernen Kapitel) zu lesen und zu verstehen um euch auf diese Art und Weise weiteres Wissen anzueignen. Flugrichtung des Balles zufällig gestalltenWie ich schon mal im ersten Kapitel angedeutet habe, wollen wir die beiden Bälle nun nicht mehr nur horrizontal über das Applet bewegen, sondern wir wollen beide Dimensionen (x und y - Koordinate) des Applets ausnutzen. Dazu müssen wir zu dem uns schon bekannten Richtungsvektor in x - Richtung (x_speed) noch einen weiteren in y - Richtung (y_speed) hinzufügen. Unser Ball hat also nun eine Geschwindigkeit in x - Richtung, die bei jedem Aufruf der Methode move() zur aktuellen x - Koordinate hinzugezählt wird und ebenso eine y - Geschwindigkeit, die jeweils zur y - Koordinate hinzuaddiert wird. Der y_speed soll bei beiden Bällen immer konstant bleiben. Dabei soll der eine Ball nach oben (y_speed = -1) und der andere Ball nach unten (y_speed = 1) fliegen. Man beachte, dass das Koordinatensystem von Java sozusagen auf dem Kopf steht (y - Werte werden von oben nach unten immer größer!). Des weiteren soll diese Geschwindigkeit in x - Richtung nach jedem Abschuss / Aus des Balles neu, per Zufall bestimmt werden. Ein ZufallsgeneratorZunächst müssen wir uns also einen Zufallsgenerator in Java beschaffen. Wir importieren hierfür die Klasse java.util.*; in unsere Ballklasse und deklarieren anschließend folgendes Objekt als Instanzvariable der Klasse Ball:
Nun können wir mit dem Befehl rnd.nextInt() eine zufällige Integerzahl erzeugen. Da wir eine Zahl zwischen -3 und +3 erzeugen wollen, müssen wir diese Zahl anschließend noch modulo 4 rechnen um nur Zahlen in diesem Zahlenraum zu erhalten. Die move - Methode des BallesNachdem wir die Instanzvariablen x_speed und y_speed deklariert und im Konstruktor initialisiert haben, können wir sie in jedem Aufruf von move() zu den aktuellen Koordinaten hinzuzählen. x_speed wird dabei immer wieder neu bestimmt (siehe oben), y_speed bleibt konstant. Die move() - Methode sieht also folgendermaßen aus:
{
pos_x += x_speed; pos_y += y_speed; /* Aufrufen der Methode isOut() um zu testen, ob sich der Ball noch im Spielfeld befindet */ isOut(); Die Methode isOut()Die Methode isOut() prüft, ob ein Ball eine der Grenzen des Spielfeldes überschritten hat. Trifft eine der vier Abfragen zu, so wird der Ball auf seine Startposition zurückgesetzt, eine Audiodatei abgespielt, die Flugrichtung neu bestimmt und der Spieler verliert ein Leben (wie genau, das folgt später noch). Das Prinzip ist das gleiche wie schon in unserem dritten Applet (BallReverse) besprochen, mit dem einzigen Unterschied, dass wir hier vier Grenzen haben, die wir nach möglichen Überschreitungen abfragen müssen und nicht nur zwei wie in unserem Beispiel aus Kapitel 1 c. Daher möchte ich nicht näher auf die programmiertechnische Seite dieser Methode eingehen, versucht stattdessen die einzelen Schritte (im Grunde ist es nur einer, der sich viermal wiederholt) alleine nachzuvollziehen (mit den gegebenen Kommentaren und dem Kapitel 1c sollte das kein Problem sein). Den Ball abschießenDieses Problem ist wohl das Schwierigste in diesem Spiel. Der Ball hat ja eine x und eine y - Koordinate. Klickt der Spieler auf das Applet, so werden die x und die y - Koordinate mit an die aufgerufenen Methode userHit (int x, int y) übergeben. Nun muss die Methode entscheiden, ob der Schuss den Ball getroffen hat, oder nicht. Wie soll man das bewerkstelligen.
double x = maus_x - pos_x; double y = maus_y - pos_y; Nun können wir mit Hilfe des Skalarproduktes bzw. Pythagoras (c = Wurzel aus a² + b²) die Länge dieses Verbindungsvektors bestimmen:
double distance = Math.sqrt ((x*x) + (y*y)); Als letzten Schritt testen wir, ob die Länge dieses Vektors kleiner ist als ein gewisser Betrag, bis zu dem wir den Ball noch als getroffen ansehen. Ich habe für diese Zahl 15 gewählt obwohl der Ball nur einen Radius von 10 hat. Aber nachdem ich einige Werte getestet habe, erschien mir dieser Wert als der am besten taugliche.
if (distance < 15) {
return true; else return false; Damit können wir den Ball abschießen, wenn wir auf bzw. kurz daneben schießen. Die Rückgabewerte ergeben sich aus der oben beschriebenen Struktur und Zusammenarbeit der Methoden. Das Spielerobjekt: Punkte zählen und Leben verlierenUm dies zu verwirklichen haben wir die Player - Klasse mit den Methoden looseLife() und addScore (int plus) ausgestattet. Immer wenn ein Ball das Spielfeld verlässt, ruft er player.looseLife() in der Methode isOut() auf. Dadurch verliert der Spieler ein Leben. Trifft der Spieler den Ball (ober beschrieben), so ruft die Methode userHit() player.addScore (10* Math.abs(x_speed) + 10) auf und zählt somit je nach Geschwindikeit des Balles Punkte zu denen des Spielers hinzu. Umso schneller ein Ball fliegt, umso mehr Punkte kann man durch einen Abschuss somit erreichen. Die Methoden addScore und looseLife sind dabei wirklich denkbar einfach. Mauszeiger verändern: Das FadenkreuzNatürlich passt zu unserem Spiel ein Fadenkreuz als Mauszeiger viel besser, als ein normaler Zeiger. Um uns einen Fadenkreuzmauszeiger zu beschaffen, müssen wir unserer Main - Klasse lediglich drei Codezeilen hinzufügen: Zunächst eine Instanzvariable der Klasse Cursor:
Cursor c; // Variable für Cursor In die Init - Methode fügen wir dann folgende Zeilen ein:
c = new Cursor (Cursor.CROSSHAIR_CURSOR); this.setCursor (c); Weitere Klassenvariablen der Klasse Cursor und somit weitere Mauscursor, können in der API nachgelesen werden. Spielzustände: Das Spiel erst nach einem Doppelklick starten und beenden, wenn der Spieler seine Leben verbraucht hatBis auf eine kleine Kleinigkeit ist unser Spiel nun fertig: Es ist für den Spieler sehr unangenehm, wenn das Spiel schon losgeht, bevor er sich überhaupt die Anleitung durchgelesen hat. Wir wollen das Spiel daher erst dann starten, wenn er einen Doppelklick in das Appletfenster ausgeführt hat. Das hat nicht nur den Vorteil, dass der Spieler den Startpunkt des Spieles selbst bestimmen kann, sondern wenn man in seinem Spiel Tastaturereignisse verwendet, dann kann man den Tastaturfocus für das Applet (wird durch Klick auf das Applet erreicht) auf diese Weise sicherstellen. Des weiteren soll das Spiel natürlich dann beendet sein, wenn der Spieler alle seine Leben verspielt hat. Zunächst fügen wir also in die Klasse Main eine boolsche Instanzvariable mit Namen isStoped ein. Ist sie true, so ist das Spiel gestoppt, ist sie false, so läuft das Spiel. Nun fügen wir in unseren Thread (run - Methode) eine Abfrage ein, die die Methoden zur Bewegung des Balles nur dann aufruft, wenn der Spieler mehr als 0 Leben hat und gleichzeitig isStoped false ist. repaint() wird weiterhin immer nach dem Starten des Threads aufgerufen.
while (true) {
{
blueball.move(); ... Im nächsten Schritt wollen wir in der paint() - Methode eine weitere Abfrage einfügen. Sie soll, solange der Spieler noch Leben hat, die Bälle sowie die Angabe über Leben und Punkte zeichen. Ist das Spiel gestoppt, so zeichnet sie zudem die Information, dass das Spiel mit einem Doppelklick gestartet werden kann, auf den Bildschirm. Hat der Spieler keine Leben mehr, so wertet die paint() - Methode seine Punktezahl aus, schreibt eine Bewertung der Ergebnisse auf den Bildschirm, sowie weitere Informationen auf den Bildschirm und gewährleistet, dass das Spiel nach einem weiteren Doppelklick des Spielers wieder gestartet wird. Die paint() - Methode gestalltet sich also folgendermaßen:
public void paint (Graphics g) {
if (player.getLives() >= 0) {
... // Wenn das Spiel zusätzlich noch gestoppt ist if (isStoped) {
// Spieler hat keine Leben mehr else if (player.getLiver() < 0) {
// Details bitte im SourceCode nachlesen Nun ist es fast geschafft! Im Moment haben wir aber noch keine Kontrolle darüber, wann wir das Spiel starten, da wir in die MouseDown - Methode noch keine Befehle eingefügt haben, die das Umschalten von dem gestoppten Spielzustand in das laufende Spiel erlauben. Um dies zu erreichen müssen wir die mouseDown() - Methode folgendermaßen verändern:
public void mouseDown (Event e, int x, int y) {
if (!isStoped) {
if (redball.userHit (x, y)) {
hitnoise.play(); // Ball zu Startwert zurücksetzten redball.ballWasHit (); // Test ob blauer Ball getroffen wurde if (blueball.userHit (x, y)) {
hitnoise.play(); // Ball zu Startwert zurücksetzten blueball.ballWasHit (); else {
shotnoise.play(); // Gestopptes Spiel bei Doppelklick starten else if (isStoped && e.clickCount == 2) {
isStoped = false; init (); return true; Geschafft!!So, nun habt ihr es hinter euch und wenn ihr auch die Teile, die ich nicht so ausführlich besprochen habe, verstanden habt, dann steht eurem ersten Spiel ja nichts mehr im Wege.
Die nächsten Kapitel werden sich noch mit einigen weiterführenden Problemen und Lösungen befassen, die ich in meinen bisher programmierten Spielen verwendet bzw. irgendwo mal gesehen habe. SourceCode download (*.zip - Datei) Nächstes KapitelKünstliche Intelligenz für einen Pong Klon |
|
||||||||||||||||||||||||||||||||||||||||
|
Zurück zu Themenseiten: StudyPaper.com/Startseite/Computer/Informatik/Programmieren/Java StudyPaper.com/Startseite/Computer/Spiele StudyPaper.com/Startseite/Computer Das Setzen von Verweisen (Links) auf diese Seite ist gestattet und bedarf keine vorherige Absprache. | |||||||||||||||||||||||||||||||||||||||||
| Startseite | english | Bookmark setzen | Webseite weiterempfehlen | Copyright © | Impressum | |||||||||||||||||||||||||||||||||||||||||