Mittwoch, 7. Januar 2009


Artikel

Mai 2008 | Artikel

Get rich and famous, be a game designer! (Teil 2)

(Link zum Artikel: http://www.phpconference.com/dotnet/artikel/1763)

Einführung in das XNA Framework

Text: Jens Konerow
Mit dem XNA Framework und XNA Game Studio Express läutet Microsoft eine neue Ära ein. Nicht nur, dass sich die Umsetzung komplexer Vorgänge deutlich vereinfacht, mit XNA umgesetzte Spiele laufen auch auf einer Xbox 360 und lassen sich, so wie früher, auch am TV spielen. Dies ist aber nur ein Nebeneffekt, der Hauptvorteil von XNA ist, dass es zum Beispiel den Umgang mit Sprites und Background Scrolling deutlich einfacher macht, als es in der Vergangenheit der Fall war.
Teil 1   Teil 2   Teil 3   Teil 4   Teil 5   

Der erste Teil der XNA-Serie beschäftigte sich neben den Grundlagen mit der Darstellung von Sprites und der Realisierung einer Sprite-Animation. Diese diente im ersten Spieleprojekt zur Darstellung von Explosionen. Damit der Eindruck eines fliegenden Objekts entsteht, bedient sich das Spiele-Projekt, das in dieser Folge vorgestellt wird, dem bekannten Background Scrolling. Bei diesem Verfahren wird eine Grafik als Sprite permanent von oben nach unten verschoben. Außerdem wird eine Datenstruktur entwickelt, die bei der Verwaltung aller Bildschirminhalte behilflich ist. Eine weitere Datenstruktur gliedert Quellcode und ermöglicht die Verwaltung der Spielstatistik. Wie es praktisch bei jedem Computerspiel üblich ist, beginnt das Spiel mit dem Anzeigen einer Menüauswahl. Am Ende werden alle vorgestellten Bestandteile zu einem großen Ganzen zusammengefügt (einen Vorgeschmack gibt Abbildung 1) und mit einer Portion „Spielelogik“ (dazu zählt z.B. die Kollisionskontrolle) angereichtert.

Background Scrolling

Voraussetzung für eine erfolgreiche Umsetzung des Background Scrollings ist eine überdimensionale Textur, die kachelbar ist. Überdimensional bedeutet, dass die Grafik zumindest höher oder breiter sein muss als der Back Buffer (Abbildung 2). Kachelbar heißt, dass die Ränder der Textur so konzipiert sind, dass beim Zusammensetzen zweier Teile kein Bruch entsteht. Andernfalls verfehlt die Täuschung eines unendlich großen Hintergrunds sein Ziel.

Zur Implementierung des Background Scrollings bedarf es einer Update-Methode, welche die Y-Komponente eines 2DVektors kontinuierlich inkrementiert, um den Hintergrund von oben nach unten zu verschieben. Die Größe des Summanden steht in Relation mit der verstrichenen Zeit seit dem letzten Frame. Das gewährleistet dieselbe Geschwindigkeit auf allen Systemkonfigurationen. Übersteigt der Wert der Y-Koordinate die Höhe der Textur, muss die Position zurückgesetzt werden:

  1. m_oPosition.Y = m_oPosition.Y % m_iTextureHeight;

Während des Render-Vorgangs wird geprüft, ob die Hintergrundgrafik einen leeren Bereich am oberen Bildschirmrand hinterlässt. Verläuft der Test positiv, werden zwei Segmente gerendert:

  1. m_oSpriteBatch.Begin();
  2. if (m_oPosition.Y < m_iTextureHeight)
  3. m_oSpriteBatch.Draw(m_oTexture, m_oPosition, null,
  4. Color.White);
  5. m_oSpriteBatch.Draw(m_oTexture, new Vector2(
  6. m_oPosition.X,
  7. m_oPosition.Y - m_iTextureHeight), null, Color.White);
  8. m_oSpriteBatch.End();

Das Beispielprojekt, welches Sie auf der Heft-CD finden, kapselt die Logik in der ScrollableBackground-Klasse. Als Basisklasse fungiert aber nicht Drawable- GameComponent, sondern eine eigene Klasse mit dem Namen Item. Deren Daseinsberechtigung liegt in der Datenstruktur begründet, die im nächsten Abschnitt vorgestellt wird.

Game States

Jedes Computerspiel besitzt verschiedene Zustände, zwischen denen der Benutzer navigieren kann. Es existiert z.B. ein Hauptmenü, eine Konfigurationsmöglichkeit oder ein Bildschirm, der die Spielregeln anzeigt. Auch das Spielgeschehen nimmt mindestens ein Zustand ein, wobei unter Umständen jeder Level als ein Zustand gelten kann. Der Programmierer des Spiels muss alle Zustände mittels einer Datenstruktur organisieren und dem Spieler die Navigation zwischen den Zuständen erlauben. Das XNA Framework bietet dafür keine direkte Unterstützung, weshalb im Folgenden eine kleine Lösung umgesetzt wird. Gleich vorweg eine Formalität: Der Begriff Screen bezeichnet einen Zustand. Jedes Menü und jede Spiellogik wird in einem solchen Screen gekapselt. Die Datenstruktur muss dafür sorgen, dass Screens verschachtelt werden können. Angenommen, der Spieler wählt den Eintrag Optionen. In den Optionen stehen wiederum die Menüpunkte Grafik, Sound und Tastaturbelegung zur Auswahl. Es soll jederzeit möglich sein, zum vorherigen Screen zurückzuspringen oder eine ebene tiefer in das System „einzutauchen“. Es muss daher ein Objekt geben, das den Überblick über alle Screens hat, damit die korrekte Reihenfolge beim Aktualisieren und Rendern eingehalten wird.

Die Stack-Klasse der .NET-Klassenbibliothek bietet sich als scheinbar ideale Lösung zur Verwaltung der Screens an. Der zuletzt auf den Stack „gepushte“ Screen entspricht der aktuellen Anzeige. Soll rückwärts navigiert werden, wird einfach der oberste Screen vom Stack genommen. Doch sobald eine Ebene (Screen) den darunter liegenden Screen nicht vollständig überlagert oder durchsichtig ist wird es problematisch. Dann müssen mindestens zwei Ebenen von unten nach oben gerendert werden. Die Aktualisierung der Logik erfolgt in entgegen gesetzter Reihenfolge. Dieser Fall tritt zum Beispiel ein, wenn der Spieler sich dazu entschließt, eine Pause einzulegen. Es erscheint ein Menü über der Szene. Das dahinter liegende System delegiert die Eingabeverarbeitung zum neuen Menü und verhindert so, dass das Spielgeschehen weiterläuft. Aufgrund der entgegen gesetzten Iterations-Reihenfolgen beim Aktualisieren und Rendern ist die Stack-Klasse zu unhandlich. Die Lösung ist eine eigene Klasse, die alle Screens in einem generischen List-Objekt platziert und die Stack-ähnliche Logik selbst implementiert. Neben der Logik spielt auch der visuelle Aspekt eine Rolle. Menüs, die verzögerungsfrei aufpoppen sind relativ unspektakulär, weshalb eine Grundfunktionalität gefordert ist, um Überblendungen zwischen Menüs implementieren zu können. ...

Teil 1   Teil 2   Teil 3   Teil 4   Teil 5   

Kommentare