Tutorial Bomberman2: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
K (Eine Textur)
K (Soundsystem)
Zeile 328: Zeile 328:
  
 
So viel also zu den verwendeten Techniken. Fehlen tut in der Liste zwar der Texturenmanager, diesen haben wir allerdings schon im letzten Tutorial besprochen, das ihr ja alle bestimmt aufmerksam gelesen habt ;-)
 
So viel also zu den verwendeten Techniken. Fehlen tut in der Liste zwar der Texturenmanager, diesen haben wir allerdings schon im letzten Tutorial besprochen, das ihr ja alle bestimmt aufmerksam gelesen habt ;-)
 +
 +
 +
==Verwendete Dateiformate==

Version vom 24. Dezember 2005, 14:56 Uhr

Bomberman.gif

Wir programmieren einen Bombermanklon!

Teil 1 : Die Codebasis und der Editor

Vorwort

Ave, und willkommen zum zweiten Tutorial der Bombermanserie! Nachdem wir uns im ersten Tutorial mit der Programmierung eines Editor und der grundlegenden Codebasis beschäftigt haben, gehts nun ans Eingemachte, nämlich den 3D-Bombermanklon.

Da der Quellcode unseres Klons recht umfangreich ist, und in diesem Tutorial viele neue Techniken behandelt werden, wirds vielleicht etwas langatmig. Aber keine Angst, denn zum einen versuche ich alles recht ausführlich und auch für Neulinge verständlich zu erklären, und zum anderen werdet ihr am Ende dieses Tutorials einen kompletten Bombermanklon programmiert haben der euch (und eure Bekannten) mit stundenlangem Spielspaß belohnt!

Deshalb gibts zum Ansporn erstmal zwei nette Screenshots direkt aus dem Spiel :

Tutorial Bomberman2 nbomber1.jpgTutorial Bomberman2 nbomber2.jpg


Voraussetzungen

Wie schon im ersten Tutorial vorausgesetzt, solltet ihr recht gute Kenntnisse in Object Pascal und OpenGL mitbringen. Des Weiteren werde ich in unserem Quellcode starken Gebrauch von dynamischen Arrays machen, deren Nutzung und Verwaltung besonders für Personen die sich damit noch nicht beschäftigt haben recht verwirrend sein kann. Deshalb sind gute Kenntnisse zum Thema dynamische Arrays unentbehrlich. Aber keine Angst, denn alles was man zu diesem Thema braucht, findet sich in der Delphi-Hilfe.

Neben der programmiertechnischen Seite, erfordert das Erschaffen eines Spiels natürlich auch den Umgang mit diversen Anwendungen. Einige davon sind kleine Tools, die sich mit einem Klick bedienen lassen während andere Programme eine nicht unerheblich Einarbeitungszeit voraussetzen. Die von mir genutzten Anwendungen und Tools im Überblick :

Komerzielle Anwendungen
Tutorial Bomberman2 app 3dsmax.jpg 3D Studio MAX

Dieses 3D-Modellierungs und Renderprogramm dürfte wohl jedem ein Begriff sein, ist es doch eines der meistgenutzten Programme in der Spielebranche, und man wird wohl kaum ohne grundlegende Kenntnisse in diesem Programm auskommen.

Wenn man sich erstmal (mittels des sehr gute Handbuches/mitgelieferten Tuts) eingearbeitet hat, dann geht das Erstellen von 3D-Modellen sehr leicht von der Hand. Den Hauptaktor unseres Bombermanklons hab ich in knapp 5 Min. erstellt.

Alternativen :
Als Alternative kommen eigentlich alle Programme in Frage, die in der Lage sind in das 3DS-Format zu exportieren, wie z.B. :
Blender, Milksphape3D, Maya

Tutorial Bomberman2 app photoshop.jpg Adobe Photoshop

Zu diesem Bildbearbeitungsprogramm muß ich wohl auch kaum was erzählen. Für alle die es nicht kennen : Das momentan wohl mächtigste Bildbearbeitungsprogramm. Die Einarbeitung ist nicht gerade einfach, doch wenn man sich mit diesem Programm erstmal auskennt, ist das Erstellen von guten Grafiken und Texturen schnell erledigt.

