Final Starfighter Deluxe Die Patterns Ein Spielentwicklungsprojekt von Stefan Radicke && Thomas...

Post on 05-Apr-2015

108 views 1 download

transcript

Final Starfighter DeluxeDie Patterns

Ein Spielentwicklungsprojekt von

Stefan Radicke

&&

Thomas Fuchsmann

sr038 && tf014 2

Inhalt 1

1. Einführung1.1 Grober Überblick über das Projekt1.2 Das Spiel: Ein virtueller Ausflug

2. Game Patterns, zum Ersten (ein grober Überblick)2.1 Erklärung vom PollingThread

2.2 Vom PollingThread zur Session2.3 Scrolling und Zeichenvorgang

3. Game Patterns, zum Zweiten (Objekte im Detail)3.1 Karl, der Raumschiff3.2 Feinde3.3 Bewegungsmuster3.4 Komm, wir basteln uns einen Feind

sr038 && tf014 3

Inhalt 2

4. Objekte erzeugen Objekte: Die Schüsse4.1 Was unterscheidet Schüsse von den anderen Objekten?

5. Kollisionserkennung5.1 Problematik – Kleine Fragestunde5.2 Das Konzept: Die konkreten Kollisionsklassen (Chain Of Responsibility, Strategy)

6. Das Level: Von der Engine zum Spiel6.1 Ein vereinfachter Iterator6.2 Konstruktoren und Arrays: Wunder der Technik6.3 Zusatzinformationen

7. Der Punkt, zu dem wir nicht mehr kommen werden, falls doch...

8. Danksagung und Ressourcen

sr038 && tf014 4

1.1 Grober Überblick über das Projekt- Statt Patterns ein Projekt- Das Rad neu erfunden?- Entwicklungszeit / Umfang- Erste Planung - Ziel

1. Einführung

1.2 Das Spiel: Ein virtueller Ausflug - Patterns in Aktion

sr038 && tf014 5

2.1 Erklärung vom PollingThread- Grundlegender Spielablauf (Endlosschleife)- Einzelne Schritte (berechnen, rendern, zeichnen, warten)

2. Game Patterns, zum Ersten

2.2 Vom PollingThread zur Session- Zentrale Klasse (Mediator)- Alle Objekttypen (Diagramm)- Listen und Manager- Zusammenhang zwischen Session und PollingThread

2.3 Scrolling und Zeichenvorgang- Der Eindruck von Bewegung- Darstellung in mehreren Ebenen (Multiscrolling)

sr038 && tf014 6

2.1 Erklärung vom PollingThread

Vereinfachter Spielablauf:

while (true) {

//Aktuellen Zustand des Spiels berechnen.berechnen();

//Das Spiel rendern und auf den Bildschirm zeichnen.

zeichnen();

//Ein wenig schlafen.Thread.sleep(25);

}

sr038 && tf014 7

Session

2.2 Vom PollingThread zur Session

Karl

Feinde

Wände

Items

FactoriesDatenbanken

Schüsse

Level

Session als zentrale Klasse: Mediator

sr038 && tf014 8

2.2 Vom PollingThread zur Session

Listen und Manager:

Die Session hält alle Feinde, Schüsse, Items und Wände in ArrayListen.=> Alle Objekte, die in den Listen gespeichert sind, sind am aktuellen Spielgeschehen beteiligt.

Für alle Objekttypen sind Manager-Methoden vorhanden, die vom PollingThread in einer bestimmten Reihenfolge aufgerufen werden.

Funktionsweise der Manager:=> über die entsprechende ArrayList wird iteriert=> Objekt wird bewegt=> Kollision wird geprüft

sr038 && tf014 9

2.2 Vom PollingThread zur Session

enemyManager() als Beispiel:

