Entwicklung einer isometrischen Graphik

Transcription

Entwicklung einer isometrischen Graphik
Entwicklung einer
isometrischen Graphik-Engine
in Java
Diplomarbeit
Vorgelegt von
Thomas Schuster
Institut für Computervisualistik
Arbeitsgruppe Computergraphik
Betreuer und Prüfer: Prof. Dr.-Ing. Stefan Müller
August 2004
(Platzhalter für Aufgabenstellung)
Hiermit erkläre ich an Eides statt, dass die vorliegende Arbeit selbständig
verfasst wurde und keine anderen als die angegebenen Quellen und Hilfsmittel verwendet wurden.
. . . . . . . . . . . . . . . . . . , den . . . . . . . . . . . .
....................................
(Ort, Datum)
(Unterschrift)
Inhaltsverzeichnis
1 Einleitung
1.1 Begriffsdefinition . . . . . . . . . . . . . . . . . . . . . . . . .
2 Bestehende Systeme und Verfahren
2.1 Isometrie in Computerspielen . . .
2.2 Verfahren . . . . . . . . . . . . . .
2.2.1 Tile-basierende Verfahren .
2.2.2 Modell-basierende Verfahren
2.2.3 Hybride Verfahren . . . . .
6
6
.
.
.
.
.
8
8
10
10
13
13
3 Anforderungsanalyse
3.1 Allgemein . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Graphik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Eingabe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
14
15
17
4 Konzeption
4.1 Überblick . . . . . . . . . . . . . . . . .
4.2 Design . . . . . . . . . . . . . . . . . . .
4.3 Die APIs im Detail . . . . . . . . . . . .
4.3.1 System . . . . . . . . . . . . . . .
4.3.2 Utilities . . . . . . . . . . . . . .
4.3.3 OpenGL-Direktaufrufe (skizziert)
4.3.4 Texturen . . . . . . . . . . . . . .
4.3.5 Sprites . . . . . . . . . . . . . . .
4.3.6 Terrains . . . . . . . . . . . . . .
4.3.7 Eingabe . . . . . . . . . . . . . .
18
18
21
21
24
25
25
27
28
32
35
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Prototypische Umsetzung
38
5.1 Technologien . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.1.1 JOGL (Java bindings for OpenGL) . . . . . . . . . . . 38
5.1.2 LWJGL (Lightweight Java Game Library) . . . . . . . 39
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
40
40
40
41
6 Implementierung des Demospiels
6.1 Design . . . . . . . . . . . . . . .
6.1.1 Allgemein . . . . . . . . .
6.1.2 Anforderungsanalyse . . .
6.2 Implementierung . . . . . . . . .
6.3 Screenshots . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
50
50
50
51
54
55
5.2
5.1.3 Vergleich . . .
5.1.4 Entscheidung
Implementierung . .
5.2.1 Allgemein . .
5.2.2 Terrain . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7 Auswertung der Ergebnisse
7.1 Erreichte Ziele . . . . . . . .
7.1.1 Allgemein . . . . . .
7.1.2 Graphik . . . . . . .
7.1.3 Eingabe . . . . . . .
7.2 Effizienzanalyse . . . . . . .
7.2.1 Aufbau des Tests . .
7.2.2 Ergebnisse in Zahlen
7.2.3 Schlussfolgerung . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
62
62
62
63
65
65
65
66
70
8 Fazit und Ausblick
8.1 Erreichte Ziele . . . . . . . . . . . .
8.2 Erweiterungen und Verbesserungen
8.2.1 Shader . . . . . . . . . . . .
8.2.2 Innenbereiche . . . . . . . .
8.2.3 Verschiedenes . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
71
71
72
72
72
73
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Kapitel 1
Einleitung
Geht man heute in einen typischen Hollywood“-Film, hat man häufig das
”
Gefühl, daß die eigentliche Handlung den Unmengen von Spezialeffekten zum
Opfer gefallen ist. Bei aktuellen Computerspielen verhält es sich oft ähnlich.
Denn durch den rasanten Fortschritt der Graphikhardware präsentieren sich
mittlerweile nahezu sämtliche Spiele in opulenter 3D-Graphik. Aber nicht
alles, was technisch in 3D umsetzbar ist, sollte auch tatsächlich so umgesetzt werden. Gerade wenn Übersicht gefragt ist, also beispielsweise komplexe Welten aus einiger Entfernung dargestellt werden, scheinen Massen von
aufwendigen 3D-Modellen oft fehl am Platz zu sein. Denn der Aufwand, sie
zu rendern, übersteigt häufig ihren effektiven Nutzen.
In dieser Arbeit wird versucht, bewährte Graphikverfahren zur Darstellung isometrischer Szenen sinnvoll mit Fähigkeiten moderner Graphikhardware zu verbinden. Auf diese Weise soll eine Graphikengine entstehen, die
auch bei weniger leistungsstarker Hardware in der Lage ist, komplexe Welten
ansprechend und effizient aus einer isometrischen Perspektive darzustellen.
Dabei wird auf die plattform-unabhängigen Standards Java und OpenGL
zurückgegriffen, um eine möglichst große Kompatibilität zu gewährleisten.
Die angestrebte Umsetzung in Java kann gleichzeitig als eine Art proof of
concept angesehen werden. Denn speziell im Bereich der Computergraphik
hat Java, im Hinblick auf seine Performanz, einen nicht gerade guten Ruf.
1.1
Begriffsdefinition
Axonometrie
Bei Axonometrie handelt es sich um eine orthographische Parallelprojektion,
d. h. die Sehstrahlen treffen senkrecht auf die Projektionsebene. In der Foto-
6
KAPITEL 1. EINLEITUNG
7
graphie entspricht dies einer Aufnahme eines sehr weit entfernten Gegenstandes mit einem starken Teleobjektiv. Diese Art der Darstellung wird aufgrund
ihrer Einfachheit hauptsächlich in technischen Zeichnungen verwendet. Die
wichtigsten Merkmale der Axonometrie sind:
• Die Projektionsebene ist nicht parallel zu einer der Koordinatenebenen.
• Die perspektivische Verkürzung ist unabhängig von der Entfernung
zum Betrachter.
• Parallelen bleiben erhalten, Winkel nicht.
Isometrie
Die häufigste axonometrische Projektion ist die isometrische Projektion, bei
der die Bildebene alle Koordinatenachsen des Modellkoordinatensystems in
gleicher Distanz schneidet. Dadurch sind die Winkel zwischen ihnen in der
Projektion gleich (120◦ ). Weiterhin stehen alle Abmessungen innerhalb des
Bildes im gleichen Verhältnis zueinander, da die Koordinatenachsen den gleichen Verkürzungsfaktor besitzen (s. Abbildung 1.1).
Andere Formen der Axonometrie sind Dimetrie (nur zwei Achsen besitzen
den gleichen Verkürzungsfaktor) und Trimetrie (jede Achse hat einen eigenen
Verkürzungsfaktor).
Abbildung 1.1: Isometrie
Kapitel 2
Bestehende Systeme und
Verfahren
Bei den betrachteten Systemen mit isometrischer Graphik handelt es sich,
wie nicht anders zu erwarten, um Spiele. Möglicherweise existierende Anwendungen anderer Art werden an dieser Stelle nicht berücksichtigt.
2.1
Isometrie in Computerspielen
Die Ära isometrischer Spiele wurde Anfang der 80er Jahre durch Automatenspiele wie Zaxxon und Marble Madness eingeläutet. Die Faszination dieser damals neuartigen Spielegraphik beruht auf dem gleichen Phänomen wie
bei technischen Zeichnungen. Mit einfachen Mitteln wird eine ansprechende
Ansicht geschaffen, die zwar keine natürliche Perspektive wie die des menschlichen Auges besitzt, aber dennoch Spielfiguren, Objekte und Hintergründe
dreidimensional darstellt.
Gerade diese Möglichkeit, Dreidimensionalität mit einer Hardware zu erreichen, die üblicherweise nur zweidimensionale Ansichten darstellen konnte,
bedeutete den Durchbruch der Isometrie in der Computerspiele-Industrie. Bis
heute finden sich auch für moderne 3D-Hardware immer wieder Spiele mit
isometrischer Ansicht, denn für manche Spiele oder sogar Genres bietet sie
gegenüber der Zentralprojektion entscheidende Vorteile. Diese werden umso deutlicher, je weiter die Kamera vom eigentlichen Spielgeschehen entfernt
und somit Übersichtlichkeit gefragt ist. Dann nämlich sieht die isometrische
Perspektive meist gleichförmiger aus, da das Erscheinungsbild eines Objektes
nicht von seiner Entfernung zum Blickpunkt abhängt.
An dieser Stelle soll eine repräsentative Auswahl von Computerspielen
mit isometrischer Graphik gegeben werden (s. Tabelle 2.1). Dieser Überblick
8
KAPITEL 2. BESTEHENDE SYSTEME UND VERFAHREN
9
Abbildung 2.1: Zaxxon & Marble Madness
umfasst zahlreiche Genres und erstreckt sich über die letzten 20 Jahre. Zum
besseren Verständnis der Tabelle werden einige der Spalten im Folgenden
kurz erläutert:
Multiplayer: Gibt an, ob das Spiel mehrere gleichzeitige Spieler unterstützt.
max. Spieler (Multiplayer): Die Anzahl der gleichzeitig unterstützten Spieler (falls zutreffend).
Echtzeit / Rundenbasiert: Läuft das Spiel in Echtzeit ab, oder ist das
Voranschreiten der Spielzeit von den Eingaben des Benutzers abhängig?
max. Einheiten pro Spieler: Die Anzahl der zum Spieler gehörenden graphischen Objekte. Diese kann von einem (meist eine Repräsentation des
Spielers selbst) bis zu mehreren hundert (Armee-Einheiten und dergleichen) reichen.
Größe der Welt / einzelner Level: Eine ungefähre Einschätzung der Weltbzw. Levelgröße in Relation zum Sichtfeld.
Größe des Sichtfelds: Wie groß ist der Ausschnitt aus der Welt, der im
Sichtfeld dargestellt wird, in Relation zu den Spielfiguren?
Interaktion des Spielers mit der Welt: Wieviel Einfluss kann der Spieler auf das Aussehen der Welt nehmen? Dies schließt die Manipulation
von Landschaften und Objekten als auch die Interaktion mit NichtSpieler-Charakteren (engl. Non-Player Characters, kurz NPC ) ein.
KAPITEL 2. BESTEHENDE SYSTEME UND VERFAHREN
10
Interaktion der Welt mit dem Spieler: Wie lebendig“ ist die Darstel”
lung der Welt, d. h. wie hoch ist der Grad der Interaktion zwischen
der Welt und dem Spieler? Berücksichtigt werden Elemente wie die
Dynamik von Landschaften, Objekten und NPCs.
Aufgrund der aufgelisteten Eigenschaften läßt sich u. a. der graphischen Aufwand eines jeweiligen Spiels ansatzweise einschätzen.
2.2
Verfahren
In diesem Abschnitt werden Verfahren zur isometrischen Darstellung beschrieben, welche vom traditionellen Vorgehen mit 2D-Hardware bis zu neuen Möglichkeiten moderner 3D-Hardware reichen. Bedauerlicherweise gibt es
jedoch wenig Veröffentlichungen zum Thema Isometrische Graphik“ allge”
mein und speziell zu Spielen. Denn die Hersteller von Spielen mit isometrischer Graphik haben erwartungsgemäß wenig Interesse daran, ihre verwendete Technik der Öffentlichkeit und damit der Konkurrenz zugänglich
zu machen. Abgesehen von Isometric Game Programming with DirectX
”
7.0“ [4] finden sich daher kaum Publikationen. Hinzu kommen vereinzelte
Internetquellen wie Artikel, Newsgroup- oder Mailinglisteneinträge, die aufgrund ihrer Fragmentiertheit an dieser Stelle nicht zitiert werden. Aufgrund
langjähriger Beschäftigung mit Computerspielen im Allgemeinen und mit
isometrischen Spielen im Besonderen fließen zusätzlich eigene Beobachtungen und Erfahrungen in diese Arbeit ein.
2.2.1
Tile-basierende Verfahren
Ein Tile ist eine Graphik, die einen Ausschnitt des Hintergrunds darstellt.
Mehrere Tiles aneinander gefügt ergeben eine nahtlose isometrische Ansicht,
möglicherweise mit mehreren Ebenen, Beleuchtungseffekten und Transparenzen. Ein Tile stellt damit einen speziellen Sprite dar. Bei Sprites handelt es
sich um vorberechnete oder gezeichnete Graphiken beliebiger Größe, meist
mit bitweiser Transparenz oder vollwertigem Alphakanal versehen. Hinzu
kommen weitere Sprites zur Darstellung von (Spiel-)Figuren, Objekten und
Effekten (z. B. Partikelsysteme).
Nach eigenen Einschätzungen nutzen die meisten Spiele aus Tabelle 2.1
dieses Verfahren. Beispiele sind Civilization 3“, Diablo 2“ und Ultima VII:
”
”
”
The Black Gate“.
Jahr
1997
2002
2000
1993
2001
2000
2000
2002
1999
1986
1999
1989
2004
1993
2000
1998
1993
1992
1998
1994
Echtzeit /
Rundenbasiert
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Rundenbasiert
Echtzeit
Echtzeit
Rundenbasiert
Rundenbasiert
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Echtzeit
Rundenbasiert
Rundenbasiert
Spiel
Age of Empires
Anno 1503
Baldur's Gate II: Shadows of Amn
Cannon Fodder
Civilization 3
Command & Conquer: Red Alert 2
Diablo II
Heroes of Might and Magic IV
Jagged Alliance 2
Marble Madness
Planescape: Torment
Populous
Sacred
SimCity 2000
Sims, The
StarCraft
Syndicate
Ultima VII: The Black Gate
Warhammer 40,000: Chaos Gate
X-COM: UFO Defense
Spiel
Age of Empires
Anno 1503
Baldur's Gate II: Shadows of Amn
Cannon Fodder
Civilization 3
Command & Conquer: Red Alert 2
Diablo II
Heroes of Might and Magic IV
Jagged Alliance 2
Marble Madness
Planescape: Torment
Populous
Sacred
SimCity 2000
Sims, The
StarCraft
Syndicate
Ultima VII: The Black Gate
Warhammer 40,000: Chaos Gate
X-COM: UFO Defense
max. Einheiten pro Größe der Welt /
Spieler
einzelner Level
> 100
Groß
> 100
Groß
6
Sehr groß
15
Gering
> 100
Sehr groß
> 100
Groß
> 10
Sehr groß
> 10
Groß
6
Mittel
1
Gering
6
Sehr groß
> 100
Groß
>5
Sehr groß
> 100
Groß
> 100
Groß
> 100
Groß
4
Groß
8
Sehr groß
5
Gering
10
Gering
Präsentation
Publisher
Microsoft
Electronic Arts
Interplay
Virgin
Infogrames
Electronic Arts
Blizzard Entertainment
New World Computing
Talonsoft
Electronic Arts
Interplay
Bullfrog Productions Ltd. Electronic Arts
Ascaron
Take2 Interactive
Maxis Software Inc.
Maxis Software Inc.
Maxis Software Inc.
Electronic Arts
Blizzard Entertainment Blizzard Entertainment
Bullfrog Productions Ltd. Electronic Arts
Origin Systems Inc.
Origin Systems Inc.
Random Games
Strategic Simulations Inc.
Mythos Games, MicroProse MicroProse
Entwickler
Ensemble Studios
Sunflowers
BioWare Corporation
Sensible Software
Firaxis Games
Westwood Studios
Blizzard Entertainment
3DO
Sir-tech Software Inc.
Atari Games
Black Isle Studios
Multiplayer
Ja
Nein
Ja
Nein
Ja
Ja
Ja
Ja
Nein
Ja
Nein
Ja
Ja
Nein
Nein
Ja
Nein
Nein
Ja
Nein
max. Spieler
(Multiplayer)
8
6
8
8
8
6
2
2
16
8
4
-
I. der Welt mit dem
Spieler
Mittel
Hoch
Sehr hoch
Gering
Gering
Mittel
Mittel
Hoch
Mittel
Gering
Hoch
Gering
Hoch
Hoch
Hoch
Gering
Mittel
Sehr hoch
Gering
Gering
Interaktion
I. des Spielers mit
Größe des Sichtfelds der Welt
Groß
Mittel
Mittel
Mittel
Gering
Gering
Mittel
Gering
Groß
Mittel
Groß
Mittel
Gering
Gering
Mittel
Gering
Mittel
Mittel
Mittel
Gering
Gering
Gering
Groß
Sehr hoch
Gering
Gering
Groß
Sehr hoch
Gering
Sehr hoch
Mittel
Mittel
Mittel
Mittel
Gering
Hoch
Gering
Mittel
Gering
Hoch
Genre
Strategie
Strategie
Rollenspiel
Action
Strategie
Strategie
Action / Rollenspiel
Strategie
Strategie / Rollenspiel
Action
Rollenspiel
Strategie
Action / Rollenspiel
Simulation / Strategie
Simulation / Strategie
Strategie
Strategie / Rollenspiel
Rollenspiel
Strategie
Strategie
Allgemein
KAPITEL 2. BESTEHENDE SYSTEME UND VERFAHREN
Tabelle 2.1: Populäre Spiele mit isometrischer Graphik
11
KAPITEL 2. BESTEHENDE SYSTEME UND VERFAHREN
12
Umsetzung mit 2D-Hardware
Ohne die Hilfe texturierter Polygone, die einem heutige Hardware sehr effizient zur Verfügung stellt, muss man eine darzustellende isometrische Fläche
oder Struktur aus einzelnen Graphik-Bausteinen zusammensetzen, ähnlich einem Puzzle. Die gängigen Darstellungsalgorithmen (vgl. [4]) verwenden dazu
Tiles, die einer festen Form und Größe entsprechen. Es handelt sich dabei
um Rhomben, d. h. spezielle Parallelogramme mit gleich langen Seiten. Um
eine Ansicht wie in Abbildung 1.1 zu erhalten, müssten die Innenwinkel der
Rhomben 60◦ bzw. 120◦ betragen. Da bei der Rasterisierung Linien in diskreten Stufen dargestellt werden, sind diese Winkel jedoch problematisch, denn
sie erzeugen ein zu unregelmäßiges Pixelmuster. Daher wird in den meisten Spielen ∼26,6◦ (genauer: arctan(0.5)) statt 30◦ verwendet, um für ein
regelmäßiges Muster zu sorgen.
Abbildung 2.2: Pixelmuster verschiedener Winkel
Umsetzung mit 3D-Hardware
Prinzipiell liegt jeder Umsetzung eines tilebasierenden Verfahrens mit 3DHardware das gleiche Prinzip zugrunde: sämtliche Graphik wird mit Hilfe texturierter Polygone dargestellt. Intuitiv bleibt man also im Wesentlichen bei der oben vorgestellten 2D-Methode, nur dass die Möglichkeiten der
3D-Hardware zur Beschleunigung genutzt werden. Dies kann schon in der
zwingenden Verwendung texturierter Polygone für Tiles und Sprites enden,
wodurch die Darstellung bereits sehr effizient wird. Zusätzlich bieten sich
natürlich viele weitere Features aktueller Hardware an, sei es um die allgemeine Performance zu erhöhen, die visuelle Qualität zu verbessern oder
Spezialeffekte zu realisieren. Dies trifft natürlich auch auf die folgenden Verfahren zu.
KAPITEL 2. BESTEHENDE SYSTEME UND VERFAHREN
2.2.2
13
Modell-basierende Verfahren
Mit 3D-Hardware können sämtliche Graphikelemente natürlich auch unter
Verwendung von 3D-Modellen realisiert werden, d. h. auf Tiles und Sprites
im eigentlichen Sinne wird verzichtet. Eine entsprechende orthographische
Projektion vorausgesetzt, ist die Erzeugung isometrischer Szenen also auch
auf diese Weise möglich. Nicht selten stellen Sprites ja auch vorgerenderte
3D-Modelle dar, die sich nun eben direkt als Modelle in der Welt befinden.
Nach eigenen Einschätzungen nutzen beispielsweise Sacred“ und The
”
”
Sims“ aus Tabelle 2.1 dieses Verfahren.
2.2.3
Hybride Verfahren
Der Nachteil der komplett modell-basierenden Verfahren liegt in der erforderlichen Komplexität der einzelnen Modelle. Um beispielsweise einen Wald
darzustellen, müsste jeder Baum als texturiertes und beleuchtetes Modell
gerendert werden. Dies ist sehr aufwendig und kann durch die Verwendung
von Sprites oder Billboards zur Darstellung der Bäume massiv beschleunigt
werden. Für den Hintergrund der Szene sind 3D-Modelle aufgrund ihrer vergleichsweise geringen Komplexität jedoch meist die bessere Wahl und somit
Tiles bzw. Sprites vorzuziehen. Prinzipiell lassen sich großflächige Hintergründe also effizienter mit 3D-Modellen realisieren und einzelne Objekte mit
Sprites.
Nach eigenen Einschätzungen nutzen beispielsweise Anno 1503“ und
”
Heroes of Might and Magic IV“ aus Tabelle 2.1 dieses Verfahren.
”
Kapitel 3
Anforderungsanalyse
Um die Lesbarkeit der folgenden Kapitel zu erhöhen soll das zu entwickelnde
Framework an dieser Stelle einen Namen erhalten. Es wird auf Mithril 1 getauft, in Anlehnung an das große Ziel, es für riesigen Mehrbenutzer-Welten
einsetzen zu können, und an das Hauptgenre dieser speziellen Computerspiele: Fantasy-Rollenspiele.
Die isometrische Darstellung in Mithril soll mittels eines hybriden Verfahrens (s. Abschnitt 2.2.3) realisiert werden, da dies als eleganter Kompromiss zwischen Geschwindigkeit und visueller Qualität angesehen wird. Außerdem kommt dies der in der Aufgabenstellung geforderten Unterstützung
von weniger leistungstarker Graphikhardware nach. Daher orientieren sich
die in diesem Kapitel formulierten Anforderungen u. a. an bekannten Vertretern hybrider Verfahren. Aber auch Beobachtungen aus anderen Spielen
sowie eigene Ideen fließen in die folgenden Abschnitte ein.
3.1
Allgemein
Folgende allgemeine Anforderungen werden an Mithril gestellt:
Effizienz: Die Engine muss schnell sein und mit Ressourcen sparsam umgehen. Dies ist besonders wichtig, weil sie ja nur einen von vielen Teilen
eines Spiels darstellt.
Visuelle Qualität: Um eine hohe visuelle Qualität zu erreichen, sollen die
Fähigkeiten der Graphikhardware möglichst gut ausgenutzt werden.
1
Mithril, auch Moria-Silber genannt. Ein phantastisches Metall aus den Büchern von
J.R.R. Tolkien. Es wurde in Moria von den Zwergen geschürft und verarbeitet. Mithril
war sehr hart und dennoch leicht zu bearbeiten.
14
KAPITEL 3. ANFORDERUNGSANALYSE
15
Dabei sollte Mithril adaptiv vorgehen und sich in seinem Vorgehen
der jeweiligen Hardware anpassen.
Flexibilität: Dem Benutzer soll ein hohes Maß an Freiheit geboten werden, die Engine an seine Bedürfnisse anzupassen. Ebenso sollen eigene
Erweiterungen durch wohldefinierte Schnittstellen möglich sein.
Abstraktheit: Da Mithril ein High-Level-Framework darstellt, soll die
tatsächlich verwendete Anbindung an OpenGL vor dem Benutzer verborgen werden. Zusätzlich soll es trotzdem möglich sein, über eine
Schnittstelle Low-Level-OpenGL-Befehle aufzurufen.
Plattform-Unabhängigkeit: Mithril soll auf unterschiedlichen Betriebssystemen laufen und sich dabei möglichst gleich verhalten. Anvisiert
werden hauptsächlich Windows und Linux.
Kompatibilität: Es werden Mindestanforderungen an die Graphikhardware festgelegt. Solange diese erfüllt sind, soll jede beliebige Hardware
unterstützt werden.
Stabilität: Die Engine soll robust und fehlertolerant sein. Transparenz ist
in diesem Zusammenhang besonders wichtig, so dass der Benutzer auf
eventuelle Fehler gezielt reagieren kann. Außerdem soll das System mittels detailiertem Logging leicht zu debuggen sein.
3.2
Graphik
Die Anforderungen im Bereich der Graphik, welche den Schwerpunkt der
Engine ausmacht, lassen sich in folgende Kategorien unterteilen:
Landschaften: In Form und Aussehen möglichst realistische Gelände mit
folgenden Features:
• Großer Umfang
• Stufenloses Höhenprofil
• Natürlich wirkender Übergang zwischen verschiedenen Oberflächen,
wie Vegetation, Gestein und Schnee
• Animierbare Wasserflächen, wie Meere, Seen und Flüsse
• Wege und Straßen
• Persistente Veränderungen zur Laufzeit, wie Verformungen und
Verfärbungen
KAPITEL 3. ANFORDERUNGSANALYSE
16
Innenbereiche:
• Großer Umfang
• Nahtlose Symbiose mit Landschaften, z. B. ein begehbares Haus
an einem See
• Line of sight, d. h. Ausblenden nicht sichtbarer Bereiche
• Mehrere Ebenen
• Stufenloses Bodenprofil, z. B. bei einem Höhlenboden
• Animierbare Elemente, wie Türen und Aufzüge
• Persistente Veränderungen zur Laufzeit, wie Verformungen und
Verfärbungen
Figuren und Objekte: Folgenden Elemente sollen am Boden, zu Wasser
und in der Luft animiert darstellbar sein:
• Einzelobjekte, wie Charaktere, Fahrzeuge, Vegetation und Gebäude
• Fortlaufende Objekte, wie Zäune, Mauern und Stromleitungen
Effekte: Animierbare Spezialeffekte, wie Explosionen, Feuer und Magie.
Animationen: Unterstützt werden sollen verschiedene Modi:
• Präsentation: Einzelereignis, Ereignissequenz und fortlaufendes Ereignis
• Steuerung: zeit- und ereignisbasierend
Verhalten bei verschiedenen Auflösungen: Je nach Spieldesign muss sich
der Entwickler (sofern er verschiedene Auflösungen unterstützen möchte)
entscheiden, wie sich die Anzeige des Spielinhalts der jeweiligen Auflösung
anpassen soll. Mithril sollte folgende Fälle unterstützen:
• Skalierung des Sichtbereichs → Keine Skalierung der Graphikelemente
• Keine Skalierung des Sichtbereichs → Skalierung der Graphikelemente
Selektion: Es müssen vielseitige Selektionsmöglichkeiten zur Verfügung stehen, um Bildschirmkoordinaten (beispielsweise die Position des Mauszeigers) auf Objekte (d. h. Sprites) und Objektkoordinaten innerhalb
von Terrains und Innenbereichen abbilden zu können.
KAPITEL 3. ANFORDERUNGSANALYSE
3.3
17
Eingabe
Da die Eingabebehandlung über den Fensterkontext des Betriebssystems geschieht, muss Mithril ebenfalls komfortable Schnittstellen zu Tastatur, Maus
und anderen Eingabegeräten bereitstellen.
Kapitel 4
Konzeption
Dieses Kapitel gliedert sich in eine allgemeine Übersicht der Engine, grundsätzliche Überlegungen zum Design des zu implementierenden Modells sowie die
detailierte Betrachtung seiner einzelnen Komponenten. Im Hinblick auf die
spätere Umsetzung in Java werden an dieser Stelle bereits Begriffe wie Klasse,
Schnittstelle, Objekt und Methode verwendet.
4.1
Überblick
Aus der Anforderungsanaylse lässt sich eine Aufteilungen des Frameworks in
drei Hauptkategorien vornehmen: Kern, Graphik und Eingabe. Die Aufgaben des Kerns umfassen dabei alles, was sich den beiden anderen Bereichen
nicht intuitiv zuordnen lässt. Die Hauptkategorien werden ihrerseits logisch
in einzelne Schnittstellen (engl. Interface oder Application Programming Interface, kurz API ) untergliedert. Diese werden in Abbildung 4.1 schematisch
dargestellt und im Folgenden in ihrer Funktion kurz umrissen.
Kern-APIs
System: Fundamentale Bestandteile des Frameworks.
Utilities: Hilfreiche, jedoch nicht essentielle Klassen und Methoden.
18
KAPITEL 4. KONZEPTION
Abbildung 4.1: Die Schnittstellen im Überblick
19
KAPITEL 4. KONZEPTION
20
Graphik-APIs
OpenGL-Direktaufrufe: Ein möglichst großer OpenGL-Befehlsumfang soll
über Wrapperklassen1 direkt erreichbar sein. Diese low level calls kann
der versierte Benutzer frei nutzen, z. B. für eigene Erweiterungen der
Engine.
Texturen: Die Erzeugung von Texturen ist durch Einladen der Daten aus
einer Bilddatei oder aus einem Bild im Arbeitsspeicher möglich. Texturen bilden die Grundlage für Sprites und Hintergrundbilder und werden
als Oberflächen für Terrains und Innenbereiche verwendet.
Sprites: Zweidimensionale Graphiken beliebiger Größe im Format RGBA
(s. Abschnitt 2.2.1). Sie werden aus Texturen heraus erzeugt. Ihre
Darstellung kann über zahlreiche Parameter gesteuert werden. Sprites
können Einzelbilder sein oder aus Einzelbildern bestehende Animationen.
Terrains: Gelände basierend auf Höhen-, Oberflächen- und Beleuchtungsinformationen. Diese Daten sind zur Laufzeit seperat manipulierbar.
Zusätzlich können Sprites zur automatischen Anzeige auf ihnen registriert werden.
Innenbereiche: Sie entsprechen prinzipiell den Terrains, werden allerdings
um die Unterstützung mehrerer Ebenen, line of sight sowie animierbare Elemente wie Türen und Aufzüge erweitert. Außerdem können
Innenbereiche innerhalb eines Terrains platziert werden.
Shader: Die Verwendung von pixel shader - und vertex shader -Technologie
dient der Verbesserung der visuellen Qualität und erhöht die Flexibilität des Frameworks. Der Einsatz der Shader geschieht über spezielle
Schnittstellen innerhalb der anderen Graphik-Komponenten.
Eingabe-APIs
Tastatur: Tastatureingaben sollen komfortabel abgefragt werden können.
Maus: Die Aktionen der Maustasten sollen abgefragt werden können, sowie
die relative Bewegung (einschliesslich des Wheels) und die absolute
Position der Maus.
1
Eine Wrapperklasse hüllt etwas ein, was eigentlich nicht objektorientiert ist. In diesem
Fall Teile der OpenGL-API.
KAPITEL 4. KONZEPTION
4.2
21
Design
Dem zu entwickelnden Framework ist durch die Verwendung der freien, plattform-unabhängigen Technologien OpenGL und Java bereits ein hohes Maß
an Flexibilität in die Wiege gelegt worden. Um diese noch weiter auszubauen,
wird Mithril zwei wesentlichen design patterns unterstellt:
1. Abstraktheit: Der Anwender soll gegen Interfaces programmieren,
nicht gegen Implementierungen.2 Dieser Regel folgend existieren für
nahezu jeden Aspekt in Mithril ein oder mehrere Interfaces, deren
tatsächliche Implementierungen vor dem Benutzer verborgen werden.
Davon ausgenommen sind lediglich einige wenige finale Klassen geringen Umfangs, wie Color oder Viewport (s. Abschnitt 4.3.1). Durch
die konsequente Einhaltung dieses Prinzips ist es möglich, ganze Teile
der Engine unter der Haube“ auszutauschen, beispielsweise um ande”
re Klassen zur OpenGL-Anbindung einzusetzen. Der Anwender würde
davon nichts bemerken, solange er nur gegen die Interfaces programmiert und keine Klasse explizit instanziiert hat. Ebenso sind größere
strukturelle Änderungen innerhalb der Implementierung denkbar, bei
denen die vorhandenen Interfaces Adapterfunktionen übernehmen, um
diese Änderungen vor dem Benutzer zu verbergen.
2. Verwendung von factories: Durch die aus der geforderten Abstraktheit resultierende Schnittstellen-Fassade werden direkte ObjektInstanziierungen erschwert oder sogar verhindert. Um dies aufzufangen existieren spezielle factory-Klassen. Auf diesen kann der Anwender
Methoden aufrufen, die die eigentliche Erzeugung vornehmen und eine
neue Instanz des gewünschten Typs zurückgeben (siehe beispielsweise
die Verwendung von FontFactory und Font in Abschnitt 4.3.1). Diese
factories werden ebenfalls über Interfaces angesprochen; ihre konkreten
Instanzen werden vom Framework erzeugt und als singletons 3 an den
Benutzer weitergegeben.
4.3
Die APIs im Detail
Die meisten APIs werden an dieser Stelle durch UML-Klassendiagramme repräsentiert, die jedoch keinen Anspruch auf Vollständigkeit erheben. Viel2
Dieses Vorgehen ist in der objekt-orientierten Programmierung generell ratsam, inbesondere bei größeren Projekten.
3
Unter einem singleton versteht man eine Instanz (einer Klasse), von der es nur genau
eine geben darf.
KAPITEL 4. KONZEPTION
22
mehr sollen die wesentlichen Konzepte visualisiert werden. Folgende drei
APIs werden allerdings nicht im Detail beschrieben: Shader, Innenbereiche
und OpenGL-Direktaufrufe. Eine detailiertere Konzeption dieser Bereiche
hätte den Umfang der vorliegenden Arbeit gesprengt. Sie werden daher in
den anderen APIs auch nicht berücksichtigt.
Auf eine Auflistung der Attribute wird verzichtet, da sich diese entweder aus den dargestellten Assoziationen ergeben oder trivialer Natur sind
(d. h. sie lassen sich beispielsweise aus den get-Methoden der entsprechenden Klassen ableiten). Abgesehen davon sind ohnehin die meisten der modellierten Klassen Interfaces und verfügen daher nicht über Attribute. Die
Auflistung der Operationen ist exemplarisch anzusehen. Dabei werden der
Name und der Rückgabewert der Operation berücksichtigt, auf die Parameter wird verzichtet. Dies geschieht einerseits, um die feinkörnige Modellierung
von Überladungen zu vermeiden, die gerade bei den factories in hohem Maße nötig wäre. Weiterhin fördert diese Art der Darstellung den abstrakten
Charakter des Modells, da lediglich der Zweck einer Operation deutlich werden soll. Die Operationen werden daher im Folgenden auch nur vereinzelt
näher beschrieben. An Beziehungen werden Vererbung, Realisation, Aggregation, Assoziation und Abhängigkeit4 verwendet. Eine Beschreibung jedes
Diagramms erfolgt innerhalb des entsprechenden Abschnitts.
Abbildung 4.2 zeigt stark vereinfacht den generellen Programmablauf der
Engine.
4
Diese jedoch ausschließlich mit dem instantiate-Stereotyp, um die Funktionsweise der
factories hervorzuheben.
KAPITEL 4. KONZEPTION
Abbildung 4.2: Vereinfachter Programmfluss
23
KAPITEL 4. KONZEPTION
4.3.1
System
Visualisiert in Abbildung 4.3.
Mithril
Das Haupt-Interface des gleichnamigen Frameworks und das Kontrollzentrum für den Anwender. Intern übernimmt es von Initialisierung über Verwaltung und Fehlermanagement bis zur eigentlichen main loop eine Vielzahl wichtiger Aufgaben, wobei
der Schwerpunkt natürlich auf der Graphik liegt. Über dieses
Interface hat der Benutzer Zugang zu den singletons der Eingabeklassen Keyboard und Mouse, sowie zu denen der factories
FontFactory, SpriteFactory, TerrainFactory und TextureFactory. Über setRenderer() kann eine Klasse, die das RendererInterface (s. u. ) implementiert registriert werden.
Renderer
Überträgt dem Anwender die Renderkontrolle. Er muss dazu das
Interface in einer eigenen Klasse realisieren und diese im MithrilInterface registrieren. Die Methode init() wird zum Zeitpunkt
der Initialisierung der Engine bzw. der Registrierung des Renderers genau einmal aufgerufen, dispose() entsprechend bei der
Beendigung des Frameworks. checkInput() und render() werden in jedem Durchlauf der main loop aufgerufen und bieten die
Möglichkeit, eigene Eingabebehandlungen und Graphikoperationen durchzuführen.
Viewport
Eine finale Klasse, die ein Darstellungsfeld in Position und Dimension beschreibt.
Color
Eine finale Klasse, die eine Farbe im Format RGBA repräsentiert.
Light
Eine generische Lichtquelle, die über ambientes, diffuses und spekulares Licht verfügt.
24
KAPITEL 4. KONZEPTION
25
AmbientLight, PointLight, DirectionalLight und SpotLight
Finale Klassen, die das Light-Interface realisieren und dabei jeweils unterschiedliche Arten von Lichtquellen repräsentieren.
FontFactory
Factory zur Erzeugung von Font-Objekten.
Font
Repräsentiert einen renderbaren Font. Dieser basiert auf einem
TextureGrid (s. Abschnitt 4.3.4).
4.3.2
Utilities
Visualisiert in Abbildung 4.4. Diese Komponente ist inhaltlich nur skizziert, da eine solche Werkzeugsammlung natürlich erst mit der Zeit und der
tatsächlichen Anwendung des Frameworks wächst.
HeightmapGenerator
Dient zum Erstellen von zufalls-basierten Höhendaten. Ebenfalls
denkbar sind Methoden zum Einlesen von Dateien, sowie das
Speichern einer Heightmap in eine Datei.
SurfaceMapGenerator
Generiert aus einer gegebenen Heightmap eine SurfaceMap. Dies
ist über zahlreiche Parameter wie Meeresspiegel-Höhe und Landschaftstypen steuerbar. Außerdem kann aus einer vorhandenen
SurfaceMap eine Textur generiert werden, die die Oberflächendaten visualisiert.
4.3.3
OpenGL-Direktaufrufe (skizziert)
Oft ist es wünschenswert, über den Funktionsumfangs einer Graphik-Engine
hinaus eigene low level calls in die zugrundeliegende Graphik-API auszuführen.
Je weiter die Engine jedoch von dieser API entfernt ist, umso schwieriger wird es, diese Möglichkeit dem Benutzer anzubieten. Ein Beispiel sind
KAPITEL 4. KONZEPTION
26
Runnable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
Mithril
areFPSDisplayed() : boolean
dispose() : void
getBackgroundColor() : Color
getBackgroundTexture() : ScreenTexture
getBitsPerPixel() : int
getFontFactory() : FontFactory
getFOV() : float
getHeight() : int
getKeyboard() : Keyboard
getMax2DTextureSize() : int
getMax3DTextureSize() : int
getMaxTextureUnits() : int
getMouse() : Mouse
getProperties() : Properties
getRenderer() : Renderer
getRefreshRate() : int
getSpriteFactory() : SpriteDataFactory
getTerrainFactory() : TerrainFactory
getTextureFactory() : TextureFactory
getTitle() : String
getViewport() : Viewport
getVSync() : boolean
getWidth() : int
isDisposing() : boolean
isFullscreen() : boolean
isMouseGrabbed() : boolean
isRunning() : boolean
isWindowModeSwitchAllowed() : boolean
saveScreenshot() : void
setBackground() : void
setFOV() : void
setBackground() : void
setFPSDisplayed() : void
setFullscreen() : void
setMouseGrabbed() : void
setRenderer() : void
setScreenshotDirectory() : void
setScreenshotPrefix() : void
setView() : void
setViewport() : void
setVSync() : void
0..1
+
+
+
+
«interface»
Renderer
checkInput() : void
dispose() : void
init() : void
render() : void
1
Color
+
+
+
+
+
+
+
+
+
+
getAlpha() : float
getBlue() : float
getGreen() : float
getRed() : float
invertRGB() : void
set() : void
setAlpha() : void
setBlue() : void
setGreen() : void
setRed() : void
Viewport
+
+
+
+
+
+
+
«interface»
Light
calcLighting() : void
getAmbient() : Color
getDiffuse() : Color
getDirection() : Vector3f
getPosition() : Vector3f
getSpecular() : Color
toOpenGLPosition() : void
3
1
AmbientLight
DirectionalLight
PointLight
1
+
«interface»
FontFactory
createFont() : Font
1
«instantiate»
+
+
+
«interface»
Font
getHeight() : int
getWidth() : int
render() : void
Abbildung 4.3: UML-Klassendiagramm: System
SpotLight
KAPITEL 4. KONZEPTION
27
SurfaceMapGenerator
+
+
generate() : SurfaceMap
createMapTexture() : Texture2D
HeightmapGenerator
+
generateDiamondCross() : Heightmap
Abbildung 4.4: UML-Klassendiagramm: Utilities
Szenengraph-Systeme wie Java3D (vgl. [7]), die zwar auf OpenGL basieren, aber aufgrund ihrer Komplexität keine Direktaufrufe einzelner OpenGLBefehle durch den Anwender unterstützen. Da Mithril in seiner Struktur
wesentlich flacher und transparenter ist, sind solche Aufrufe jedoch denkbar
und sollten durch Wrapperklassen zur Verfügung gestellt werden. Dabei wird
ein möglichst großer Teil der OpenGL-Befehle nach außen sichtbar gemacht
und kann auf eigene Gefahr vom Anwendungsprogrammierer genutzt werden. Denn obwohl die Engine dadurch viel flexibler wird, kann man sich auf
diese Weise auch leicht Fehler und Seiteneffekte einbauen. Diese sind unter
Umständen nur schwer nachvollziehbar, da OpenGL eine state machine ist:
das Umsetzen eines Status hat oft weitreichende Konsequenzen für nachfolgende OpenGL-Befehle. Also auch für solche, die von Mithril ausgeführt
werden.
4.3.4
Texturen
Visualisiert in Abbildung 4.5.
Texture
Repräsentiert allgemeine Textur-Informationen und wird von Texture2D,
Texture3D und ScreenTexture spezifisch erweitert. Konkrete TextureInstanzen werden über das TextureFactory-Interface erstellt.
Texture2D
Erweitert Texture um die Belange zwei-dimensionaler Texturen.
Ihre Daten basieren auf RGBA-Bitmaps oder Teilen daraus. Optional werden mip maps unterstützt. Weiterhin übernimmt dieses
Interface eine Art factory-Funktion, indem es die Erzeugung von
KAPITEL 4. KONZEPTION
TextureGrid-Objekten aus Texture2D-Objekten heraus anbietet. Dies ist der einzige Weg ein solches Grid zu instanziieren.
Texture3D
Erweitert Texture um eine Tiefeneigenschaft. Wie Texture2D basiert auch Texture3D auf RGBA-Bitmaps.
ScreenTexture
Eine spezielle Meta-Textur, die aus einer oder mehreren Texture2Ds
besteht. Sie repräsentiert ein renderbares Bild in der Größe des
Bildschirms oder eines beliebigen anderen Viewports.
TextureFactory
Erzeugt Instanzen von Texture2D, Texture3D und ScreenTexture.
Dies kann aus Dateien oder Bildern im Hauptspeicher geschehen.
TextureGrid
Kapselt ein regelmäßiges Texelgitter. Die zugrundeliegende zweidimensionale Textur wird dadurch in Zellen und ihre Zwischenräume aufgeteilt. Die Zellen dienen als Grundlage für einen oder
mehrere Fonts oder Sprites. Im Falle des Fonts repräsentiert
jede Zelle eine Glyphe des Schriftsatzes. Bei den Sprites kann eine Zelle für einen einzelnen Sprite stehen oder für ein Einzelbild
innerhalb eines animierten Sprites.
4.3.5
Sprites
Visualisiert in Abbildung 4.6.
SpriteData
Repräsentiert die Grunddaten einer ganzen Klasse von Sprites
und stellt damit eine Art Vorlage dar. Diese Daten umfassen Dimension, Rotation, Skalierung, Opazität, Blendingeigenschaften
sowie Angaben zu Schwerpunkt und optionaler Zentrierung. Mittels createSprite() werden Sprite-Instanzen erzeugt, die auf
einer Kopie dieser Daten basieren.
28
KAPITEL 4. KONZEPTION
+
+
+
+
+
+
«interface»
Texture
getHeight() : int
getImage() : BufferedImage
getImageResource() : String
getMagFilter() : int
getMinFilter() : int
getWidth() : int
+
29
«interface»
Texture3D
getDepth() : int
+
+
+
«interface»
TextureFactory
createScreenTexture() : ScreenTexture
createTexture2D() : Texture2D
createTexture3D() : Texture3D
«instantiate»
«instantiate»
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
TextureGrid
getCellHeight() : int
getCells() : int
getCellSpacing() : int
getCellWidth() : int
getCols() : int
getRows() : int
getSMax() : float
getSMin() : float
getSPerCell() : float
getSPerSpacing() : float
getTexture() : Texture2D
getTMax() : float
getTMin() : float
getTPerCell() : float
getTPerSpacing() : float
«instantiate»
+
+
+
+
+
+
1 +
+
+
+
+
«instantiate»
«interface»
Texture2D
createTextureGrid() : TextureGrid
createTextureGrid() : TextureGrid
getImageHeight() : int
getImageWidth() : int
getSMax() : float
getSubImageHeight() : int
getSubImageWidth() : int
getSubImageX() : int
getSubImageY() : int
getTMax() : float
isMipMapped() : boolean
«interface»
ScreenTexture
+ render() : void
1..*
Abbildung 4.5: UML-Klassendiagramm: Texturen
KAPITEL 4. KONZEPTION
StillSpriteData
Ein leeres flag interface zur exakten Klassifizierung von Objekten
der Klasse SpriteData in Einzelbild-Sprites (im Folgenden auch
einfache“ Sprites genannt).
”
AnimatedSpriteData
Erweitert SpriteData um die Länge einer Animation und die
Anzahl ihrer Wiederholungen.
Sprite
Ein renderbarer Sprite auf Basis eines SpriteData-Objekts. Da
Sprites in ihrem Lebenszyklus von ihren initialen Daten abweichen können, lassen sich diese Daten mit Hilfe der reset-Methoden
teilweise oder auch komplett auf ihre Grunddaten zurück setzen.
Sprites werden explizit gerendert oder implizit innerhalb eines
Terrains, auf dem sie registriert sind.
StillSprite
Ein leeres flag interface zur exakten Klassifizierung einfacher Sprites.
AnimatedSprite
Erweitert Sprite um die Belange animierter Sprites. Sie basieren
analog auf AnimatedSpriteData-Objekten und enthalten Steuerungsmöglichkeiten wie start(), stop(), pause() und resume().
SpriteDataFactory
Factory zur Erzeugung von Instanzen der StillSpriteData- und
AnimatedSpriteData-Klassen. Die entsprechenden Methoden sind
in hohem Maße überladen um alle sinnvollen Variantionen von
Quellformat und Grunddaten abzudecken.
30
KAPITEL 4. KONZEPTION
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
Sprite
getBlendingColor() : Color
getBlendingStrength() : float
getData() : SpriteData
getOpacity() : float
getRotation() : float
getScaling() : float
getTerrainLocation() : TerrainLocation
getUserTag() : Object
isCentered() : boolean
isOverblended() : boolean
render() : void
resetAll() : void
resetBlendingColor() : void
resetBlendingStrength() : void
resetCentered() : void
resetOpacity() : void
resetOverblended() : void
resetRotation() : void
resetScaling() : void
setBlendingColor() : void
setBlendingStrength() : void
setCentered() : void
setOpacity() : void
setOverblended() : void
setRotation() : void
setScaling() : void
setTerrainLocation() : void
setUserTag() : void
31
+
+
+
+
«instantiate»
+
+
+
+
1
+
+
«interface»
StillSpriteData
+
+
«instantiate»
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
AnimatedSprite
getDuration() : long
getLoops() : int
isFinished() : boolean
isPaused() : boolean
isRunning() : boolean
pause() : void
resetDuration() : void
resetLoops() : void
restart() : void
resume() : void
start() : void
stop() : void
stopAfterLoop() : void
«interface»
SpriteData
createSprite() : Sprite
getDefaultBlendingColor() : Color
getDefaultBlendingStrength() : float
getDefaultOpacity() : float
getDefaultRotation() : float
getDefaultScaling() : float
getHeight() : int
getWidth() : int
isDefaultCentered() : boolean
isDefaultOverblended() : boolean
«interface»
AnimatedSpriteData
getDefaultDuration() : long
getDefaultLoops() : int
«instantiate»
«interface»
SpriteDataFactory
+
+
createAnimatedSpriteData() : AnimatedSpriteData
createStillSpriteData() : StillSpriteData
«interface»
StillSprite
Abbildung 4.6: UML-Klassendiagramm: Sprites
KAPITEL 4. KONZEPTION
4.3.6
32
Terrains
Terrains bestehen grundsätzlich aus einem regelmäßigen Gitter von Knotenpunkten oder Nodes, von denen jeweils vier ein Tile aufspannen. Jede dieser Nodes trägt Informationen zu Landhöhe, -typ und -normale sowie Wasserhöhe, -typ und -normale. Dadurch ist es möglich, Wasser als eine zweite
Ebene mit variabler Transparenz über dem normalen Land darzustellen.
Diese Trennung in Land- und Wasserflächen ermöglicht beispielsweise
die Darstellung seichter Bäche (hohe Transparenz, naher Untergrund), tiefer
Seen (geringe Transparenz, entfernter Untergrund) und noch tieferer Gewässer
(keine Transparenz). Obwohl weniger naheliegend sind auch Vereisung, Sumpf
oder Lava mittels Wasserflächen realisierbar.
Zwischen den verschiedenen Land- bzw. Wassertypen sind fließende Übergänge vorgesehen. Benachbarte Nodes mit unterschiedlichen Typen lösen also
einen ansprechenden Verlauf dieser Typen innerhalb der Tiles zwischen ihnen
aus (s. Abbildung 4.7). Auf diese Weise muss ein Tile im Extremfall vier
verschiedene Typen ineinander mischen.
Abbildung 4.7: Verlauf von Land- bzw. Wassertypen
Das Rendern der Terrains muss aus einer isometrischen Perspektive wie in
Abschnitt 1.1 beschrieben stattfinden. Abbildung 4.8 stellt ein beispielhaftes
Gelände aus 16x16 Nodes schematisch dar und zeigt zusätzlich, wie es durch
eine Umsetzung des Frameworks gerendert aussehen könnte.
Weiterhin können auf einem Terrain Sprites registriert werden, die beim
Rendern des Terrains ebenfalls gerendert werden. Diese Sprites unterhalten je eine TerrainLocation als Position in der Welt. Es werden dabei
zwei Arten von Sprites unterschieden: statische und dynamische (nicht zu
KAPITEL 4. KONZEPTION
Abbildung 4.8: Terrain schematisch und gerendet
33
KAPITEL 4. KONZEPTION
34
verwechseln mit einfachen und animierten). Unter statischen Sprites werden solche verstanden, die ihre Position innerhalb des Terrains (d. h. ihre
TerrainLocation) nicht verändern. Unter dieser Annahme läßt sich das
Rendern des Geländes beschleunigen. Solche Optimierungen sind bei dynamischen Sprites hingegen schwierig, denn sie bieten den Vorteil, ihre Position
beliebig verändern zu dürfen.
Abbildung 4.9 repräsentiert schließlich das UML-Klassendiagramm der
Terrain-API.
ReadableHeightmap
Repräsentiert den lesenden Zugriff auf Höhendaten und Normalen.
WritableHeightmap
Repräsentiert den schreibenden Zugriff auf Höhendaten und Normalen.
Heightmap
Vereint die Funktionalitäten der Interfaces ReadableHeightmap
und WritableHeightmap in einem Interface.
DefaultHeightmap
Standard-Implementierung des Heightmap-Interfaces.
ReadableSurfaceMap
Repräsentiert den lesenden Zugriff auf Land- und Wassertypen.
WritableSurfaceMap
Repräsentiert den schreibenden Zugriff auf Land- und Wassertypen.
SurfaceMap
Vereint die Funktionalitäten der Interfaces ReadableSurfaceMap
und WritableSurfaceMap in einem Interface.
KAPITEL 4. KONZEPTION
DefaultSurfaceMap
Standard-Implementierung des SurfaceMap-Interfaces.
TerrainModel
Stellt das grundlegende Modell eines Terrains dar. Verwaltet die
dazu nötige Heightmap und SurfaceMap.
DefaultTerrainModel
Standard-Implementierung des TerrainModel-Interfaces.
Terrain
Ein renderbares Terrain. Es basiert auf einem TerrainModel und
unterhält Listen der statischen und dynamischen Sprites, die auf
ihm registriert sind. Außerdem ist das Setzen einer Lichtquelle und eines Viewports möglich, welche das Rendern beeinflussen. Weiterhin können Bildschirm-Koordinaten in das Gelände
zurückgerechnet werden, um beispielsweise die Position des Mauszeigers auf einen Punkt innerhalb des Geländes abzubilden. Umgekehrt ist es möglich, eine solche TerrainLocation auf die Bildebene zu projezieren. Mit dieser Technik werden beispielsweise
beim Rendern die Pixelpositionen der auf dem Terrain registrierten Sprites ermittelt.
TerrainFactory
Erzeugt Terrain-Instanzen.
TerrainLocation
Eine Position innerhalb eines Geländes. Sie besteht aus einer XYKoordinate, gemessen anhand der Tiles, sowie einem Z-Wert, der
der Höhe innerhalb des Terrains entspricht.
4.3.7
Eingabe
Visualisiert in Abbildung 4.10.
35
KAPITEL 4. KONZEPTION
+
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
ReadableHeightmap
getMaxSurfaceHeight() : float
getMaxTotalHeight() : float
getMaxWaterHeight() : float
getMinSurfaceHeight() : float
getMinTotalHeight() : float
getMinWaterHeight() : float
getNodesX() : int
getNodesY() : int
getSurfaceHeight() : float
getSurfaceNormal() : Vector3f
getTilesX() : int
getTilesY() : int
getWaterHeight() : float
getWaterNormal() : Vector3f
«interface»
Heightmap
+
+
+
+
1
+
+
+
+
+
+
36
«interface»
WritableHeightmap
baseSurfaceOnZero() : void
calcSurfaceNormals() : void
calcWaterNormals() : void
scale() : void
setSurfaceHeight() : void
setWaterHeight() : void
«interface»
ReadableSurfaceMap
+ getNodesX() : int
+ getNodesY() : int
+ getSurface() : byte
+ getSurfaces() : byte
+ getTilesX() : int
+ getTilesY() : int
+ getWater() : byte
+ getWaters() : byte
«interface»
TerrainModel
getHeightmap() : ReadableHeightmap
getSurfaceMap() : ReadableSurfaceMap
setHeightmap() : void
setSurfaceMap() : void
«interface»
WritableSurfaceMap
+ setSurface() : void
+ setWater() : void
«interface»
SurfaceMap
1
1
DefaultHeightmap
+
«interface»
Terrain
DefaultTerrainModel
«interface»
TerrainFactory
createTerrain() : Terrain
«instantiate»
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
addDynamicSprite() : void
addStaticSprite() : void
clearDynamicSprites() : void
clearStaticSprites() : void
getDynamicSprites() : Iterator
getLight() : Light
getModel() : TerrainModel
getStaticSprites() : Iterator
getViewport() : Viewport
projectSurface() : Point3i
removeDynamicSprite() : void
removeStaticSprite() : void
render() : void
setViewport() : void
unprojectSurface() : boolean
DefaultSurfaceMap
TerrainLocation
+
+
+
+
+
+
+
+
+
+
+
+
Abbildung 4.9: UML-Klassendiagramm: Terrains
add() : void
distance2D() : float
distance3D() : float
getX() : float
getY() : float
getZ() : float
reset() : void
set() : void
setX() : void
setY() : void
setZ() : void
toPoint() : Point3f
KAPITEL 4. KONZEPTION
37
Keyboard
Die Ereignisse der Tasten, also Drücken und Loslassen, werden
gepuffert und können mittels next() durchlaufen werden. Ungepufferte Statusabfragen sind ebenfalls möglich. Insgesamt stehen
drei verschiedene Möglichkeiten der Abfrage zur Verfügung:
1. Gepuffert: Das Ereignis einer Taste
2. Ungepuffert: Die Position einer Taste (gedrückt oder nicht)
3. Ungepuffert: Der Status von Caps-Lock, Num-Lock und ScrollLock
Außerdem können die Namen der Tasten abgefragt werden.
Mouse
Wie bei der Tastatur werden auch bei der Maus die Ereignisse der
Tasten, also Drücken und Loslassen, gepuffert und können mittels
next() durchlaufen werden. Auch hier sind ungepufferte Statusabfragen möglich. Die Abfragen verlaufen dabei analog wie bei
der Tastatur. Zusätzlich bietet dieses Interface die Möglichkeit,
relative Bewegungen der Maus oder des Wheels (sofern vorhanden), sowie die absolute Position des Mauszeigers abzufragen. Die
Anzahl der Tasten sowie das Vorhandensein eines Wheels können
ebenfalls ermittelt werden.
+
+
+
+
+
+
+
+
+
«interface»
Keyboard
getEventCharacter() : char
getEventKey() : int
getKeyName() : String
getKeyState() : int
isEventKeyPressed() : boolean
isKeyDown() : boolean
keyPressed() : boolean
keyReleased() : boolean
next() : boolean
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
«interface»
Mouse
getButtonCount() : int
getButtonIndex() : int
getButtonName() : String
getDWheel() : int
getDX() : int
getDY() : int
getEventButton() : int
getSensitivity() : float[]
getX() : int
getY() : int
hasWheel() : boolean
isButtonDown() : boolean
isEventButtonPressed() : boolean
next() : boolean
setSensitivity() : void
Abbildung 4.10: UML-Klassendiagramm: Eingabe
Kapitel 5
Prototypische Umsetzung
5.1
Technologien
Wie bereits in der Aufgabenstellung festgelegt basiert Mithril auf Java und
OpenGL, um möglichst plattform-unabhängig zu sein. Die Anbindung an
OpenGL steht in Java durch die Standard-Bibliotheken jedoch nicht zur
Verfügung. Zu diesem Zweck gab und gibt es einige freie Entwicklungen als
Open Source, von denen sich jedoch nur die beiden folgenden durchgesetzt
haben:
5.1.1
JOGL (Java bindings for OpenGL)
Beschreibung: The JOGL Project hosts a reference implementation of the
Java bindings for OpenGL API, and is designed to provide hardwaresupported 3D graphics to applications written in Java. It is part of
a suite of open-source technologies initiated by the Game Technology
Group at Sun Microsystems.
JOGL provides full access to the APIs in the OpenGL 1.5 specification
as well as nearly all vendor extensions, and integrates with the AWT
and Swing widget sets.[6]
Lizenz: BSD (Berkeley Software Distribution License)
Verwendung: JOGL stellt dem Benutzer eine Zeichenflächen-Komponente
zur Verfügung, die er in eine AWT- oder Swing-Umgebung einbetten
muss. Über diese Komponente hat er Zugang zur eigentlichen OpenGLAPI, realisiert über einen speziellen Kontext. Alle Aufrufe der dort
bereitgestellten Methoden müssen im selben Thread geschehen wie die
38
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
39
Anzeige der Zeichenfläche. JOGL unterstützt mehrere dieser Kontexte,
und damit auch mehrere Zeichenflächen, innerhalb einer Anwendung.
5.1.2
LWJGL (Lightweight Java Game Library)
Beschreibung: The Lightweight Java Game Library (LWJGL) is a solution
aimed directly at professional and amateur Java programmers alike to
enable commercial quality games to be written in Java. LWJGL provides
developers access to high performance crossplatform libraries such as
OpenGL (Open Graphics Library) and OpenAL (Open Audio Library)
allowing for state of the art 3D games and 3D sound. Additionally
LWJGL provides access to controllers such as Gamepads, Steering wheel
and Joysticks. All in a simple and straight forward API.[3]
Lizenz: GPL (GNU General Public License)
Verwendung: LWJGL basiert auf einer eigenen Fenster-Klasse, d. h. es ist
unabhängig von AWT oder Swing. Das Fenster ist hauptsächlich für
den Einsatz im exklusiven Vollbild-Modus vorgesehen, kann jedoch mit
einigen Einschränkungen auch im Fenster-Modus genutzt oder sogar
in SWT1 -Umgebungen eingebunden werden. Die OpenGL-API wird
durch eine Sammlung statischer Methoden repräsentiert, welche unabhängig vom einzigen2 Fensterkontext und thread-übergreifend aufgerufen werden können. In der gleichen Weise steht auch die Anbindung
an OpenAL und an Eingabegeräte zur Verfügung.
5.1.3
Vergleich
JOGL und LWJGL sind sich auf den ersten Blick sehr ähnlich, repräsentieren sie doch beide ein binding der OpenGL-API nach Java. Auch im Umfang
der abgedeckten Befehle differieren sie kaum, beide erfüllen die OpenGLSpezifikation in der Version 1.5 und unterstützen darüber hinaus zahlreiche Erweiterungen einzelner Hersteller. Und wie zahlreiche Tests und Erfahrungsberichte aus der open source community belegen, liegen die beiden
Systeme sogar in ihrer Performanz sehr dicht beeinander. Wirklich deutlich
werden die Unterschiede zwischen ihnen erst im zugrundeliegenden Design.
JOGL versucht sich möglichst nahtlos in die ereignis-basierenden Umgebungen AWT und Swing zu integrieren und gleichzeitig das stark imperative,
1
SWT = Standard Widget Toolkit [2]
Mehrere Kontexte werden nicht unterstützt, da LWJGLs Hauptziel ohnehin der
Vollbild-Modus ist.
2
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
40
status-basierende OpenGL zu unterstützen. Dieser Balanceakt hat einige
Kompromisse zur Folge, von denen der auffälligste die bereits angesprochene
Abhängigkeit vom Renderthread der Zeichenfläche ist. LWJGL hingegen versteht sich als eine reine enabling technology: OpenGL soll für Java verfügbar
gemacht werden, so direkt und unkompliziert wie möglich. Trotz dieser Differenzen haben beide Philosophien ihre Daseinsberechtigung, und die Wahl
für eines der bindings muss der Anwender abhängig vom Verwendungszweck
treffen.
5.1.4
Entscheidung
Mithril wird in seiner prototypischen Implementierung auf LWJGL basieren. Diese Entscheidung begründet sich hauptsächlich auf den oben genannten Design-Unterschieden und deren Konsequenzen. LWJGL ist für die Entwicklung einer Spiele-Engine eindeutig besser geeignet, da sein Fokus genau
wie der von Mithril eindeutig auf dem exklusiven Vollbild-Modus liegt: Spiele sind für gewöhnlich nicht auf mehrere Render-Kontexte angewiesen und
werden auch nicht im Fenster ausgeführt. Die fehlende Integration in AWT
und Swing ist also ein Vorteil, denn wie der Name schon sagt ( lightweight“)
”
geht es bei LWJGL um eine einfache, schlanke und effiziente Bereitstellung
der OpenGL-Funktionalität unter Java. Dieser Gedanke wird sogar bis auf
die mögliche Verwendung auf mobilen Endgeräten ausgedehnt. Zwei weitere Pluspunkte, wenn auch nicht ausschlaggebend, sind die integrierte Unterstützung von OpenAL und die Abfragemöglichkeiten der Eingabegeräte.
5.2
5.2.1
Implementierung
Allgemein
Die Umsetzung besteht im Wesentlichen aus einer Sammlung von Interfaces (die sich sehr stark an der Konzeption orientieren) und einer StandardImplementierung unter der Verwendung von LWJGL. Durch diese starke Abstraktheit verbirgt Mithril die tatsächlich verwendete OpenGL-Anbindung
nahezu vollständig vor dem Benutzer. Es wäre daher ohne weiteres möglich,
eine zusätzliche Implementierung der Schnittstellen unter der Verwendung
von JOGL zu realisieren. Der Benutzer des Frameworks könnte sich dann bei
der Initialisierung der Engine für eine der verfügbaren Implementierungen
entscheiden. Der Rest seiner Anwendung bliebe unverändert.
Im Folgenden wird eine essentielle Komponente der prototypischen Umsetzung im Detail vorgestellt und die wesentliche Vorgehensweise bei der
Implementierung beschrieben.
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
5.2.2
41
Terrain
Innerhalb der gesamten prototypischen Umsetzung des Konzepts stellt die
effiziente Darstellung der Terrains die größte Herausforderung dar. Je nach
Auflösung und field of view müssen dazu hunderte oder sogar tausende von
texturierten und beleuchteten Tiles gerendert werden. Hinzu kommt eine
unbestimmte Anzahl von statischen und dynamischen Sprites, die auf dem
Terrain registriert sind.
Da es sich bei den Tiles um Vierecke handelt, liegt es nahe, die OpenGLPrimitiven QUAD oder QUAD_STRIP zu nutzen. Aufgrund der hohen Redundanzen der Vertizes (ein Vertex stellt ja meist einen Eckpunkt in vier verschiedenen Tiles dar) wäre es jedoch sehr ineffizient, ihre Koordinaten mehrfach an
die OpenGL-Pipeline zu übergeben. Aus diesem Grund wurden in OpenGL
1.1 Vertex Arrays eingeführt (vgl. [1]). Mit diesen ist es möglich, Eckpunktdaten wie
• Koordinate,
• Farbe,
• Normale und
• Texturkoordinate(n)
gebündelt an die Hardware weiterzugeben. Diese Daten lassen sich dann rendern, als ob sie in entsprechender Form innerhalb der klassischen Befehle
glBegin() und glEnd() angegeben wären. Dies führt zwar bereits zu einer
leichten Steigerung der Geschwindigkeit, beseitigt aber noch nicht die angesprochenen Redundanzen. Zu diesem Zweck kann zusätzlich eine Menge
von Indizes spezifiziert werden. Diese beschreiben die Reihenfolge, in denen
die übergebenen Eckpunktdaten verwendet werden sollen. Auf diese Weise
können identische Vertizes mehrfach referenziert werden und müssen nicht
als Kopien an die Pipeline übergeben werden.
Mithril verwendet für die Terrains daher Vertex Arrays inklusive Indizes
zur effizienten Darstellung von QUAD_STRIPs.
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
42
Erzeugung eines Terrains
Die Umsetzung des TerrainFactory-Interfaces (s. Abbildung 4.9) sieht die
Methode
Terrain createTerrain(TerrainModel model, Light light,
Texture2D[] surfaces, Texture2D[] waterPairs,
Viewport viewport);
vor. Über diese kann sich der Benutzer ein Terrain-Objekt erzeugen lassen.
Dazu muss er die folgenden Parameter übergeben:
TerrainModel model: Standardmäßig ist dies eine DefaultTerrainModelInstanz, basierend auf Instanzen der Klassen DefaultHeightmap und
DefaultSurfaceMap. Natürlich könnte der Anwender auch eigene Realisierungen der entsprechenden Interfaces als Instanzen übergeben.
Light light: Die Lichtquelle, die das Terrain beleuchtet.
Texture2D[] surfaces: Je eine zweidimensionale Textur pro möglichem
Landtyp der im Modell enthaltenen SurfaceMap.
Texture2D[] waterPairs: Je zwei zweidimensionale Texturen pro möglichem Wassertyp der im Modell enthaltenen SurfaceMap, da Wasser
mit Multitexturing dargestellt wird.
Viewport viewport: Der Bildschirmausschnitt, in welchem das Terrain gerendert werden soll.
Bei dieser Erzeugung werden intern Optimierungsstrukturen über den in
model gekapselten Geländedaten aufgebaut. Dabei werden die Tiles in ein
zweidimenionales Feld von Pages eingeteilt. Eine Page deckt 162 Tiles in einem rechteckigen Bereich ab. Die Pages werden anschließend ihrerseits zu
PageProxys zusammengefasst, von denen jeder 42 Pages umfasst. Abbildung
5.1 zeigt diesen Vorgang.
Jede Page unterhält eigene Vertex Arrays zu den Tiles, die sie beinhaltet.
Es gibt dabei pro Page genau ein Vertex-Array3 , ein Normalen-Array und
ein Texturkoordinaten-Array. Zusätzlich existiert für jeden Land- bzw. Wassertyp genau ein Farb-Array. Die genannten Arrays umfassen dabei jeweils
alle 162 Tiles bzw. 172 Nodes. Die Bildung der ersten drei Arrays ist trivial,
3
Also ein Array mit Eckpunkt-Koordinaten, nicht zu verwechseln mit dem Oberbegriff
Vertex Arrays“, der alle Arrays umfasst
”
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
43
Abbildung 5.1: Tiles, Pages und PageProxys
da sie einfach nur die entsprechenden Informationen der beteiligten Nodes
enthalten. Die Farb-Arrays hingegen repräsentieren die räumliche Verteilung
der Land- bzw. Wassertypen innerhalb der Page. Dabei werden pro Typ die
RGB-Werte aller Nodes auf 1 gesetzt, also auf Weiß. Erst der Alphawert trägt
die tatsächlich relevante Information: stimmt der jeweils betrachtete Typ mit
dem der Node überein, wird der Alphawert auf 1 gesetzt, anderenfalls auf
0. Abbildung 5.2 zeigt beispielhaft die Alphawerte des Farb-Arrays, welches
zum Landtyp Grün“ gehört.
”
Abbildung 5.2: Alphawerte der Nodes eines Farb-Arrays
Die unterschiedlichen Alphawerte realisieren die Übergänge zwischen den
Land- bzw. Wassertypen. Dazu werden pro Typ alle zugehörigen Tiles gerendert, also nur solche, bei denen mindestens eine Node dem aktuellen Typ
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
44
entspricht. Diese Reduzierung der zu rendernden Tiles auf zusammenhängende Segmente geschiet mittels Index-Arrays. Je nachdem wie stark eine Page
durch verschiedene Typen fragmentiert ist, werden also mehr oder weniger
Index-Arrays benötigt. Durch das sequentielle Rendern aller Segmente aller
Typen ergibt sich aufgrund der Alphawerte ein Gesamtbild der Page mit
ansprechenden Übergängen zwischen den Typen.
Rendern eines Terrains
Der Anwender hat in seiner Realisierung des Renderer-Interfaces die Möglichkeit, das erzeugte Terrain darzustellen. Dies geschieht durch einen Aufruf der
render()-Methode des Terrains:
void render(float tileX, float tileY, float z);
Diese rendert das Terrain zentriert innerhalb des gesetzten Viewports über
der mit tileX, tileY und z beschriebenen Geländekoordinate. Vereinfacht
ausgedrückt läuft das Rendering wie folgt ab. Zunächst werden die EckVertizes der PageProxys in Bildschirmkoordinaten projeziert und gegen den
Viewport getestet. Liegt ein PageProxy komplett außerhalb des Viewports,
ist er nicht sichtbar und muss folglich auch nicht gerendert werden. Wird ein
PageProxy jedoch als möglicherweise sichtbar klassifiziert, so werden nun alle
in ihm enthaltenen Pages auf die gleiche Weise gegen den Viewport getestet.
Wieder werden die nicht sichtbaren Pages verworfen, während die möglicherweise sichtbaren in einer sortierten Liste gespeichert werden. Diese Sortierung erfolgt von hinten nach vorne aus Sicht der isometrischen Perspektive.
Sind alle PageProxys (und Pages) durchlaufen, werden die Pages in der Liste
nacheinander gerendert. Dabei werden zuerst die Landtypen dargestellt und
dann die Wassertypen. Abschließend werden die registrierten Sprites pageweise gerendert, ebenfalls von hinten nach vorne sortiert. Abbildung 5.3 zeigt
die Unterteilung des Terrains in Tiles und Pages, sowie das Weglassen ganzer
Pages außerhalb des Viewports. Der Viewport ist durch das rote Rechteck
visualisiert und umfasst normalerweise den ganzen Bildschirm. In dieser Einstellung wurde sein Pixel-Clipping zum besseren Verständnis ausgeschaltet.
Der gesamte Renderingprozess wird in den folgenden vier Flussdiagrammen noch einmal detailiert dargestellt:
Abbildung 5.4: Auswahl der sichtbaren PageProxys
Abbildung 5.5: Auswahl der sichtbaren Pages
Abbildung 5.6: Rendern der sichtbaren Pages
Abbildung 5.7: Rendern der sichtbaren Sprites
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
Abbildung 5.3: Tiles, Pages und Viewport
45
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
Abbildung 5.4: Rendern eines Terrains (Diagramm 1 von 4)
46
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
Abbildung 5.5: Rendern eines Terrains (Diagramm 2 von 4)
47
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
Abbildung 5.6: Rendern eines Terrains (Diagramm 3 von 4)
48
KAPITEL 5. PROTOTYPISCHE UMSETZUNG
Abbildung 5.7: Rendern eines Terrains (Diagramm 4 von 4)
49
Kapitel 6
Implementierung des
Demospiels
6.1
6.1.1
Design
Allgemein
Namensfindung
Das Spiel wird auf Run To The Hills getauft. Dieser Titel beruht einerseits
auf der hügeligen Beschaffenheit des Spielareals, andererseits auf dem gleichnamigen Song der Band Iron Maiden aus dem Jahre 1982.
Hintergrund
Verschiedene Fraktionen wollen einen Planeten besiedeln. Dazu haben sie
jeweils eine stationäre, nicht einnehmbare Basis auf der Oberfläche errichtet.
Von dieser aus entsenden sie holographische Projektionen ihrer selbst, um
Territorium für sich einzunehmen.
Ziel
Die Spieler versuchen Flaggenpunkte der gegnerischen Teams einzunehmen
und die eigenen Flaggen zu verteidigen. Punkte sammeln sie, indem sie Flaggen zum eigenen Team umfärben oder andere Spieler zu ihren Spawnpunkten
zurückschicken. Das Team, welches als erstes eine bestimmte Punktezahl erreicht, gewinnt die laufende Runde. Ist in einer Welt eine voreingestellte
Anzahl von Runden gespielt worden, beginnt ein neues Spiel in einer neuen
Welt.
50
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
51
Ein möglicher Spielablauf
Der Spieler startet die Client Applikation und wird nach seinem Namen gefragt und nennt sich Dude. Zusätzlich kann er noch weitere Einstellungen, die
seinen Rechner betreffen, angeben. Danach verbindet er sich mit einem ihm
bekannten Server, auf dem bereits ein Spiel im Gange ist. Es befinden sich 23
Spieler, aufgeteilt in drei Teams (Rot, Grün und Blau) auf dem Server. Da
Team Grün zur Zeit zahlenmäßig unterlegen ist, wird Dude automatisch diesem Team zugewiesen. Jetzt wählt Dude seine Rolle, die er im Spiel ausüben
will. Er entscheidet sich für den schnellen jedoch mit schwachem Energieschild ausgerüsteten Angreifer. Außerdem bestimmt er Flagge 4 als seinen
Startpunkt, da Team Grün bereits mehrere Flaggen kontrolliert. Er wartet
die verbleiben Sekunden seiner Spawnzeit ab. [. . . ] Dude erscheint in der
Nähe der Flagge 4. Diese befindet sich auf einer kleinen, bewaldeten Insel.
Zusammen mit zwei Teamkollegen watet er durch das seichte Küstenwasser
in Richtung Flagge 6, welche gerade von fünf Spielern aus Team Rot kontrolliert wird. Der folgende Ansturm ist kurz und erfolglos: Dude und seine
Mitangreifer werden durch Antiprotonenstrahlen aufgelöst. Die drei glücklosen Angreifer müssen erneut einen Startpunkt und eine Rolle wählen, sowie
einige Sekunden auf die Rekalibrierung ihrer Projektionsmatrix warten. [. . . ]
Eine halbe Stunde später endet die Runde mit einem Sieg von Team Rot!
6.1.2
Anforderungsanalyse
√
und × siehe Abschnitt 6.2.
Zur Bedeutung der Symbole
Allgemein
• Große, zufällige Spielwelten
• Viele Spieler
√
√
• Mehr als zwei Teams
√
• Spieler sind unbelebte Hologramme
√
• Spieler starten bei festgelegten Flaggenpunkten
√
• Gegnerische Flaggenpunkte einnehmen um Punkte zu erzielen
• Eigene Flaggenpunkte verteidigen
√
• Anzahl der Flaggen richtet sich nach Weltgröße ×
√
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
52
• Einteilung in Runden und Welten ×
• Möglichkeit, andere Spieler zu einem
√Spawnpunkt (Startpunkt) zurückzuschicken um Punkte zu erzielen
• Verschiedene Spielerrollen ×
• Verschiedene Ausrüstungsgegenstände ×
• Bonuskisten ×
• Chatfunktion (Texte versenden, global oder teamintern)
√
• Teaminterne Schnellkommandos per Tastenkombination ×
• Punktelisten / Highscore, sowohl für Team als auch Einzelspieler ×
• Statistiken ×
• Continuous World (Spiel ist immer offen)
√
• Spectators (Zuschauer) sind erlaubt ×
• Verschiedene Serveroptionen
√
• Verschiedene Clientoptionen, wie Bildschirmauflösung und Farbtiefe
Der Server
Bei Serverstart werden unter anderem festgelegt:
• Weltdimension, z. B. 2562 Tiles
√
• Maximale Spielerzahl (Kapazität), z. B. 128
• Anzahl der Teams, zwischen 2 und 8
√
√
• Maximale Punkte pro Runde, z. B. 100 ×
• Runden pro Welt, z. B. 3 ×
• Friendly Fire-Anteil, z. B. 50% ×
Zur Laufzeit stehen folgende Funktionen zur Verfügung:
√
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
53
Administration
Über ein Webfrontend können Spieler in andere Teams eingeteilt, oder
vom Server gekickt (entfernt) oder gebanned (dauerhaft ausgeschlossen) werden. Außerdem können Mitteilungen an die Spieler gesendet
werden. ×
Auto Balancing
Bei Eintritt in die Welt wird dem neuen Spieler ein Team vorgeschlagen.
√
Dieser Vorschlag richten sich nach der aktuellen Teambalance.
Die Welt
• Sämtliche Eigenschaften werden zufällig generiert
√
• Verschiedene Themen, wie Mond, Erde und Fantasiewelt ×
• Verschiedene Landschaften, am Beispiel Erde:
– Animiertes Wasser (Meere, Flüsse, Seen)
– Küste
√
– Grasland
– Wald
√
√
√
– Gebirge
√
• Stufenloses Höhenprofil
√
• Wege und Straßen ×
• Einfluss der Oberflächenbeschaffenheit auf den Spielfluss ×
• Persistente Veränderungen von Höhenprofil und Oberflächen ×
• Animierbare Objekte, wie Spieler, Bäume und Kisten
Der Spieler
• Name
√
• Teamzugehörigkeit / Farbe
• Punkte pro Runde ×
• Rang pro Welt ×
√
√
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
• Position in der Welt (x, y, z)
• Ausrichtung
54
√
√
• Geschwindigkeit ×
• Rolle, wie Angreifer und Verteidiger ×
• Ausrüstung, wie Waffen und Schutzschild ×
• Hitpoints
√
Das Team
• Farbe, ev. auch Wappen
√
• Punkte pro Runde ×
• Gewonnene Runden pro Welt ×
• Homebase, Holocore,
Heimatpunkt. Dieser ist nicht von anderen Teams
√
einnehmbar
Punktewertung
Es gibt zwei Möglichkeiten, Punkte zu erlangen:
1. Desintegrieren eines Gegners
Für den Spieler 1 Punkt, für das Team ebenfalls 1 Punkt ×
2. Umfärben einer Flagge
Für den Spieler 2 Punkte, für das Team sogar 2 Punkte pro beteiligtem
Spieler ×
6.2
Implementierung
Wie in der Aufgabenstellung festgelegt, wurde das Demospiel in Zusammenarbeit mit Christian Stein entwickelt, auf dessen Diplomarbeit in diesem
Zusammenhang verwiesen wird.[5] Aufgrund der begrenzten Zeit, die für die
Implementierung zur Verfügung stand, konnten nicht alle der angedachten
Spielinhalte verwirklicht werden. Um zu zeigen, welche Zielsetzungen aus
dem vorigen Abschnitt erreicht wurden und welche
nicht, sind diese mit
√
entsprechenden Symbolen gekennzeichnet. Ein
steht für eine erfolgreiche
Umsetzung, ein × für ein Fehlen innerhalb des Spiels. Für anspruchsvollere
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
55
Graphiken, d. h. Texturen und Sprites, stand ebenfalls nicht genug Zeit zur
Verfügung. Beispielsweise sollte die Spielfigur statt der Mensch-ärger-dich”
nicht“-Variante flüssig animiert und in verschiedenen Rotationen gerendert
sein.
6.3
Screenshots
Die folgenden Screenshots wurden bei einer Auflösung von 1024x768 Pixeln
und 32 bit Farbtiefe aufgenommen. Sie sollen den Funktionsumfang und die
Qualität von Mithril im Bereich der Graphik demonstrieren. Eine Analyse
der Performanz wird an dieser Stelle nicht gegeben, da dies im Kapitel 7
erfolgt.
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
56
Abbildung 6.1: Übergang von seichtem in tiefes Wasser. Der Strand besteht
aus zwei unterschiedlichen Landtypen (trockener und feuchter Sand). Dazu kommt ansatzweise Gras als dritter Landtyp. Unter dem Wasser liegt in
Küstennähe der feuchte Sand, weiter draußen ein dunkler Meeresgrund als
insgesamt vierter Landtyp in diesem Bild
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
57
Abbildung 6.2: Strand und seichtes Wasser. Die verwendeten Landtypen entsprechen denen aus Abbildung 6.1
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
58
Abbildung 6.3: Übergang von Strand nach Wald. Der Wald besteht aus statischen Sprites (inklusive Schatten per Alphakanal) und Gras als Landtyp
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
59
Abbildung 6.4: Wald mit Flagge“. Um sie herum ist die gegenseitige Ver”
deckung der Sprites durch ihre Sortierung besonders gut zu erkennen. Neben
der Minimap“ in der Ecke ist ein Symbol zu sehen, welches die Nähe des
”
Spielers zu einer Flagge anzeigt
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
60
Abbildung 6.5: Übergänge zwischen mehreren Landtypen. Am unteren Bildrand ist eine Flagge in der Farbe des Spielers zu sehen
KAPITEL 6. IMPLEMENTIERUNG DES DEMOSPIELS
61
Abbildung 6.6: Neutrale Flagge in hügeligem Gelände. Der orangene Spieler
ist gerade dabei, sie für sein Team umzufärben“. Hier kann man erkennen,
”
daß die Flaggenkristalle transparent sind, denn der verdeckte Spieler scheint
leicht hindurch
Kapitel 7
Auswertung der Ergebnisse
7.1
Erreichte Ziele
Folgende Zielsetzungen der Anforderungsanalyse (s. Kapitel 3) konnten in
der prototypischen Umsetzung erreicht bzw. nicht erreicht werden:
7.1.1
Allgemein
Effizienz: Die Engine muss schnell sein und mit Ressourcen sparsam umgehen.
Dies ist besonders wichtig, weil sie ja nur einen von vielen Teilen eines Spiels
darstellt.
Dieser Aspekt wurde stark priorisiert und konnte erfolgreich umgesetzt
werden (s. Abschnitt 7.2).
Visuelle Qualität: Um eine hohe visuelle Qualität zu erreichen, sollen die Fähigkeiten der Graphikhardware möglichst gut ausgenutzt werden. Dabei sollte
Mithril adaptiv vorgehen und sich in seinem Vorgehen der jeweiligen Hardware anpassen.
Diese Forderung wird nur ansatzweise erfüllt. Durch die Verwendung
von Shadern könnten die Fähigkeiten der jeweiligen Graphikhardware
in einigen Fällen besser genutzt werden.
Flexibilität: Dem Benutzer soll ein hohes Maß an Freiheit geboten werden, die
Engine an seine Bedürfnisse anzupassen. Ebenso sollen eigene Erweiterungen durch wohldefinierte Schnittstellen möglich sein.
Es steht dem Benutzer frei, einige der Schnittstellen in Mithril selber zu implementieren, anstatt Standard-Implementierungen zu verwenden. Als Beispiel sei DefaultHeightmap genannt. Weiterhin sind
viele Aspekte der Engine konfigurierbar, wie z. B. das field of view. Die
62
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
63
einzelnen Komponenten (wie Sprites und Terrains) sind in ihrer Verwendung möglichst flexibel gehalten, um den Benutzer nicht unnötig
einzuschränken.
Abstraktheit: Da Mithril ein High-Level-Framework darstellt, soll die tatsächlich
verwendete Anbindung an OpenGL vor dem Benutzer verborgen werden.
Zusätzlich soll es trotzdem möglich sein, über eine Schnittstelle Low-LevelOpenGL-Befehle aufzurufen.
Die verwendete OpenGL-Anbindung wird vollständig vor dem Benutzer verborgen. Eine Schnittstelle für explizite OpenGL-Befehlsaufrufe
wurde jedoch nicht umgesetzt.
Plattform-Unabhängigkeit: Mithril soll auf unterschiedlichen Betriebssystemen laufen und sich dabei möglichst gleich verhalten. Anvisiert werden
hauptsächlich Windows und Linux.
Diese Forderung konnte komplett erfüllt werden. Zusätzlich sind auch
andere, OpenGL- und Java-fähige Systeme als Zielplattformen denkbar.
Kompatibilität: Es werden Mindestanforderungen an die Graphikhardware festgelegt. Solange diese erfüllt sind, soll jede beliebige Hardware unterstützt
werden.
Es wurden keine Mindestanforderungen explizit festgelegt. Dennoch
wurde bei der Entwicklung viel Wert auf Kompatibilität gelegt und diese durch ständige Tests auf unterschiedlicher Hardware auch erreicht:
es hat sich gezeigt, dass die Umsetzung auf nahezu allen gängigen Graphikchips bzw. -karten läuft.
Stabilität: Die Engine soll robust und fehlertolerant sein. Transparenz ist in diesem Zusammenhang besonders wichtig, so dass der Benutzer auf eventuelle
Fehler gezielt reagieren kann. Außerdem soll das System mittels detailiertem
Logging leicht zu debuggen sein.
Die Engine gibt tolerierbare Fehler als Ausnahmen (engl. exceptions)
an den Benutzer weiter, so dass er darauf reagieren kann. Fatale Fehler führen zu einer möglichst sauberen“ Beendigung des Frameworks.
”
Das integrierte Logging ist tatsächlich sehr detailiert und ermöglicht
eine schnelle und gezielte Fehlersuche.
7.1.2
√
Graphik
Ein
steht für eine erfolgreiche Umsetzung, ein × für ein Fehlen innerhalb
der Engine.
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
64
Landschaften:
• Großer Umfang
√
• Stufenloses Höhenprofil
√
• Natürlich wirkender Übergang zwischen
√ verschiedenen Oberflächen, wie
Vegetation, Gestein und Schnee
• Animierbare Wasserflächen, wie Meere, Seen und Flüsse
• Wege und Straßen
√
√
• Persistente√
Veränderungen zur Laufzeit, wie Verformungen und Verfärbungen
Innenbereiche: ×
Figuren und Objekte:
• Einzelobjekte, wie Charaktere, Fahrzeuge, Vegetation und Gebäude
√
• Fortlaufende Objekte, wie Zäune, Mauern und Stromleitungen ×
Effekte: Animierbare Spezialeffekte, wie Explosionen, Feuer und Magie.
√
Animationen:
• Präsentation:
Einzelereignis, Ereignissequenz und fortlaufendes Ereig√
nis
• Steuerung: zeit- und ereignisbasierend
√
Verhalten bei verschiedenen Auflösungen:
• Skalierung
des Sichtbereichs → Keine Skalierung der Graphikelemen√
te
• Keine Skalierung des Sichtbereichs → Skalierung der Graphikelemente
×
Selektion: Es müssen vielseitige Selektionsmöglichkeiten zur Verfügung stehen,
um Bildschirmkoordinaten (beispielsweise die Position des Mauszeigers) auf
Objekte (d. h. Sprites) und Objektkoordinaten innerhalb von Terrains und
Innenbereichen abbilden zu können.
Objektkoordinaten innerhalb eines Terrains können in Bildschirmkoordinaten projeziert werden und umgekehrt. Die Abbildung von Bildschirmkoordinaten auf Sprites ist angedacht, aber nicht realisiert worden.
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
7.1.3
65
Eingabe
Da die Eingabebehandlung über den Fensterkontext des Betriebssystems geschieht,
muss Mithril ebenfalls komfortable Schnittstellen zu Tastatur, Maus und anderen
Eingabegeräten bereitstellen.
Maus- und Tastatureingaben können flexibel abgefragt werden. Die Unterstützung weiterer Eingabegeräte wie Gamepads ist vorgesehen.
7.2
Effizienzanalyse
Basierend auf der prototypischen Umsetzung wurde ein Benchmark -Programm erstellt, welches an zahlreiche Testpersonen verteilt wurde. Insgesamt
konnten auf diese Weise Messdaten von 21 unterschiedlichen Rechnerkonfigurationen gesammelt werden. Die als relevant betrachteten Systemeigenschaften umfassen dabei Betriebssystem, Prozessor(en), Hauptspeichergröße und
-typ, Version und Hersteller der Java Virtual Machine sowie natürlich den
Graphikchip bzw. die Graphikkarte.
7.2.1
Aufbau des Tests
Der Test läuft ausschließlich und durchgehend mit einer Bildschirmauflösung
von 1024x768 Pixeln. Die dabei durchgeführten Messungen gliedern sich in
10 Phasen:
1. Einfache Sprites I: Ein einfacher Sprite der Größe 642 Pixel wird 192
mal in einem bildschirmfüllenden Gitter von 16x12 Zellen gerendert.
Der Sprite ist vollständig opaque.
2. Einfache Sprites II: Ein einfacher Sprite der Größe 642 Pixel wird
500 mal an zufälligen Positionen gerendert. Der Sprite ist vollständig
opaque.
3. Einfache Sprites III: Ein einfacher Sprite der Größe 642 Pixel wird
2000 mal an zufälligen Positionen gerendert. Der Sprite ist vollständig
opaque.
4. Animierte Sprites I: 192 animierte Sprites werden in einem bildschirmfüllenden Gitter von 16x12 Zellen gerendert. Alle referenzieren
auf dieselben Spritedaten und laufen in einer Endlosschleife ab. Die
Animation ist im Ganzen zu ca. 75% transparent und misst 642 Pixel.
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
66
5. Animierte Sprites II: 500 animierte Sprites werden an zufälligen
Positionen gerendert. Alle referenzieren auf dieselben Spritedaten und
laufen in einer Endlosschleife ab. Die Animation ist im Ganzen zu ca.
75% transparent und misst 642 Pixel.
6. Animierte Sprites III: 2000 animierte Sprites werden an zufälligen
Positionen gerendert. Alle referenzieren auf dieselben Spritedaten und
laufen in einer Endlosschleife ab. Die Animation ist im Ganzen zu ca.
75% transparent und misst 642 Pixel.
7. Terrain I: Rendern eines Terrains mit einem Landtyp ohne Wasser.
Normales field of view, welches in ca. 1500 Tiles resultiert.
8. Terrain II: Rendern eines Terrains mit einem Landtyp sowie durchgehendem Wasser eines Typs. Normales field of view, welches in ca. 1500
Tiles resultiert.
9. Terrain III: Wie Terrain I“, aber erweitert um 500 registrierte sta”
tische Sprites, zu gleichen Teilen einfache und animierte.
10. Terrain IV: Wie Terrain II“, aber erweitert um 500 registrierte sta”
tische Sprites, zu gleichen Teilen einfache und animierte.
Jede Phase dauert 20 Sekunden an. In dieser Zeit wird der jeweilige Inhalt
so oft wie möglich gerendert. Die Einzelbilder (engl. frames) werden aufsummiert und durch die Phasendauer geteilt, um die Einzelbilder pro Sekunde
(engl. frames per second, kurz FPS ) zu ermitteln.
Der Test simuliert allerdings kein echtes Spiel, in dem ja auch andere
Komponenten Systemresourcen beanspruchen würden. Die Entwicklung eines derart ausgefeilten Benchmarks hätte die dafür zur Verfügung stehende
Zeit bei weitem überschritten. Statt dessen werden die Kernfunktionalitäten
von Mithril einem Stress-Test unterzogen, der die pure Graphikleistung ermittelt.
7.2.2
Ergebnisse in Zahlen
Die folgenden Diagramme 7.1, 7.2 und 7.3 stellen die gesammelten Messdaten
nach Themen gruppiert dar. Die Reihenfolge der Testsysteme ist in allen
Diagrammen gleich und entspricht einer Sortierung gemäß der Leistung in
Phase 1.
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows 2000,
VM: 1.4.2_04-b05
67
104,4
373,3
1086,3
Intel Pentium 4 3 GHz, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows XP,
VM: 1.4.2_03-b02
89,3
367,0
1085,0
Intel Pentium 4 HT 2,4 GHz, 1024 MB
DDR, ATI Radeon 9700 Pro, Windows
XP, VM: 1.4.2_04-b05
81,9
297,3
982,3
AMD Athlon XP-M 2400+, 512 MB
SDRAM, NVIDIA GeForceFX 5900 XT,
Windows XP, VM: 1.4.2_05-b04
98,5
350,4
952,3
Intel Dual Xeon 2,8 GHz, 1024 MB
DDR, NVIDIA GeForceFX 5950 Ultra,
Windows XP, VM: 1.4.2_03-b02
68,5
AMD Athlon XP 1800+, 768 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_01-b06
67,0
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_05-b04
66,7
AMD Athlon XP 1600+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_03-b02
65,5
246,1
826,1
238,7
622,7
237,6
620,5
230,8
604,8
AMD Athlon XP 1800+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_04-b05
56,7
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_05-b04
54,0
206,0
548,1
195,7
522,6
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Windows XP,
VM: 1.4.2_05-b04
65,3
230,1
509,4
55,7
AMD Athlon 900 MHz, 512 MB
SDRAM, ATI Radeon 9600 Pro,
Windows 2000, VM: 1.4.2_03-b02
192,3
414,7
Intel Mobile Pentium 1,7 GHz, 2048 MB
DDR, ATI Mobility Fire GL T2, Windows
XP, VM: 1.4.2 (IBM)
40,4
145,5
313,0
Intel Mobile Pentium 4 2 GHz, 512 MB
DDR, NVIDIA Quadro4 500 GoGL,
Windows 2000, VM: 1.4.2_05-b04
30,1
Intel Mobile Pentium 4 2 GHz, 1024 MB
DDR, ATI Mobility Radeon 9000,
Windows XP, VM: 1.4.2_01-b06
34,0
Intel Pentium 4 1,8 GHz, 512 MB DDR,
ATI Radeon 8500, Windows XP, VM:
1.4.1_02-b06
37,2
110,8
293,9
124,8
289,9
119,8
228,0
Intel Mobile Pentium 1,6 GHz, 512 MB
SDRAM, ATI Mobility Radeon 9600,
Windows XP, VM: 1.4.2_04-b05
22,2
82,3
198,8
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Linux 2.6.8, VM:
1.4.2_05-b04
51,1
129,0
192,6
18,1
Intel Pentium 4 1,6 GHz, 256 MB DDR,
ATI Mobility Radeon 7500, Windows
XP, VM: 1.4.1_02-b06
67,1
159,3
Intel Mobile Pentium 4 1,8 GHz, 512
MB SDRAM, SiS M650, Windows 2000,
VM: 1.4.2_04-b05
31,7
Intel Mobile Pentium 3 900 MHz, 256
MB SDRAM, NVIDIA Go, Windows XP,
VM: 1.4.2_03-b02
10,9
40,1
107,7
138,8
92,9
0,0
200,0
400,0
600,0
800,0
1000,0
FPS (Frames Per Second)
192 einfache Sprites
500 einfache Sprites
2000 einfache Sprites
Abbildung 7.1: Einfache Sprites in verschiedener Anzahl
1200,0
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows 2000,
VM: 1.4.2_04-b05
68
88,6
359,3
1160,9
Intel Pentium 4 3 GHz, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows XP,
VM: 1.4.2_03-b02
77,7
Intel Pentium 4 HT 2,4 GHz, 1024 MB
DDR, ATI Radeon 9700 Pro, Windows
XP, VM: 1.4.2_04-b05
73,1
316,0
1075,8
271,1
874,1
AMD Athlon XP-M 2400+, 512 MB
SDRAM, NVIDIA GeForceFX 5900 XT,
Windows XP, VM: 1.4.2_05-b04
90,1
319,3
844,6
Intel Dual Xeon 2,8 GHz, 1024 MB
DDR, NVIDIA GeForceFX 5950 Ultra,
Windows XP, VM: 1.4.2_03-b02
58,4
218,0
751,1
AMD Athlon XP 1800+, 768 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_01-b06
72,1
261,2
607,7
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_05-b04
89,1
312,2
606,4
AMD Athlon XP 1600+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_03-b02
62,8
209,9
548,8
AMD Athlon XP 1800+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_04-b05
85,8
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_05-b04
82,8
297,0
543,9
286,0
534,5
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Windows XP,
VM: 1.4.2_05-b04
93,0
322,2
622,8
44,7
AMD Athlon 900 MHz, 512 MB
SDRAM, ATI Radeon 9600 Pro,
Windows 2000, VM: 1.4.2_03-b02
172,3
537,5
Intel Mobile Pentium 1,7 GHz, 2048 MB
DDR, ATI Mobility Fire GL T2, Windows
XP, VM: 1.4.2 (IBM)
63,0
213,4
392,6
Intel Mobile Pentium 4 2 GHz, 512 MB
DDR, NVIDIA Quadro4 500 GoGL,
Windows 2000, VM: 1.4.2_05-b04
31,9
Intel Mobile Pentium 4 2 GHz, 1024 MB
DDR, ATI Mobility Radeon 9000,
Windows XP, VM: 1.4.2_01-b06
34,0
Intel Pentium 4 1,8 GHz, 512 MB DDR,
ATI Radeon 8500, Windows XP, VM:
1.4.1_02-b06
37,5
Intel Mobile Pentium 1,6 GHz, 512 MB
SDRAM, ATI Mobility Radeon 9600,
Windows XP, VM: 1.4.2_04-b05
31,9
116,8
267,9
124,7
370,2
119,6
256,9
114,9
263,3
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Linux 2.6.8, VM:
1.4.2_05-b04
63,9
Intel Pentium 4 1,6 GHz, 256 MB DDR,
ATI Mobility Radeon 7500, Windows
XP, VM: 1.4.1_02-b06
18,1
67,0
156,2
205,0
240,5
Intel Mobile Pentium 4 1,8 GHz, 512
MB SDRAM, SiS M650, Windows 2000,
VM: 1.4.2_04-b05
29,6
Intel Mobile Pentium 3 900 MHz, 256
MB SDRAM, NVIDIA Go, Windows XP,
VM: 1.4.2_03-b02
12,5
46,2
100,8
138,2
103,8
0,0
200,0
400,0
600,0
800,0
1000,0
1200,0
1400,0
FPS (Frames Per Second)
192 animierte Sprites
500 animierte Sprites
2000 animierte Sprites
Abbildung 7.2: Animierte Sprites in verschiedener Anzahl
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
69
95,8
104,0
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows 2000,
VM: 1.4.2_04-b05
325,2
563,4
75,4
84,4
Intel Pentium 4 3 GHz, 1024 MB DDR,
ATI Radeon 9800 Pro, Windows XP,
VM: 1.4.2_03-b02
334,0
566,2
64,4
71,4
Intel Pentium 4 HT 2,4 GHz, 1024 MB
DDR, ATI Radeon 9700 Pro, Windows
XP, VM: 1.4.2_04-b05
245,3
392,9
AMD Athlon XP-M 2400+, 512 MB
SDRAM, NVIDIA GeForceFX 5900 XT,
Windows XP, VM: 1.4.2_05-b04
70,1
77,6
Intel Dual Xeon 2,8 GHz, 1024 MB
DDR, NVIDIA GeForceFX 5950 Ultra,
Windows XP, VM: 1.4.2_03-b02
75,7
80,4
193,8
303,8
344,0
498,2
83,3
93,0
AMD Athlon XP 1800+, 768 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_01-b06
221,8
363,8
110,0
122,6
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_05-b04
220,3
364,6
69,4
78,0
AMD Athlon XP 1600+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_03-b02
189,9
283,5
49,4
AMD Athlon XP 1800+, 512 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
2000, VM: 1.4.2_04-b05
74,5
66,4
140,1
111,1
123,6
AMD Athlon XP 2600+, 1024 MB DDR,
NVIDIA GeForce4 Ti4200, Windows
XP, VM: 1.4.2_05-b04
188,9
325,0
94,0
108,7
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Windows XP,
VM: 1.4.2_05-b04
201,4
423,8
39,2
48,5
AMD Athlon 900 MHz, 512 MB
SDRAM, ATI Radeon 9600 Pro,
Windows 2000, VM: 1.4.2_03-b02
76,6
160,8
89,4
Intel Mobile Pentium 1,7 GHz, 2048 MB
DDR, ATI Mobility Fire GL T2, Windows
XP, VM: 1.4.2 (IBM)
124,0
133,6
253,2
59,8
75,8
Intel Mobile Pentium 4 2 GHz, 512 MB
DDR, NVIDIA Quadro4 500 GoGL,
Windows 2000, VM: 1.4.2_05-b04
103,0
160,5
65,6
79,5
Intel Mobile Pentium 4 2 GHz, 1024 MB
DDR, ATI Mobility Radeon 9000,
Windows XP, VM: 1.4.2_01-b06
115,2
217,1
52,0
61,1
Intel Pentium 4 1,8 GHz, 512 MB DDR,
ATI Radeon 8500, Windows XP, VM:
1.4.1_02-b06
102,7
194,1
51,2
Intel Mobile Pentium 1,6 GHz, 512 MB
SDRAM, ATI Mobility Radeon 9600,
Windows XP, VM: 1.4.2_04-b05
79,4
81,5
163,2
62,9
69,0
AMD Athlon XP 2500+, 1024 MB DDR,
ATI Radeon 9600 Pro, Linux 2.6.8, VM:
1.4.2_05-b04
103,1
147,6
37,7
53,4
58,8
Intel Pentium 4 1,6 GHz, 256 MB DDR,
ATI Mobility Radeon 7500, Windows
XP, VM: 1.4.1_02-b06
103,5
Intel Mobile Pentium 4 1,8 GHz, 512
MB SDRAM, SiS M650, Windows 2000,
VM: 1.4.2_04-b05
23,8
29,3
48,7
Intel Mobile Pentium 3 900 MHz, 256
MB SDRAM, NVIDIA Go, Windows XP,
VM: 1.4.2_03-b02
23,0
32,3
39,3
91,2
77,4
0,0
100,0
200,0
300,0
400,0
500,0
600,0
FPS (Frames Per Second)
Terrain ohne Wasser
Terrain mit Wasser
Terrain ohne Wasser mit statischen Sprites
Terrain mit Wasser und statischen Sprites
Abbildung 7.3: Verschiedene Terrainkonfigurationen
KAPITEL 7. AUSWERTUNG DER ERGEBNISSE
7.2.3
70
Schlussfolgerung
Bei aller Funktionalität liegt das Hauptaugenmerk von Mithril natürlich in
der Effizienz, die für den Einsatz in Echtzeit-Spielen essentiell ist. Dieses Ziel
der prototypischen Umsetzung scheint erreicht worden zu sein, wenn man
an dieser Stelle von erforderlichen 60 FPS bei Spielen ausgeht. Allerdings
ist die letztendliche Deutung der Messdaten schwierig, da diese aus unterschiedlichen Systemkonfigurationen und funktional eng begrenzten Einzeltests resultieren. Dazu kommt die bereits angesprochene Beschränkung auf
die Graphik, wodurch von den Ergebnissen ein unbestimmter Anteil abgezogen werden muss, je nach Komplexität der Zielanwendung.
Kapitel 8
Fazit und Ausblick
In diesem Kapitel sollen die erreichten und nicht erreichten Ziele mit denen
aus der Aufgabenstellung verglichen werden, um das Gesamtergebnis der
vorliegenden Arbeit bewerten zu können.
8.1
Erreichte Ziele
In Kapitel 5 sowie in Abschnitt 7.1 wurden die erfolgreich umgesetzten Inhalte der Anforderungsanalyse und des Konzepts beschrieben. Zu beurteilen
ist nun, ob mit ihnen auch die Aufgabenstellung als erfüllt anzusehen ist.
Ziel dieser Arbeit ist die Konzeption und Entwicklung einer isometrischen Graphik-Engine, die auf den plattform-unabhängigen Standards
Java und OpenGL basiert. Diese soll in der Lage sein, komplexe Welten ansprechend und effizient darzustellen.
Nach eigener Einschätzung kann Mithril in dieser Hinsicht mehr als überzeugen. Große und vielschichtige Welten lassen sich performant und mit hoher graphischer Qualität rendern, wie das Demospiel und der Benchmark
belegen.
Um eine hohe graphische Qualität sicherzustellen wird die Möglichkeit
untersucht, Vertex- und Pixel-Shader zu unterstützen.
Bedauerlicherweise blieb während der Entwicklung des Frameworks keine
Zeit, die Unterstützung von Shadern im Konzept oder in der Umsetzung zu
berücksichtigen. Im folgenden Abschnitt 8.2.1 werden die Integration und die
Einsatzmöglichkeiten von Shadern ausblickend behandelt.
71
KAPITEL 8. FAZIT UND AUSBLICK
72
Diese Arbeit entsteht in enger Zusammenarbeit mit Christian Stein,
dessen Diplomarbeit die Entwicklung einer Massive Multiplayer Network Engine in Java umfasst. Die Realisierung eines gemeinsamen
Demospiels ist ein zusätzliches Ziel beider Arbeiten.
Das Demospiel kann die Leistungsfähigkeit beider Frameworks (Mithril und
Mamuneen [5]) eindrucksvoll unter Beweis stellen. Das Spiel läuft auf unterschiedlichster Hardware bis hin zu Laptops mit Graphikchips, deren 3DTauglichkeit bzw. Graphikleistung im Allgemeinen als eher zweifelhaft anzusehen ist. Dies kann zusätzlich als eine Erfüllung des Nebenziels“, auch
”
weniger leistungsstarke Graphikhardware zu unterstützen, gewertet werden.
8.2
Erweiterungen und Verbesserungen
Abgesehen von allgemeinen Korrekturen und Optimierungen innerhalb des
Systems sollten in der Zukunft vorallem folgende Punkte adressiert werden:
8.2.1
Shader
Vertex- und Pixelshader stellen mächtige Werkzeuge zur Erweiterung der
Engine durch den Benutzer dar. Innerhalb des Frameworks sollten daher
spezielle Schnittstellen vorgesehen werden, mit deren Hilfe eigene Shaderprogramme durch den Anwender eingebunden werden können. Diese Schnittstellen repräsentieren bestimmte Stationen innerhalb der Renderingprozesse
des Frameworks, an denen Shader anwendbar sind. Diese Stationen umfassen
beispielsweise:
• die benutzer-abhängige render()-Methode
• das Rendern von Sprites oder Terrains
Innerhalb der Terrains sind auch feinere Unterteilungen der Stationen denkbar, um nur einzelne Land- bzw. Wassertypen oder Regionen zu beeinflussen. Beispielsweise könnte ein Pixelshader speziell für den Wassertyp Lava“
”
zuständig sein, und diesen mit einem roten Glühen umgeben.
8.2.2
Innenbereiche
Innenbereiche mit den in der Anforderungsanalyse (s. Kapitel 3) formulierten
Eigenschaften sollten auf Basis der bereits umgesetzten Terrains realisierbar
sein, ohne das bestehende Konzept grundlegend verändern zu müssen. Für
KAPITEL 8. FAZIT UND AUSBLICK
73
die neuen Komponenten wie Wände, Türen und Aufzüge müssen zusätzliche
und teilweise variable Geometrien eingeführt werden. Diese sind vermutlich
auch für die ebenfalls noch fehlenden fortlaufenden“ Terrain-Objekte wie
”
Zäune und Stromleitungen geeignet.
8.2.3
Verschiedenes
Mobile Endgeräte: Es ist zu untersuchen, ob Mithril im Ganzen oder in
einer verkleinerten Version auf mobilen Endgeräten einsetzbar ist. Derzeit werden verstärkt 3D-Chips für Geräte wie beispielsweise Mobiltelefone entwickelt, die in Zukunft voraussichtlich zum Standard werden.
Bessere Schriftausgabe: Das Rendering von Schrift und das generelle FontSystem muss verbessert werden, um beispielsweise Schriften mit variablem Zeichenabstand zu unterstützen.
Bessere Selektion: Über die bestehenden Selektionsmöglichkeiten hinaus
sollten auch Sprites komfortabel selektierbar sein. Dabei könnte neben
der bounding box auch der Alphawert eines Sprites ein Selektionskriterium sein.
Fog: Das in OpenGL zur Verfügung stehende Fog Array, als Teil der Vertex Arrays, könnte für visuelle Effekte innerhalb der Terrains genutzt
werden.
Flexibleres Multitexturing: Land- und Wassertypen sollten mit Detailtexturen ausstattbar sein, die per Multitexturing umgesetzt werden.
Speziell beim Wasser sollte die Animation der Texturmatrizen konfigurierbar sein.
Mehr Eingabegeräte: Zusätzliche Eingabegeräte wie Joysticks und Gamepads sollten unterstützt werden.
task switch: Der Wechsel zwischen mehreren laufenden Programmen (in
Windows mittels der Tastenkombination ALT+TAB) ist derzeit nicht
möglich und sollte realisiert werden.
Partikelsysteme: Die meist zur Umsetzung von Spezialeffekten genutzten
Partikelsysteme könnten auf der Basis von Sprites in Mithril umgesetzt werden.
Literaturverzeichnis
[1] OpenGL Architecture Review Board. OpenGL Reference Manual (Fourth
Edition): The Official Reference Document to OpenGL, Version 1.4.
Addison-Wesley, 2004. 41
[2] Eclipse Foundation. SWT - Standard Widget Toolkit, 2004.
http://eclipse.org/swt. 39
[3] lwjgl.org. Lightweight Java Game Library, 2004.
http://lwjgl.org. 39
[4] Ernest Pazera. Isometric Game Programming with DirectX 7.0. Stacy L.
Hiquet, 2001. 10, 12
[5] Christian Stein. Entwicklung einer Massive Multiplayer Engine in Java,
2004. Diplomarbeit. Universitt Koblenz-Landau, Standort Koblenz. 54,
72
[6] Sun Microsystems, Inc. Java bindings for OpenGL, 2004.
http://jogl.dev.java.net. 38
[7] Sun Microsystems, Inc. Java3D API, 2004.
http://java.sun.com/products/java-media/3D. 27
74
Index
2D-Hardware, 12
3D-Hardware, 12
PageProxy, 42
Paging, 44
Abstraktheit, 21
Anforderungsanalyse, 14
API, 18
Ausblick, 71
Auswertung der Ergebnisse, 62
Axonometrie, 6
Run To The Hills, 50
Benchmark, 65
Demospiel, 50
Dimetrie, 7
Einleitung, 6
Factory, 21
Fazit, 71
FPS, 66
Indizes, 41
Interface, 18
Isometrie, 7
JOGL, 38
Konzeption, 18
LWJGL, 39
Schnittstelle, 18
Sprite, 10
animierte, 30
einfache, 30
SWT, 39
Systeme
bestehende, 8
Tile, 10
Trimetrie, 7
Umsetzung
prototypische, 38
Verfahren
bestehende, 8
hybride, 13
modell-basierende, 13
tile-basierende, 10
Verkürzungsfaktor, 7
Vertex Arrays, 41
Wrapperklasse, 20
Zaxxon, 8
Marble Madness, 8
Mithril, 14
Node, 32
Page, 42
75