For those that don't know about Easy Storage here's the description from the codeplex project "EasyStorage is a library for making it quicker and easier for XNA Game Studio developers to manage the StorageDevice without all the details. EasyStorage uses a simple API to enable you to add file saving to your game."
Nick Gravelyn updated it to support XNA 4.0/Windows Phone 7 and since I've used it with both my games for the 360 I figured I'd check it out for my WP7 game. It's pretty simple to set up on the 360, and I wrote a tutorial on how to do that, and SUPER simple to use on WP7.
First off, download the latest build (55373 as of writing this) from here. It comes with windows/360/WP7 stuff and if you plan on supporting any multiple of those platforms then you'll have to look through the included sample to see how they get setup differently. For the purpose of this tutorial we'll just port the WP7 code into out project. From the easystorage-55373 folder navigate to GS4 and copy the EasyStorage folder into your project (and include it). Now that you have it as part of your project we can gut everything except the stuff we need. You can delete everything in the folder EXCEPT for these 3 things:
- EasyStorageSettings.cs
- ISaveDevice.cs
- IsolatedStorageSaveDevice.cs
Now you should have a folder named EasyStorage with the 3 files above inside. I created a class called 'Global' so I have access to saving and loading through my project. Here's the class below that you can use for your project.
using System;
using EasyStorage;
using Microsoft.Xna.Framework;
namespace YOUR_NAMESPACE_HERE
{
public struct SaveGameData
{
public int lives;
public int score;
public bool doIHaveTheKey;
}
public class Global
{
// A generic EasyStorage save device
public static ISaveDevice SaveDevice;
public static string saveFileName = "YOURGAME_Save";
public static string containerName = "YOURGAME_Container";
public static SaveGameData saveData;
public static SaveGameData loadData;
}
}
Anything you'll want to save in your game can go in the in the SaveGameData struct above. I just have a few placeholders so you can see some examples of what you might save.
Now we just need to initialize our isolated storage. Since I'm working with the GameStateManagement (4.0) I added the initialization in my MainMenuScreen.cs. I'll move it into my 'Touch to begin' screen whenever that gets completed. You can add the code below in your LoadContent() method.
EasyStorageSettings.SetSupportedLanguages(Language.English);
Global.SaveDevice = new IsolatedStorageSaveDevice();
Here you can set your supported languages and we also set our isolated storage device to our global counterpart so we can access it if needed although I don't currently have a need to use it. On the 360 I would check to see if it was null (if the user refused storage) before I tried saving or loading data.
Now wherever you're saving your data (mine's in GameplayScreen.cs) you'll need to add the following line. I also had to add a reference to System.Xml.Serialization. To add that reference right click on the references folder in your project and click Add Reference. Then just scroll down (in the .NET tab) until you find System.Xml.Serialization and add it. You'll also have to add the using statement at the top: using System.Xml.Serialization;
public readonly XmlSerializer serializer =
new XmlSerializer(typeof(SaveGameData));
We need to add the saving/loading methods, as well as a method for each so we can read the data. Add these someplace in the same file:
private void SaveData()
{
// serialize out some XML data
try
{
Global.SaveDevice.Save(Global.containerName, Global.saveFileName, SerializeTest);
}
catch
{
}
}
private void SerializeTest(Stream stream)
{
Global.saveData.lives = lives;
Global.saveData.score = score;
Global.saveData.doIHaveTheKey = doIHaveTheKey;
serializer.Serialize(stream, Global.saveData);
}
So basically this serializes our file and if something goes wrong nothing happens. I have it in a try catch because it was needed for 360 development. I don't think you can remove the storage (correct me if I'm wrong) so putting it in a try/catch block might be a little overkill for working on the phone.
So here's our load methods which look much the same as the saving ones, it just reverses everything. Once again I just ported over the same code I used on the 360 so there's plenty of checks to make sure nothing can throw an exception if a storage device doesn't exist. Possible overkill but better safe than sorry right?
private void LoadData()
{
if (Global.SaveDevice != null &&
Global.SaveDevice.FileExists(Global.containerName, Global.saveFileName))
{
try
{
Global.SaveDevice.Load(Global.containerName, Global.saveFileName, DeserializeTest);
}
catch
{
}
this.lives= Global.loadData.lives;
this.score = Global.loadData.score;
this.doIHaveTheKey = Global.loadData.doIHaveTheKey;
}
}
private void DeserializeTest(Stream stream)
{
Global.loadData = (SaveGameData)serializer.Deserialize(stream);
}
And that's everything! When we want to save our game we simply call SaveData() and when I load up my game I call LoadData() in my LoadContent() method.
I haven't tried it but you could probably use this as a way for tombstoning also (If the user takes a call or similar and your game is killed). Just set up an event handler that calls SaveData() when your game is deactivated and call LoadData() when your game is activated again.
Big props to Nick Gravelyn for keeping the Easy Storage library up to date!