XNAPong Phase 3

Aus Das Sopra Wiki

Zurück zu Phase 2

Phase 3 - Der Rest

  • Punkteanzeige
  • Siegbedingung

Text wird in XNA auch mit Hilfe einer SpriteBatch Instanz gezeichnet. Allerdings benötigt man anstatt einer Texture2D Instanz ein Objekt vom Typ SpriteFont. Um eine SpriteFont zu den Ressourcen des Projektes hinzuzufügen geht man folgendermassen vor: Rechtsklick auf das Content Projekt im Solution Explorer -> Add.. -> New Item.. -> Sprite Font. Ich habe den Namen 'pongFont.spritefont' verwendet. Nach dem hinzufügen öffnet sich sofort die .spritefont Datei im Visual Studio Editor. Der wichtigste Wert in der leicht verständlichen XML Datei ist das Element FontName. Hier kann der Name einer installierten Systemschriftart angegeben werden, die dann von XNAs ContentProcessor in ein nutzbares Format umgewandelt wird. Nach dem die Schriftart dem Content Projekt hinzugefügt wurde lässt sie sich bequem über den ContentManager laden:

  • In der Game Klassendefinition
private Vector2 scorePosition;
private SpriteFont scoreFont;
private string scoreText;
private int[] score;
  • In LoadContent()
score = new int[] { 0, 0};
scoreFont = Content.Load<SpriteFont>("pongFont");
scoreText = "L:0 - R:0";
float textWidth = scoreFont.MeasureString(scoreText).X;
scorePosition = new Vector2(viewportWidth / 2 - textWidth / 2, 10);      // zentriert den text
  • In Draw()
spriteBatch.DrawString(scoreFont, scoreText, scorePosition, Color.White);

Die SpriteFont Objekte bieten die äusserst nützliche Methode MeasureString() an, mit deren Hilfe sich leicht die Ausmasse von Text auf dem Bildschirm bestimmen lässt. Der Punktezähler ist nach dem Kompilieren zwar schon sichtbar, zählt allerdings noch nicht mit.

Das Zählen und Anzeigen der Punkte muss wiederum in Update() passieren, um auf den den Bildschirm verlassenden Ball zu reagieren:

if (ball.X + ball.Width < 0)
{
    score[1]++;
    scoreText = "L:" + score[0] + " - R:" + score[1] + "";
    ballDirection.X *= -1;
    ball.X = GraphicsDevice.Viewport.Width / 2;
}

if (ball.X > GraphicsDevice.Viewport.Width)
{
    score[0]++;
    scoreText = "L:"+score[0]+" - R:"+score[1]+"";
    ballDirection.X *= -1;
    ball.X = GraphicsDevice.Viewport.Width / 2;
}

Falls der Ball den Bildschirm verlässt wird der Punktestand des entsprechenden Spielers erhöht und der zu zeichnende Punktestrink aktualisiert. Der Ball wird ausserdem wieder auf das Spielfeld versetzt und seine Flugrichtung umgekehrt. Schliesslich muss das Spiel noch erkennen wann ein Spieler gewonnen hat. Wir lösen das Problem in dem wir in Update() testen ob ein Spieler die notwendige Punktzahl erreicht hat und nur falls das nicht der Fall ist, geht das Spiel wie gewohnt weiter, ansonsten zeigt es nur noch die Siegernachricht an:

  • Update():
protected override void Update(GameTime gameTime)
{
    if (score[0] == 10)
    {
        scoreText = "Left Player Won";
    }
    else if (score[1] == 10)
    {
        scoreText = "Right Player Won";
    }
    else
    {
        HandlePlayerInput();

        ball.X += (int)ballDirection.X;
        ball.Y += (int)ballDirection.Y;


        if (ball.Intersects(rightPaddle) || ball.Intersects(leftPaddle))
            ballDirection.X *= -1;

        if (ball.Y < 0 || ball.Y > GraphicsDevice.Viewport.Height - ball.Height)
            ballDirection.Y *= -1;

        if (ball.X + ball.Width < 0)
        {
            score[1]++;
            scoreText = "L:" + score[0] + " - R:" + score[1] + "";
            ballDirection.X *= -1;
            ball.X = GraphicsDevice.Viewport.Width / 2;
        }

        if (ball.X > GraphicsDevice.Viewport.Width)
        {
            score[0]++;
            scoreText = "L:" + score[0] + " - R:" + score[1] + "";
            ballDirection.X *= -1;
            ball.X = GraphicsDevice.Viewport.Width / 2;
        }    
    }
    
    base.Update(gameTime);
}

Die letzte und entscheidenste Änderung muss nun noch in der Draw() Methode vorgenommen werden. Die GraphicsDevice.Clear() Zeile sollte anschliessend so aussehen:

GraphicsDevice.Clear(Color.SteelBlue);               // oder auch jede andere farbe AUSSER CornflowerBlue