public void enemyManager() { for (iterator = enemies.iterator(); iterator.hasNext();) { enemy = (IEnemy)iterator.next();

if (enemy.isAlive()) { enemy.move(); //Kollision wird an anderer Stelle geprüft } else { enemy.suicide(); } }}

sr038 && tf014 10

2.2 Vom PollingThread zur Session

Zusammenhang zwischen Session und PollingThread:

PollingThread Session

levelManager()

wallManager()

enemyManager()

enemyShootManager()

shootManager()itemManager()

karlManager()

repaint()

Spielzustand berechnen

rendern,zeichnen

sr038 && tf014 11

2.3 Scrolling und Zeichenvorgang

Der Eindruck von Bewegung:

sr038 && tf014 12

2.3 Scrolling und Zeichenvorgang

Der Eindruck von Bewegung:

sr038 && tf014 13

2.3 Scrolling und Zeichenvorgang

Darstellung in mehreren Ebenen:

sr038 && tf014 14

3. Game Patterns, zum Zweiten

3.1 Karl, der Raumschiff- Wichtige Attribute- Ergänzung zur Session: Der KeyListener- Steuerung und Bewegung- Waffen für Karl: Ballern wie gestört

3.2 Feinde- Wichtige Attribute- Analogie zu den Grundpatterns (State, Template und Facade)- Das Interface: Jeder Feind wird gleich behandelt (Facade)

3.3 Bewegungsmuster- Lustig, aber wahr: Feinde dekorieren Bewegungsmuster (Decorator)- Die Hierarchie der MovePatterns und ihrer Datenbank- Problemloser Wechsel, zu Laufzeit (State)

3.4 Komm, wir basteln uns einen Feind

sr038 && tf014 15

3.1 Karl, der Raumschiff

Attribute für die Steuerung:

+ isMovingUp : boolean+ isMovingDown : boolean+ isMovingLeft : boolean+ isMovingRight : boolean+ isShooting : boolean

=> In den Methoden keyPressed(...) und keyReleased(...) werden die boolschen Variablen gesetzt.=> Dadurch ist eine flüssige Steuerung, unabhängig von Interruptzeiten, möglich.

Ergänzung zur Session: Der KeyListener

sr038 && tf014 16

3.1 Karl, der Raumschiff

Waffen für Karl: Ballern wie gestört

=> Im shootManager() wird von Karl ein Schuss angefordert, wenn karl.isShooting auf true steht.

=> Karl entscheidet selbstständig, ob er zum aktuellen Zeitpunkt schießen darf.

=> Unter folgenden Voraussetzungen darf Karl schießen:- Es befinden sich nicht mehr Schüsse im Bild, als erlaubt.- Die vorgegebene Verzögerungszeit ist abgelaufen.Die nötigen Variablen sind in der allgemeinen abstrakten Klasse Shoot statisch festgelegt.

=> Die Verzögerungszeit wird ignoriert, wenn der Spieler die Feuern-Taste schnell hintereinander mehrmals betätigt.

sr038 && tf014 17

3.2 Feinde

=> State: Bewegung und Schussverhalten=> Template: Algorithmen und deren Reihenfolge in abstrakten Superklassen. Subklassen bestimmen nur die Attributwerte.=> Facade: Allgemeines Interface für alle Feinde

Wichtige Attribute

# isAlive : boolean# hp : int# points : int- enemyImage : Image- suicideImage : Image- lineArray : Line2D[ ]# movePattern : IMovePattern# isHitByShoot : boolean

Analogie zu den Grundpatterns

sr038 && tf014 18

3.2 Feinde

Jeder Feind wird gleich behandelt: Das Feindkonzept

<< IEnemy >>

Enemy

AnimatedEnemy

Weitere Klassen:

Datenbanken, Karl, Level, etc.

Fighter5

GroundCannon1

Session

<< IMovePattern >>

Subsystem

Facade

sr038 && tf014 19

3.3 Bewegungsmuster

Feinde dekorieren Bewegungsmuster: Decorator + State

<< IMovePattern >>

MovePattern

PointMovePattern SimpleMovePattern

<< IEnemy >>

+move() : void

Session

=> Das Interface IEnemy sieht eine Methode setMovePattern(...) vor, mit der es möglich ist, die Movepatterns zur Laufzeit auszutauschen.

PointListData

sr038 && tf014 20

3.4 Komm, wir basteln uns einen Feind!public class FieserFeind extends Enemy {

}

public FieserFeind(Session session) { super(session); }

public int getHeight() { return 60; }

public int getWidth() { return 80; }

public int getHP() { return 100; }

public int getPoints() { return 10999; }

public Image getEnemyImage() { return session.graphicData.getFieserFeindImage(); }

public Image getSuicideImage() { return session.graphicData.getExplosion1Image(); }

public void playSuicideSound() { session.soundData.playExplosion1(); }

IMovePattern movePattern = new SimpleMovePattern(...); public IMovePattern getMovePattern()

{ return movePattern; }

sr038 && tf014 21

4. Objekte erzeugen Objekte: Die Schüsse

4.1 Was unterscheidet Schüsse von den anderen Objekten?- Die Hierarchie aller Schüsse- Karls Schüsse und feindliche Schüsse im Vergleich- Factories: Unterbindung von new

sr038 && tf014 22

4.1 Was unterscheidet Schüsse von anderen Objekten?

=> Schüsse werden zu unvorhersehbaren Zeiten in beliebiger Anzahl erzeugt.

=> Weiteres Problem: Schüsse dürfen nicht zur Laufzeit initialisiert werden.

Lösung: Factories, die alle Schüsse beim Laden der Engine in ausreichender Anzahl erzeugen.

=> Worin unterscheiden sich Karls Schüsse von feindlichen Schüssen?- Art der Erzeugung- Karls Schüsse haben Trefferpunkte- feindliche Schüsse vernichten Karl sofort- feindliche Schüsse fliegen auf einen konkreten Zielpunkt zu

sr038 && tf014 23

4.1 Was unterscheidet Schüsse von anderen Objekten?

Die Hierarchie aller Schüsse

<< IShoot >>

Shoot

KarlShoot EnemyShoot

EnemyShootFactory

Session

Fireball1 RedLaser1

KarlShootFactory

n

Karl

sr038 && tf014 24

Factories: Unterbindung von new

EnemyShootFactory als Beispiel:

4.1 Was unterscheidet Schüsse von anderen Objekten?

EnemyShootFactory

- redLaser1Array : EnemyShoot [ ]

... //weitere Schusstypen-Arrays

+ getEnemyShoot(shootName:String) : EnemyShoot

Enemy

+ createShoot() : void

sr038 && tf014 25

5. Kollisionserkennung

5.1 Problematik – Kleine Fragestunde- Anforderungen an die Kollision- ???

5.2 Das Konzept: Die konkreten Kollisionsklassen (Chain Of Responsibility, Strategy)

- Prinzipielle Zusammenarbeit der Klassen- Unterscheidung von Objekttypen- Performance, was ist das? (Grobüberprüfung, Reihenfolge)

sr038 && tf014 26

5. Kollisionserkennung

5.1 Anforderungen an die Kollisionserkennung:

=> Möglichst pixelgenaue Prüfung

=> Zuverlässigkeit

=> Einfache Handhabung: Flexibilität

=> Performance: Welche Prüfung ist wirklich nötig?

Welche Lösung erfüllt diese Anforderungen?

Unsere Lösung: Vektoren zur Kollisionsprüfung

sr038 && tf014 27

5.2 Die konkreten Kollisionsklassen

Prinzipielle Zusammenarbeit der Klassen

<< ICollision >>

+ check(obj:Object) : boolean

AbstractCollision

# session : Session

Collision

+ check(obj:Object) : boolean

Session

KarlShootCollision

EnemyShootCollision

ItemCollision

KarlCollision

sr038 && tf014 28

5.2 Die konkreten Kollisionsklassen

Unterscheidung von Objekttypen in der Klasse Collision

public boolean check(Object obj) {

if (obj instanceof Karl) { return karlCollision.check(obj); }

if (obj instanceof KarlShoot) { return karlShootCollision.check(obj); }

if (obj instanceof EnemyShoot) { return enemyShootCollision.check(obj); }

if (obj instanceof Item) { return itemCollision.check(obj); }

return false;}

sr038 && tf014 29

5.2 Die konkreten Kollisionsklassen

Kollisionserkennung im Detail: KarlCollision

Schritt 1 => Grobe Überprüfung, um Performance zu sparen: Bounding-Box

Kollision kann ausgeschlossen werden.

=> Abbruch der Überprüfung

sr038 && tf014 30

5.2 Die konkreten Kollisionsklassen

Kollisionserkennung im Detail: KarlCollision

Schritt 2=> Grobe Überprüfung, um Performance zu sparen: Bounding-Box

Kollision ist möglich.

=> Überprüfung auf Vektorebene

sr038 && tf014 31

5.2 Die konkreten Kollisionsklassen

Kollisionserkennung im Detail: KarlCollision

Schritt 3=> Genaue Überprüfung: Vektoren

Vektoren überschneiden sich nicht.

=> keine Kollision

sr038 && tf014 32

5.2 Die konkreten Kollisionsklassen

Kollisionserkennung im Detail: KarlCollision

Schritt 4=> Genaue Überprüfung: Vektoren

Vektoren überschneiden sich.

=> Kollision .. Karl ist tot!

sr038 && tf014 33

6. Das Level: Von der Engine zum Spiel

6.1 Ein vereinfachter Iterator- Hierarchie der Level- Skriptprinzip (Iterator)

6.2 Konstruktoren und Arrays: Wunder der Technik- Woraus besteht ein Objekt?

=> Teilung schwergewichtiger Ressourcen

6.3 Zusatzinformationen: - Hintergrundbild, Scrolling, Musik, besondere Ereignisse

sr038 && tf014 34

6.1 Ein vereinfachter Iterator

<< ILevel >>

+ hasNextStep() : boolean

+ nextStep() : void

+ putWallsIntoList() : void

+ putEnemiesIntoList() : void

Level

+ nextStep() : void

+ putWallsIntoList() : void

+ putEnemiesIntoList() : void

Hierarchie der Level

Level1_1

- enemyArray : IEnemy [ ] [ ]

- wallArray : IWall [ ] [ ]

+ hasNextStep() : boolean

Der levelManager() in der Session „iteriert“ mit den Methoden hasNextStep() und nextStep() über die Arrays der konkreten Level.

=> Das Level wird wie ein Skript abgearbeitet.

sr038 && tf014 35

6.2 Konstruktoren und Arrays

Erzeugung der Feinde und Wände

=> Alle im Level vorkommenden Objekte werden beim Laden des Levels im Konstruktor initialisiert und in Arrays gespeichert. Dadurch gibt es praktisch kein new zur Laufzeit.=> Vor beginn des Levels sind bereits alle Feinde komplett einsatzbereit zusammengebaut (inklusive aller denkbaren Verhaltensmuster).

=> Eine so riesige Menge von Objekten im Speicher zu halten, ist kein Problem, da alle schwergewichtigen Resourcen (Bilder, Sounds, ...) über Datenbanken geteilt werden. Somit besteht ein konkreter Feind nur aus ein paar Zahlenwerten und benötigt kaum Speicherplatz.

=> Zur Laufzeit des Spiels werden lediglich Referenzen kopiert bzw. verschoben (Level => Session) und nur in Sonderfällen neu erzeugt.

sr038 && tf014 36

6.2 Konstruktoren und Arrays

Erzeugung der Feinde und Wände II: Codebeispiel

public class Level1_1 extends Level { //... private IEnemy[][] enemyArray = new IEnemy[5000][]; //... IEnemy[] e101; //... public Level1_2(Session session) { //... e101 = new IEnemy[] { new Fighter5(session) }; e101[0].setPosition(500, 0); e101[0].setMovePattern(new PointMovePattern( e101[0], session.pointListData.getDropIn(true, 100, 5))); e101[0].setShoot( EnemyShoot.ROUNDFIREBALL1, session.shootBehaviorData.shootRepeatedlyToKarl(80, 6)); //... enemyArray[101] = e101; //... }}

sr038 && tf014 37

6.3 Zusatzinformationen

Hintergrundbild, Scrolling, Musik, besondere Ereignisse

=> Das Level kann zu jedem beliebigen Zeitpunkt angehalten werden: + stopLevel() : boolean Beliebige Bedingungen, z.B. Endgegner im Bild, sind möglich.

=> Informationen über Scrolling-Verhalten: - weit entferntes Hintergrundbild - näheres Hintergrundbild - Wände Alle drei Schichten können sowohl einzeln, als auch in Abhängigkeit zueinander bewegt werden.

=> Es können zu beliebigen Zeitpunkten Musikstücke oder Geräusche abgespielt oder gestoppt werden.

=> Beim Start eines Levels kann eine Animation abgespielt werden.

=> Zur Laufzeit kann jedes Objekt beliebig manipuliert werden.

sr038 && tf014 38

- Schussverhalten- Datenbanken für Sound und Grafik- Vererbungshierarchien im Detail- Animationen:

=> Zwischensequenzen- Auch Feinde haben das Recht recycelt zu werden!- Viele bunte Items- Karls magisches Schutzschild- Zusammenspiel und Abhängigkeiten zwischen Objekten:

=> Wände und Feinde- Intelligente Feinde- Animierte Feinde- Die Pausefunktion: versteckte Problematik- Ein Ladebildschirm- Geschichten eines Entwicklers:

=> Nette Bugs! (Freude am Iterator)

7. Der Punkt, zu dem wir nicht mehr kommen werden, falls doch:

sr038 && tf014 39

8. Danksagung und Ressourcen

Großen Dank an...... Tobias Herborth für seine Nachhilfe in Sachen Animation, Threads und Softwaredesign.... Rebecca Trippe für ihre tollen Charakterdesigns und Spielgrafiken.... Nicolas Schmid für nützliche Tipps und seine ausgiebigste Misshandlung unserer Engine.... Herrn Walter Kriha für sein Talent, uns massiv zu motivieren.... alle Studenten, die uns durch ihre Design Patterns Präsentation in vielerlei Hinsicht die Augen geöffnet haben.... nicht zuletzt alle Testspieler, Kritiker und Versuchkaninchen (Die Flosse bleibt!)

Ressourcen:- GOF-Book (Die Pattern-Bibel)- http://java.sun.com- Spieleentwicklung in Java: http://fivedots.coe.psu.ac.th/~ad/jg/index.html- Java2D, O‘Reilly-Verlag