Alternativen :
Micrografx Picture Publisher, Gimp, JASC Paintshop Pro

Kostenlose Tools
Tutorial Bomberman2 tools explosion generator.jpg
Explosion Generator

Dieses sehr praktische Tool rendert eine komplette Explosion in eine Textur, so daß man diese als Grundlage für eine Explosionsanimation ins einer Anwendung nutzen kann. Nachteil der Sache ist, das sich das Erscheinungsbild der Explosion nur manuell über eine Textdatei anpassen lässt.

Link : www.positech.co.uk

Tutorial Bomberman2 tools bitmapfont builder.jpg Bitmapfont Builder

Mit diesem Programm lassen sich in Windeseile die für Bitmapfonts benötigten Fonttexturen auf Basis der in Windows verfügbaren Schriftarten erstellen.

Link : www.lmnopc.com

Soviel also zu den (von mir) genutzten Anwendungen und Tools. Natürlich steht euch die Wahl frei, und ihr könnt die Tools und Programme eurer Wahl nutzen.


Ziel

Wie schon kurz im Vorwort erwähnt, werden wir in diesem Tutorial einen kompletten Bombermanklon programmieren. Ziel dabei ist es, eine saubere Codebasis zu schreiben und euch grundlegende Techniken der Spieleprogrammierung beizubringen.

Außerdem möchte ich euch einen recht sauberen Programmierstil beibringen, der bei vielen missen lässt und Programmcodes für andere oft unnutzbar macht.

Folgendes wird euch im Tutorial erwarten, und euch auch bei zukünftigen Ausflügen in die Welt der Spieleprogrammierung von Nutzen sein :


Tutorial Bomberman2 superbomberman help.gif
  • Timebased Movement (Frameunabhängige Bewegungen)
  • Texturenfonts
  • Statemachine
  • Kollisionsabfrage
  • Sound (via FMOD)


Projektstruktur

Widmen wir uns nun kurz der Projektstruktur. Gemeint sind damit die genutzten Units, deren Funktion und Inhalt. Was genau wo gemacht wird, darüber werden wir uns später unterhalten.

Bei eurer Projektstruktur solltet ihr vor allem darauf achten, nicht alles in eine Unit zu packen. Zum einen kann das später nämlich eingige Probleme machen (ich sage nur Kreuzbezüge) und zum anderen schadet es der Portabilität. Damit sind z.B. wiederverwendbare Programmteile wie der Texturenmanager oder das Soundsystem gemeint, die wenn sie in eine externe Unit ausgelagert werden, später ohne großen Aufwand in andere Projekte eingebunden werden können. Dadurch spart man sich über die Zeit sehr viel Arbeit und baut sich nach und nach mit jedem Projekt eine größere Codebasis auf.

Wichtig ist natürlich (wie auch bei euren Variablen) die Namensgebung. Es scheint zwar verlockend, Objekt- oder Unitnamen so kurz wie möglich zu halten (besonders dann wenn man schreibfaul ist), aber das wird sich früher oder später rächen. Wenn man dann nämlich dutzende Units mit kryptischen Namen in denen dutzende Objekte mit noch kryptischeren Namen verteilt sind quer auf der Platte verteilt hat, fällt die Wiederverwendung und Zuordnung recht schwer!

Projektunits

Nachfolgend gebe ich einen kurzen Überblick über alle dem Projekt zugehörigen Units und deren Inhalt.

Icon unit.gifNapalmBomber3D_1.pas

In dieser Unit befindet sich das Hauptformular unseres Bombermanklons. Hier findet neben der Initialisierung einiger wichtiger Variablen und Objekte nichts wirklich Interessantes statt.

Icon unit.gifBombermanGlobal.pas

Dies ist wie der Name schon vermuten lässt der Sitz unserer Codebasis und somit auch die wichtigste Unit unseres Projektes. Im letzten Tutorial hieß sie noch global.pas, wurde jedoch aufgrund der besseren Übersicht umbenannt.

Icon unit.gifBombermanTextureManager.pas

