XNAPong Phase 0-1

Aus Das Sopra Wiki


Pong in XNA

Pong ist ein einfaches, weitbekanntes Spiel und eignet sich deshalb hervorragend um grundlegende Konzepte an einem kleinen Beispiel zu verdeutlichen.

Wer niemals von Computerspielen gehört hat, der findet hier Erleuchtung.

Phase 0 - Vorbereitungen

  • Spielidee haben, durchdenken, verwerfen, neu überlegen, verbessern und für gut befinden
  • Notwendige Spielelobjekte identifizieren
  • Spielmechaniken identifizieren
Die Spielelobjekte
  • 1 Ball
  • 2 Paddel
  • 1 Punkteanzeige
Mechanik
  • Der Ball prallt an Paddeln ab
  • Der Ball prallt am oberen und unteren Bildschirmrand ab
  • Der Ball fliegt am linken und rechten Bildschirmrand in's aus
  • Der Ball soll nach der Faustregel "Einfallswinkel gleich Ausfallswinkel" abprallen
  • Fliegt der Ball auf einer Seite in's aus zählt dies als Punkt für den gegenüberliegenden Spieler

Phase 1 - Die ersten Schritte

  • Ein neues Projekt im Visual Studio anlegen (XNA Game Studio 4.0 Game Project)
  • Dort die Game1.cs Datei lokalisieren und öffnen

Das erste Ziel ist das Zeichnen der beiden Paddel. Dafür benötigen wir Texturen und die Position auf dem Bildschirm an der gezeichnet werden soll. In XNA gibt es für beide Konzepte eine passende Klasse: Texture2D und Rectangle. Wir werden im folgenden also Instanzen dieser Klassen benötigen.

  • In der Game Klasse legen wir daher folgende Felder an:
Texture2D paddleTexture;
Rectangle leftPaddle;
Rectangle rightPaddle;

Als Texturen kann der ContentManager verschiedenste Formate laden. Wir werden in diesem Fall .PNG Dateien verwenden. Die Bilddatei kann einfach mittels Drag'n'Drop in das Content Projekt im Solution Explorer von Visual Studio gezogen werden. In diesem Beispiel verwende ich eine Datei namens pongPaddle.png. Nach dem Einfügen kann mittels des ContentManagers auf diese Ressource zugegriffen werden:

  • In LoadContent()
paddleTexture = Content.Load<Texture2D>("pongPaddle");

Aktuell ist allerdings noch nirgends definiert wo das Paddel denn gezeichnet werden soll. Hier kommen die Rectangle Objekte in's Spiel:

  • Ebenfalls in LoadContent(), nach dem Laden der Paddeltextur
leftPaddle = new Rectangle(10, 10, 50, 100);
rightPaddle = new Rectangle(200, 10, 50, 100);

Und um schliesslich auch etwas auf dem Bildschirm zu sehen brauchen wir noch folgende Zeilen:

  • In Draw(), nach dem GraphicsDevice.Clear() Aufruf
spriteBatch.Begin();
spriteBatch.Draw(paddleTexture, leftPaddle, Color.White);
spriteBatch.Draw(paddleTexture, rightPaddle, Color.White);
spriteBatch.End();

Beim Druck auf 'F5' startet das Spiel nun bereits und zeigt unsere beiden Paddel an. Allerdings gibt es noch einige Schönheitsfehler zu beheben:

  1. Die Textur ist verzerrt worden, da sie eine anderes Seitenverhältnis aufweist als das Rechteck in das wir gezeichnet haben
  2. Das rechte Paddel ist nicht gleich weit vom rechten Rand entfernt wie das linke Paddel vom linken Rand

Übliche Lösungen für das erste Problem sind

  • Die Textur so gestalten, dass sie in eine oder zwei Richtungen Dehnbar ist
  • Die Rechtecke mit den Seitenverhältnissen der Texturen zeichnen
  • spriteBatch.Draw() mit dem overload für sourceRectangle aufrufen und dort einen Teilbereich des Quellbildes angeben

Die Datei 'pongPaddle.png' hat eine Auflösung von 64x512 und soll ihr Seitenverhältnis beibehalten. Daher ändern wir die Initialisierung der beiden Paddel in LoadContent() auf:

leftPaddle = new Rectangle(10, 10, paddleTexture.Width / 3, paddleTexture.Height / 3);
rightPaddle = new Rectangle(200, 10, paddleTexture.Width / 3, paddleTexture.Height / 3);

Wir lesen also die Höhe und Breite aus der Textur aus und verwenden sie direkt als Höhe und Breite für das Zeichnen. Da mir die Paddel trotzdem noch zu gross waren habe ich ihre Höhe und Breite einfach jeweils durch 3 geteilt um eine angenehme Grösse zu erhalten. Um nun das rechte Paddel richtig positionieren zu können müssen wir über den Bildschirmbereich, den unser Spiel einnimmt, Bescheid wissen. Das ermöglicht uns das von der XNA Game Klasse zur Verfügung gestellte GraphicsDevice. Mit:

int viewportWidth = GraphicsDevice.Viewport.Width;
int viewportHeigth = GraphicsDevice.Viewport.Height;

kann innerhalb der Game Klasse der aktuell gültige Viewport ermittelt werden. Um nun das rechte Paddel korrekt zu platzieren genügt etwas Mathematik und unsere Paddel Initialisierung sieht nun so aus:

int paddlePadding = 10;            // der Abstand eines Paddels zum jeweiligen Seitenrand
leftPaddle = new Rectangle
   (
       0 + paddlePadding,          // X
       0 + paddlePadding,          // Y
       paddleTexture.Width / 3,    // Breite (ein Drittel der Texturbreite)
       paddleTexture.Height / 3    // Höhe
   );
rightPaddle = new Rectangle
   (
       viewportWidth - paddlePadding - (paddleTexture.Width / 3),   // rechter Rand - Abstand - Breite
       0 + paddlePadding,
       paddleTexture.Width / 3,
       paddleTexture.Height / 3
   );

Die X,Y Koordinaten beim Zeichnen von 2D Texturen innerhalb von XNA gehen im Normalfall von einem Ursprung Oben Links auf der Textur aus. Das bedeutet, das eine Textur an Position 0,0 genau in der linken oberen Ecke erscheint und vollständig zu sehen ist, während eine Textur die an Position viewportWidth,viewportHeigth gezeichnet wird nicht zu sehen ist.

Der neuerliche Druck auf 'F5' zeigt, dass die beiden Paddel nun mit dem richtigen Seitenverhältnis an der richtigen Position gezeichnet werden.

Weiter mit Phase 2