Last week, we added scoring, and keeping track of the high score over a set of games. The problem is, when you exit the game for any reason, you lose your high score. That’s because everything is unloaded from memory, so when you start your game over, it has nothing to start from. This week, we’ll save your high score to a file, so we can load it back up when you restart your game. To begin, we’ll load the code from last week over at the SkyDrive Share.

When working with files, we’ll need to add a few libraries. On the Windows Phone, applications have access to a special type of storage called IsolatedStorage, which is a file store that is accessible only by your application. Additionally, we will be storing our high score in an XML format, and accessing it with LINQ. To work with these, we’ll the following three include statements:

Using Statements
  1. using System.IO;
  2. using System.IO.IsolatedStorage;
  3. using System.Xml.Linq;

Once we’ve got these, we’ll just need to set up two simple methods. We simply need to save to the file, and load from the file. We’ll then just need to update the game to call the load method when it starts, and the save method at the end of each game.

SaveToFile
  1. public void SaveToFile()
  2. {
  3.     string fileName = "SavedState.xml";
  4.  
  5.     using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
  6.     {
  7.         using (IsolatedStorageFileStream writeStream = new IsolatedStorageFileStream(fileName, FileMode.Create, store))
  8.         {
  9.             using (StreamWriter writer = new StreamWriter(writeStream))
  10.             {
  11.                 XDocument doc = new XDocument(
  12.                     new XDeclaration("1.0", "utf-8", "yes"),
  13.                     new XElement("State",
  14.                         new XElement("HighScore", highScore.ToString())
  15.                         )
  16.                      );
  17.  
  18.                 writer.Write(doc.ToString());
  19.             }
  20.         }
  21.     }
  22. }

At the beginning of the SaveToFile method, we choose a file name to save the game state. You then open the Isolated Storage and open a file stream into it. We use FileMode.Create because we just want to overwrite a file if it’s there, and make a new one if it isn’t. The StreamWriter lets us write directly into the file we created in Isolated Storage. We then create a basic XML file that contains the high score inside of a State element.

LoadFromFile
  1. public void LoadFromFile()
  2. {
  3.     string fileName = "SavedState.xml";
  4.  
  5.     try
  6.     {
  7.         using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
  8.         {
  9.             using (IsolatedStorageFileStream readStream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
  10.             {
  11.                 using (StreamReader reader = new StreamReader(readStream))
  12.                 {
  13.                     string stateXml = reader.ReadToEnd();
  14.  
  15.                     XDocument doc = XDocument.Parse(stateXml);
  16.  
  17.                     var q = from c in doc.Descendants("State")
  18.                             select (string)c.Element("HighScore");
  19.                     
  20.                     int i = 0;
  21.  
  22.                     foreach (string s in q)
  23.                     {
  24.                         if (int.TryParse(s, out i))
  25.                         {
  26.                             highScore = i;
  27.                         }
  28.                     }
  29.                 }
  30.             }
  31.         }
  32.     }
  33.     catch (IsolatedStorageException)
  34.     {
  35.     }
  36. }

To load from the file, we use the same file name we defined when we saved our state. We then open the Isolated Storage using a StreamReader, and load its contents into a XDocument. This lets us use LINQ to pull in the elements that we saved. We walk through the elements named HighScore, and parse its contents into the highScore variable. The whole thing is wrapped in a try catch block because the file might not be there, or maybe there is something wrong with the file. We don’t want that to crash the game, so we just let it go.

Now we need to use these methods. First of all, we just need to load in the file in the Initalize method.

Initialize
  1. protected override void Initialize()
  2. {
  3.     random = new Random();
  4.  
  5.     highScore = 0;
  6.  
  7.     LoadFromFile();
  8.  
  9.     base.Initialize();
  10. }

And finally, we need to save it. You could put it in every time the high score is beaten, but file I/O is expensive, so this could cause performance problems. Since we are really storing game high scores, why not drop it into the update method when the player dies.

Code Snippet
  1. 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)player.Position.X, (int)player.Position.Y))
  2. {
  3.     triangleColor = Color.Red;
  4.     isPlayerDead = true;
  5.     SaveToFile();
  6. }

And there you go, your high score is saved across application launches. Remember that if you restart the emulator, your isolated storage will be blown away, so you’ll lose your high score. This will also happen in you uninstall the game and then redeploy.

Next week, we’ll be adding sound effects, so stay tuned.

Download the latest version of the source code.