Naja, ich glaube es ist ein Einfaches anhand der Namensgebung herauszufinden was sich hinter dieser Unit versteckt. Im letzten Tutorial befand sich unser Texturenmanager noch in der globalen Unit. Allerdings will unser 3DS-Lader diesen Texturenmanager auch nutzen, und um Kreuzbezüge zu vermeiden habe ich ihn deshalb in eine extra Unit ausgelagert.
Vorteil ist, neben der Tatsache das er nun von mehrern Units genutzt werden kann, auch noch die praktische Tatsache das man diese Unit unverändert für seine anderen Projekte nutzen kann. Also quasi ein Texturenmanager mit Zukunft.

Icon unit.gifBombermanSoundSystem.pas

Auch hier sollte die Unitfunktion anhand der Namensgebung recht einfach zu erkennen sein. Hier befindet sich das (momentan noch recht einfache) Soundsystem. Vorteil der Auslagerung in eine estra Unit ist auch hier die Portabilität.

Icon unit.gifBombermanFont.pas

In dieser Unit befindet sich unser Fontsystem zur Ausgabe von Bitmapfonts.Mehr dazu später.

Icon unit.gifBombermanLoad3DS.pas

Diese Unit bietet einige einfache Methode um 3D-Modelle im 3DS-Format zu laden und in eine unter OpenGL darstellbare DisplayListe zu wandeln.
Die Unit basiert ursprünglich auf dem 3DS-Loader von Mike Lischke, und wurde von mir vereinfacht. Deshalb wirds hierzu keine genaue Erklärung geben.


Fremdunits

Nachdem ich vorher alle dem Projekt zugehörigen Units aufgezählt habe, gibts hier noch einen ganz kurzen Überblick über die Fremdunits, die vom Projekt benötigt werden.

Icon unit.gifUtils3DS.pas,Const3DS.pas,File3DS.pas,Types3DS.pas

Diese Units werden von unserem 3DS-Lader benötigt und stammen auch aus Mike Lischkes 3DS-Packet.

Icon unit.giffmod.pas,fmodtypes.pas,fmoddyn.pas,fmoderros.pas,fmodpresets.pas

Auch hier lässt die Namensgebung recht schnell auf die Units für die FMOD-Library schliessen, die als Grundlage für unser Soundsystem dient.

Icon unit.gifGLBmp.pas

Zu dieser Unit muß ich wohl kaum noch viele Worte verlieren, haben wir diese doch schon im Editor zum Laden der Texturen genutzt.
Quelle : http://delphigl.cfxweb.net

Icon unit.gifOpenGL12.pas

Auch zu dieser Unit gibts nicht viel zu sagen. Sie beinhaltet alle nötigen Deklarationen und Funktionen zur Nutzung von OpenGL (1.2).


Verwendete Techniken

Bevor wir uns also in den Quellcode stürzen, werde ich hier kurz die verwendeten Techniken, deren Nutzen und deren Umsetzung erklären. Alle hier erwähnten Dinge werdet ihr in weiteren Projekten verwenden können und sind für das Gelingen größerer Projekte fast unerlässlich, also lest aufmerksam!


Tutorial Bomberman2 bombermanbomb.gif

Timebased Movement

Bisher werden viele von euch (wenn sie denn schonmal ein kleines Spiel programmiert haben) die Ereignisse wie z.B. Spielerbewegung oder das aktualisieren einer Animation am Ende eines jeweiligen Frames abgearbeitet haben. Das ist zwar eine einfache Lösung, hat jedoch den riesigen Nachteil, dass Bewegungen und Animationen je nach Rendergeschwindigkeit (sprich Anzahl der pro Sekunde berechneten Bilder) verschieden sind. Daraus resultiert z.B., das sich eine Spielfigur auf einem schnellen Rechner unkontrollierbar schnell nach vorne bewegt, während sie auf einem langsamen Rechner kaum von der Stelle kommt. Besonders schlecht ist sowas in einem Netzwerkspiel, da der Spieler am langsamen Rechner durch die langsamere Bewegung einen großen Nachteil hat. Abhilfe schafft hier das sog. "Timebased Movement" (zu Deutsch : Zeitbasierte Bewegung), welches für gleichmäßige Bewegungen bzw. Animationen sorgt, in dem es (im Gegensatz zum "Framebased Movement") diese mittels Zeitmessung auf einen festen Faktor angleicht.

