Time to add scoring! To add a competitive edge to the game, let’s add in a running total of how many enemies you’ve shot. We’ll also keep track of the high score across games so you can try to beat your last score. To do this, we’ll make use of a Sprite Font. A Sprite Font is a font specially prepared by taking a set of characters and converting them to textures. So let’s get started. To begin, we’ll want to grab the code from last week over at the SkyDrive share.

The first thing that we’ll want to do is create a new Sprite Font. Right-click on the TriangleShooterContent project, and choose Sprite Font. Under name, type “Font.spritefont”, and then click Add. It will open in the editor, in all it’s XML glory. As you can see by looking at the file, it describes a specific version of a font. You define the Font’s name, size, spacing, whether to use kerning or not, the style, a default character, and the portion of the font to include. The document is well commented, and is easy enough to understand. The one thing that might catch you up is the CharacterRegions. Because games require a lot of efficiency, you want to minimize any overhead possible. This includes characters from a font you wouldn’t use. This is especially important when you want to use non-Latin characters, such as Chinese or Japanese, because they won’t be included in the default Character Region. If you’re going to be using a lot of non-Latin characters, I suggest you take a look at the Localization Sample on AppHub.

We’ll change two things. First, change the FontName field to Kootenay. Second, change the Size field to 32. This will give us a readable font for the phone.

Next, we’ll need to set up our variables. We’ll be counting the number of enemies you shoot, so well use an integer named score, and an integer named highScore to keep track of the record. We’ll also need a variable to hold our font.

Variable Declaration
  1. int score;
  2. int highScore;
  4. SpriteFont font;

We’ll initialize the highScore in the Initialize method

  1. highScore = 0;

And the score in the NewGame method.

  1. score = 0;

Then load up the font in the LoadContent method

  1. font = Content.Load<SpriteFont>("Font");

Now we’re ready to start keeping score. Inside of the Update method, where we do the collision for bullets, we add a few lines to a successful collision. We increment the score, then check if the score is greater than the high score. If that’s the case, we update the high score to equal the current score. All together, the updated bullet collision detection part of the Update method looks like the following

Bullet Collision
  1. foreach (Bullet b in bullets.ToList())
  2. {
  3.     b.Position = new Vector2(b.Position.X + b.Speed * (float)Math.Cos(b.Rotation), b.Position.Y + b.Speed * (float)Math.Sin(b.Rotation));
  5.     if (!graphics.GraphicsDevice.Viewport.Bounds.Contains(new Point((int)b.Position.X, (int)b.Position.Y)))
  6.     {
  7.         bullets.Remove(b);
  8.     }
  9.     else
  10.     {
  11.         foreach (Enemy enemy in enemies.ToList())
  12.         {
  13.             if (new Rectangle((int)enemy.Position.X - enemy.Avatar.Width / 2, (int)enemy.Position.Y - enemy.Avatar.Height / 2, enemy.Avatar.Width, enemy.Avatar.Height).Contains((int)b.Position.X, (int)b.Position.Y))
  14.             {
  15.                 bullets.Remove(b);
  16.                 enemies.Remove(enemy);
  17.                 score++;
  18.                 if (score > highScore)
  19.                 {
  20.                     highScore = score;
  21.                 }
  22.                 break;
  23.             }
  24.         }
  25.     }
  26. }

Finally, we add a couple of lines to the Draw method. We use the spriteBatch.DrawString method. The High score is left aligned, so we just tell it to draw at Vector2.Zero, the top left position. For the Score, we want to right align, which means we have to set the offset based on the width of the string. To do this, we use the font.MeasureString function, and subtract it from the width of the Viewport. The lines look like this:

  1. spriteBatch.DrawString(font, score.ToString(), new Vector2(graphics.GraphicsDevice.Viewport.Width, 0), Color.White, 0f, new Vector2(font.MeasureString(score.ToString()).X, 0), 1f, SpriteEffects.None, 1f);
  3. spriteBatch.DrawString(font, "High: " + highScore.ToString(), Vector2.Zero, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);

With those changes, we now have scoring, and the updated game looks like this:


When you die, the score resets, but the high score remains. If you reset the game, though, you’ll lose your high score. That’s why next week we’ll be looking at persistent storage, and save the high score to a file we can load when the game starts.

Download the latest version of the source code.