Wir setzen unsere Reise durch die faszinierende Welt der Spieleprogrammierung fort: Texturen, wie in den vorigen Teilen der Serie im Detail vorgestellt, können nämlich viel mehr, als man ihnen auf den ersten Blick zutraut. Wir verwenden die kleinen Bitmaps zum Realisieren von laufenden Hintergründen und Feuer- bzw. Rauchanimationen. Wenn die Grafiken gut erstellt sind und die dahinterstehende Logik sauber ausprogrammiert ist, müssen sich auf Sprites basierende Effekte nicht hinter den Ergebnissen von 3-D-Engines verstecken.
Zunächst einmal: Es gibt neue Informationen zur Nachfolgerin der Xbox 360. Die als Durango bezeichnete Maschine könnte schon auf der am 11. Juni stattfindenden Spielemesse E3 vorgestellt werden. Dafür spricht, dass der als Major Nelson bekannte Larry Hryb seine Webseite um den in der Abbildung 1 gezeigten Count-down erweitert hat. Da diese Person der Director of Programming für die Xbox-Live-Abteilung ist, hat das durchaus Signifikanz.
Auch der im Allgemeinen gut informierte amerikanische Newsdienst Bloomberg stößt in ein ähnliches Horn. Laut den dort veröffentlichten Daten sollte die Xbox dieses Jahr zu Thanksgiving verfügbar sein – in den USA ist das eine sehr wichtige Einkaufssaison, die über den Erfolg oder Misserfolg von Produkten entscheidet. Zur Hardware gibt es einige neue Informationen: Erstens dürfte die neue Xbox auch ein Blu-Ray-Laufwerk enthalten – nach dem Tod des von Microsoft propagierten Formats HD-DVD ist das nicht wirklich überraschend. Auch soll die neue Konsole eine Augmented-Reality-Brille dabei haben. Aus der Halbleiterindustrie hört man außerdem, dass der als „Oban“ bezeichnete Chip so gut wie fertig sei. Leider scheint sich Microsoft noch nicht sicher zu sein, wie es mit den Indie Games weitergeht. Einerseits wurde das Forum im Rahmen der MSDN-Umstrukturierung weitergeführt, andererseits testet der Hersteller die DirectX-Fähigkeiten seiner Entwickler mit dem Windows Phone 8.
Aus diesem Grund ist es sinnvoll, sich neben praktischem Code auch mit Hintergrundwissen zu befassen. Eines der häufigsten Probleme von Anfängern ist das Erstellen von ansprechenden Bildschirmhintergründen – es ist unzeitgemäß, wenn das Raumschiff des Spielers vor einem schwarzen Bildschirm herumtuckert. Die beste Lösung für dieses Problem ist das Verwenden eines gekachelten Hintergrunds. Dabei handelt es sich um eine normale Textur, deren Kanten aber aufeinander abgestimmt sind. Ein Beispiel dafür ist in Abbildung 2 gezeigt.
Bei genauer Betrachtung der Ränder des Quadrats fällt auf, dass das nahtlose Aneinanderreihen der Textur einen glatten Übergang ergibt. Mit etwas Übung ist es sogar möglich, Gradienten überlappend anzulegen. Dabei leistet das quelloffene Bildbearbeitungsprogramm GIMP dank der Winkelbeschränkungsfunktion gute Dienste – wenn die Winkel ident und die Start- bzw. Endpunkte des Gradienten genau am Bildrand liegen, so ist der Übergang glatt.
Im nächsten Schritt beschäftigen wir uns mit dem eigentlichen Zeichnen der Textur. Dazu genügt es uns, zwei Laufindizes festzulegen. Sie geben an, an welcher Stelle der Kachel der obere linke Punkt des Bildschirms liegt. Die Koordinaten der restlichen Würfel ergeben sich dann aus der Logik:
public class Game1 : Microsoft.Xna.Framework.Game
{
float myXOffset;
float myYOffset;
In der periodisch aufgerufenen Funktion Update() aktualisieren wir diese Koordinaten. Die Werte sind absichtlich als Floats definiert, da die Konsole Update() sechzig Mal pro Sekunde aufruft – wir möchten in diesem Beispiel aber einen eher langsamen Übergang. Zusätzlich vereinfachen wir die Arbeit unserer Zeichenroutine, indem wir die Werte nach dem Inkrementieren „normalisieren“ (Listing 1).
Listing 1
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
myXOffset += 0.5F;
if (myXOffset > myTile.Bounds.Width) myXOffset=0;
myYOffset += 0.9F;
if (myYOffset > myTile.Bounds.Width) myYOffset = 0;
base.Update(gameTime);
}
Nun fehlt uns nur mehr das eigentliche Zeichnen des Hintergrunds. Es erfolgt in der Methode Draw mit folgendem Code (Listing 2).
Listing 2
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
for (int x = 0 - (int)myXOffset; x < GraphicsDevice.Viewport.Width; x += 200)
{
for (int y = 0 - (int)myYOffset; y < GraphicsDevice.Viewport.Height; y += 200)
{
spriteBatch.Draw(myTile, new Rectangle(x, y, 200, 200), Color.White);
}
}
spriteBatch.End();
base.Draw(gameTime);
}
Diese auf den ersten Blick extrem kompliziert erscheinende Routine entpuppt sich bei näherer Betrachtung als absolut simpel. Im Allgemeinen ist es sinnvoll, derartige Algorithmen anhand der Anfangsbedingung zu analysieren und „von dort aus“ auf spätere Zustände zu schließen.
Der erste „Würfel“ soll auf der oberen linken Bildschirmecke erscheinen. Da die Draw()-Funktion von XNA als Parameter ein Rechteck mit Destinationsinformationen verlangt, setzen wir ...