Die Implementation dieser Technik ist zum Glück recht einfach, bietet uns Windows doch netterweise (über einen im Chipsatz integrierten Timer) einen Hochpräzisionstimer dessen Auflösung um ein Tausendfaches höher ist als die eines Systemtimers. Damit wird es uns möglich die oft nur sehr geringen Zeitabstände zwischen dem Rendern der Frames zu berechnen. Ein kleines Beispiel : Ein moderner Rechner schafft heute in einer nicht besonders Aufwendigen 3D-Szene ohne Probleme an die 300-400 Bilder pro Sekunde. Dies bedeutet, das er zum Berechnen und Ausgeben eines Bildes 2,5ms (=1000ms/400fps) benötigt. Ein normaler Systemtimer würde uns eine solche Messung mit seiner "Genauigkeit" von ~55ms gänzlich unmöglich machen.

Windows bietet uns nun zwei Funktionen zur Nutzung dieses Hochpräzisionstimer an :

  • function QueryPerformanceFrequency(var lpFrequency : TLargeInteger): Bool;
Diese Funktion liefert uns in lpPerformanceCount die Anzahl der Takte pro Sekunde zurück, also die Auflösung des Timers. Dieser Wert variiert von Chipsatz zu Chipsatz und muß deshalb unbedingt beim Programmstart abgefragt und in einer Variable abgelegt werden.
Meine Hauptplatine auf Basis des nVidia nForce2-Chipsatz liefert z.B. den Wert 3579545, d.h. dass der Hochpräzisionstimer genau 3.579.545 mal pro Sekunde taktet.
  • function QueryPerformanceCounter(var lpPerformanceCount : TLargeInteger): Bool;
Obige Funktion liefert uns in lpPerformanceCount den aktuellen Stand des Hochpräzisionscounter, gemessen in Systemtakten zurück, und wird von uns zur genauen Zeitmessung genutzt.


Ermitteln der Counterfrequenz

Wie schon in der Funktionsbeschreibung erwähnt müssen wir vor der Nutzung des Hochpräzisionscounters erstmal dessen Frequenz ermitteln. Dies tun wir direkt beim Start unseres Programms im OnCreate-Ereignis des Hauptfensters :

procedure TBomberManForm.FormCreate(Sender: TObject);
begin
QueryPerformanceFrequency(PerfCounterFreq);
[...]
end;


Die Variable PerfCounterFreq wird in der Unit BombermanGlobal.pas deklariert und ist vom Typ Int64. In dieser ist von nun an die Frequenz unseres Hochpräzisionstimers hinterlegt. Sofern dieser Wert < 0 ist, läuft alles nach Plan.

Die Zeitmessung

Nach der recht langen Präambel widmen wir uns nun dem eigentlich Kern des Timebased Movements, nämlich der Zeitmessung. Diese wird in in der DrawScene-Prozedur unseres TBombermanGame-Objektes (BombermanGlobal.pas) umgesetzt :

procedure TBomberManGame.DrawScene;
var
 QPCStartCount, QPCEndCount : Int64;
begin
QueryPerformanceCounter(QPCStartCount);
[...]
// Szene zeichnen
[...]
QueryPerformanceCounter(QPCEndCount);


Der Quellcode spricht eigentlich für sich. Wir ermitteln insgesamt zwei Zeitwerte, zum einen vor dem Zeichnen der Szene und zum anderen nach dem Zeichnen der Szene, und speichern diese ab. Danach berechnen wir über eine recht einfache Formel unseren Zeitfaktor :

BomberManGame.TimeFactor := (QPCEndCount-QPCStartCount)/PerfCounterFreq*100;
end;


Dieser Zeitfaktor entspricht dann der zum Rendern benötigten Zeit in ms/10 und kann dann beim aktualisieren der Bewegungen bzw. Animationen als Faktor genutzt werden.

Kleine Rechenkunde

Um denn Sinn und die Funktion des Timebased Movement besser verstehen zu können, gibts hier ein paar kleine Rechenbeispiele, die darlegen dass der Code nun frameunabhängig Funktioniert :

Rechner 1 braucht 7 ms um die Szene zu Rendern

Zeitfaktor = 0.7
Bewegung des Spieler = 0.05*0.7 = 0,035 Einheiten
Bewegungen werden 142 mal pro Sekunde aktualisiert (142fps)
Gesamtbewegung/s = 142*0,035 = 4,97 Einheiten
Ohne Timebased Movement : Gesamtbewegung = 142*0,05 = 7,1 Einheiten

Rechner 2 braucht 11 ms um die Szene zu Rendern

Zeitfaktor = 1.1
Bewegung des Spieler = 0.05*1.1 = 0,055 Einheiten
Bewegungen werden 90 mal pro Sekunde aktualisiert (90fps)
Gesamtbewegung/s = 90*0,055 = 4,95 Einheiten
Ohne Timebased Movement : Gesamtbewegung = 90*0,05 = 4,5 Einheiten

Ich hoffe mal, dass diese beiden Beispiele verdeutlichen, das sich der Spieler unter Zuhilfenahme des Timebased Movements auf verschieden schnellen Rechner (und in verschieden komplexen Szenen) mit gleicher Geschwindigkeit bewegt. Die Diskrepanz vin 0,02 Einheiten bei obigen Werten ist darauf zurückzuführen, dass ich mit abgerundeten Werten gerechnet habe.

Auch wenn dieser Teil des Tuts etwas theoretisch und trocken war, so ist das Timebased Movement, wie ihr sicher schon aus dem Text herauslesen konntet unerlässlich für moderne Spieletitel, und zwar ganz besonders dann wenn diese später auch im Netzwerk bzw. über das Internet spielbar sein sollen. Allerdings wird sich Bomberman drüber freuen, das er sich jetzt auf jedem System gleichschnell fortbewegen kann... Bomberman wait.gif


Tutorial Bomberman2 bombermanbomb.gif

Statemachine

Auch diesen Begriff dürften einige von euch schonmal irgendwo aufgeschnappt haben. Vermutlich war das aber in einem anderen und weitaus komplexerem Zusammenhang als dies bei unserer (recht primitiven) Statemachine der Fall ist.

Spiele bestehen ja bekannterweise aus verschiedenen Szene (=States) wie z.B. dem Hauptmenü und der 3D-Ansicht. Die Statemachine macht in unserem Falle nichts anderes als den in TBombermanGame.CurrentState gesetzten Status abzufragen und dann in die entsprechende Zeichenroutine zu verzweigen. So hat man die für die einzelnen Szenen erforderlichen Zeichneroutinen in verschiedene Prozeduren separiert und kann später bequem und ohne großen Aufwand neue Szenen hinzufügen.

Für jede Szene deklarieren wir in der Konstantensektion der globalen Unit eine eigene Konstanten, anhand derer sie eindeutig identifiziert werden kann :

      const
       GSMainMenu  = $00;
       GSNewGame   = $01;
       GSInGame    = $02;
       GSMatchEnd  = $03;


Die Statemachine prüft dann in der Zeichenprozedur TBombermanGame.DrawScene in welchem Status sie sich befindet und verzweigt dann mittels einer einfachen Case-Anweisung zur entsprechenden Zeichneroutine :

      procedure TBomberManGame.DrawScene;
      [...]
      case CurrentState of
       GSMainMenu : DrawScene_GSMainMenu;
       GSNewGame  : DrawScene_GSNewGame;
       GSInGame   : DrawScene_GSInGame;
       GSMatchEnd : DrawScene_GSMatchEnd;
      else
       DrawScene_GSMainMenu;
      end;
      [...]


Den Status unserer Statemachine setzen wir dann mittels der Prozedur TBombermanGame.SetState. Aber warum tun wir das nicht direkt über die Variable TBombermanGame.CurrentState? Dafür gibts einen ganz einfachen Grund : Es ist möglich, dass beim Wechsel zwischen zwei Zuständen verschiedene Variablen geändert oder gesetzt werden müssen. Wechseln wir den Status also über oben genannte Prozedur, so können wir vor dem finalen Wechsel noch prüfen in welchen Status gewechselt wird, und eventuell noch benötigte Variablen setzen oder verändern.

Auch wenn oben beschriebenes recht banal erscheinen mag, so ist eine Statemachine (egal wie primitiv) ein einfaches Mittel zur Verwaltung des Spielzustandes, die sich dazu noch recht leicht erweitern lässt.


Tutorial Bomberman2 bombermanbomb.gif

Texturenfonts

Was vielen ein Dorn im Auge ist, und sich hoffentlich bald ändert, ist das Fehlen von Routinen zur Fontdarstellung in OpenGL. Aber zum Glück haben sich einige findige Programmierer zu diesem Thema Gedanken gemacht und Methoden zur Schriftdarstellung mittels OpenGL entwickelt die recht einfach zu nutzen und gleichzeitig schnell sind. Eine davon sind Texturenfonts, die wie deren Name schon vermuten lässt, ihre Schriftzeichen aus einer Textur herausholen.

Ein Tool das diese Texturen erstellen kann, wurde von mir bereits am Anfang dieses Tutorials vorgestellt, nämlich der Bitmap Font Builder. Dieser erstellt auf der Basis einer Windowsschriftart eine Textur die alle nötigen Schriftzeichen enthält, und z.B. so aussehen könnte :

Tutorial Bomberman2 texfont.jpg

Das Erstellen und Ausgeben dieser Schrift erledigt für uns die Klasse TTexFont in der Unit TBombermanFont.pas. Dort finden sich am Anfang in der Konstantesektion die vorgenerierten Texturenkoordinaten für die einzelnen Buchstaben. Da grundlegende Kenntnisse zum Thema Texturemapping eine Voraussetzung für dieses Tut sind, gehe ich davon aus das ihr wisst was diese zu bedeuten haben und wie sie funktionieren.

Unsere TTexFont-Klasse tut jetzt bei der Initialiserung nichts anderes, als für jedes in der Textur hinterlegte Schriftzeichen anhand der in der Konstantesektion festgelegten Texturkoordinate eine Displayliste zu erstellen, die beim Ausgeben des Textes dann nur noch aufgerufen wird.


Tutorial Bomberman2 bombermanbomb.gif

Animierte Texturen

In unserem Bombermanklon nutzen wir für die Explosionen animierte Texturen. Diese animierten Explosionen lassen sich auf zwei Arten realisieren :

Verschiedene Texturen

Wir laden für jede Explosionsphase eine eigene Textur. Dazu benötigen wir also 16 Texturen, die auf der Festplatte recht viel Speicher beanschlagen. Je nach Explosionsphase binden wir nun vor dem Zeichnen des Explosionsquad die zur aktuellen Explosionsphare gehöhrende Textur.

Diese Methode ist zwar recht einfach zu implementieren, hat jedoch einige Nachteile : Da jede Animationsphase in einer eigenen Textur liegt wird sowohl auf der Festplatte als auch im Grafikspeicher recht viel Overhead erzeugt.


Eine Textur

Dies ist die Lösung die wir verwenden werden, da sie recht viele Vorteile beherbergt. Wir erstellen uns mittels eines Tools (z.b. den am Anfang des Tuts erwähnten ExplosionsGenerator) eine Textur auf der in Reihen und Spalten alle Animationsphasen der Explosion dargestellt sind.

Nun binden wir für jedes Explosionsquad dieselbe Textur und verändern entsprechend der Animationsphase nur unsere Texturkoordinaten, die wir in einem speziellen Array abgelegt haben :

ExpTexCoord : array[0..15, 0..3] of Single =
  ((0, 0,    0.25, 0.25), (0.25, 0,     0.5, 0.25), (0.5, 0,    0.75, 0.25), (0.75, 0,    1, 0.25),
   (0, 0.25, 0.25, 0.5),  (0.25, 0.25,  0.5, 0.5),  (0.5, 0.25, 0.75, 0.5),  (0.75, 0.25, 1, 0.5),
   (0, 0.5,  0.25, 0.75), (0.25, 0.5,   0.5, 0.75), (0.5, 0.5,  0.75, 0.75), (0.75, 0.5,  1, 0.75),
   (0, 0.75, 0.25, 1),    (0.25, 0.75,  0.5, 1),    (0.5, 0.75, 0.75, 1),    (0.75, 0.75, 1, 1));


Wenn man sich dieses Array genauer betrachtet, dann kann man schon erahnen das unsere Explosionstextur in 4x4 Zellen aufgeteilt ist, und von links nach rechts verläuft. Links seht ihr die vom Explosionsgenerator erstellte Textur, und rechts selbige mit ein paar von mir eingetragenen Texturkoordinaten, die euch das Verständnis dieser Technik ein wenig erleichtern sollten :

Tutorial Bomberman2 explosion.jpgExplosion det.jpg

Wer also weiß wie man mit Texturkoordinaten umgeht dürfte hier absolut keine Verständnisprobleme haben. Unser Quad zeichnen wir dann wie folgt (siehe TMap.Draw) :

glBegin(GL_QUADS);
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][0], -ExpTexCoord[Round(ExplosionPhase)][3]);  glVertex3f(0, 0, 0);
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][2], -ExpTexCoord[Round(ExplosionPhase)][3]);  glVertex3f(2, 0, 0);
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][2], -ExpTexCoord[Round(ExplosionPhase)][1]);  glVertex3f(2, 2, 0);
 glTexCoord2f(ExpTexCoord[Round(ExplosionPhase)][0], -ExpTexCoord[Round(ExplosionPhase)][1]);  glVertex3f(0, 2, 0);
glEnd;


Wie leicht zu erkennen nehmen wir unsere Texturkoordinaten anhand der aktuellen Explosionsphase aus unserem vorher in der Konstantensektion deklariertem Koordinatenarray. Bei ExplosionPhase=0 sieht unser Quad also so aus :

glBegin(GL_QUADS);
 glTexCoord2f(0,    -0.75); glVertex3f(0, 0, 0);
 glTexCoord2f(0.25, -0.75); glVertex3f(2, 0, 0);
 glTexCoord2f(0.25,  0);    glVertex3f(2, 2, 0);
 glTexCoord2f(0,     0);    glVertex3f(0, 2, 0);
glEnd;


Der offensichtliche Vorteil dieser Methode ist die Tatsache, das die komplette Animation in einer Textur abgelegt ist, und somit nur eine Textur auf der Festplatte sowie im Grafikkartenspeicher Platz verbraucht.


Tutorial Bomberman2 bombermanbomb.gif

Soundsystem

Zu einer intensiven Spielumgebung gehören natürlich nicht nur aufwendige Grafiken, sondern auch Soundeffekte die dem Spieler das Gefühl vermitteln, er bewege sich inmitten einer dreidimensionalen Umgebung.


Hier springt unser Soundsystem ein (BombermanSoundSystem.pas), welches einfache Routinen zur Initialiserung und Ausgabe von Soundateien mitbringt.

Auf dem Markt gibt es inzwischen einige sehr gute Soundlibraries, die vor allem für Freewareprogramme kostenlos nutzbar sind. Deshalb machen wir von einer dieser Soundbibliotheken gebrauch, nämlich fmod, dessen Vorteile ein riesiger Funktionsumfang und die Nutzung aller gängigen Soundformate ist.

Unser Soundsystem tut deshalb nichts anderes als diese (sowieso schon einfach nutzbare) Bibiliothek zu kapseln. So kann man später einfach auf eine andere Bibliothek umsteigen, oder sein Soundsystem komplett selbst z.B. unter Verwendung von DirectSound programmieren.


Auf die Funktionsweise bzw. Implementation von fmod werde ich hier jedoch nicht genauer eingehen. Die mit dieser Bibliothek gelieferten Hilfedateien und Beispiele sind so ausführlich, dass jede weitere Dokumentation Zeitverschwendung wäre.

Unsere Implementation der FMOD-Library ins Soundsystem werden wir später aber noch genauer betrachten.


So viel also zu den verwendeten Techniken. Fehlen tut in der Liste zwar der Texturenmanager, diesen haben wir allerdings schon im letzten Tutorial besprochen, das ihr ja alle bestimmt aufmerksam gelesen habt ;-)


Verwendete Dateiformate