Saving and loading your game, the Windows 8 way

While nervously awaiting the verdict on Cardiac Arrest and my application, I went about fixing some things that I was unable to fix beforehand.

First and foremost, the main thing that broke when converting my XNA game to a Windows 8 app using MonoGame was my save game method. After some rooting around and playing with variables (and using Google of course) I realised that it is the method of storage that comes with Windows 8/Metro/RT that changed how I would have to store my data to keep it consistent between games.

I looked for solutions on the internet before the deadline, but the tutorials I found were very inconsistent and unclear, meaning I had to hide my top score information in game before hand. After the deadline however, I found a tutorial which, after some variable changing and customising, I was able to put into my game and see it working, and I thought this would be a perfect thing to try a write a tutorial for.

So here we go, saving you game. Here I will cover how to save your game, load it back in, save whatever you want, and load it where ever you need.

Saving whatever you want

First thing, these are all methods in Main. I, like many of you, prefer using classes, but things seem to go wrong when it is in a class, so main its is. And having said that, these lines should go at the start of main:

using Windows.Storage;
using Windows.ApplicationModel.Core;
using Windows.UI.Xaml;
using Windows.Storage.Streams;
using System.Runtime.Serialization;
using System.Threading.Tasks;

These allow you to call on many of the objects used in the code, such as serializing the data and using streams. Now, lets start with what you want to save, which so far can be pretty much anything. This bit is pretty straight forward, make a new class in your main with the information you want to save, as follows:

public class DataToSave
{
public int topScore { get; set; }

}

Add extra variables for each thing you want to save, dependant on how complicated your game is of course. This class is essentially your save game file.

Saving your game

Time to add the method to save the game. This will be called whenever you want the game to save, through another asynchronous method. Asynchronous methods are Windows 8’s way of keeping everything running smoothly. The tasks in a program labelled asynchronous can have the await prefix given to them meaning that windows has to wait on a response from those tasks before continuing. I can see how this would be used for other program critical tasks when using multi-threading for large apps, but for now this is a nice introduction in the form of loading and saving. This is the code that will save your game:

async Task SaveAsync(DataToSave whatYouAreSaving)
{
StorageFile userdetailsfile = await ApplicationData.Current.LocalFolder.CreateFileAsync(“UserDetails”, CreationCollisionOption.ReplaceExisting);
IRandomAccessStream raStream = await userdetailsfile.OpenAsync(FileAccessMode.ReadWrite);
using (IOutputStream outStream = raStream.GetOutputStreamAt(0))
{
// Serialize the Session State.
DataContractSerializer serializer = new DataContractSerializer(typeof(DataToSave));
serializer.WriteObject(outStream.AsStreamForWrite(), whatYouAreSaving);
await outStream.FlushAsync();
}
}

This code checks for a file (here known as “UserDetails”) and if it it exists destroys the old copy in favour of the new. It sets up a stream to put the save data into the file, then, using the outStream, serializes the data (so it cannot be directly edited), writes the class (here “whatAreYouSaving”) to the file then flushes the async finishing the save. That is the code that directly saves the game, but it has to be called indirectly. This is where the following method comes in:

private async void saveGame()
{
DataToSave Stats = new gameData();
Stats.topScore = currentPlayerScore;
await SaveAsync(Stats);
}

This is the method that will call your save game, or SaveAsync, method. In here I have put my saving logic, as in what I will be saving from the game, and storing it in an instance of the class that I will be saving, namely DataToSave.

Finally as far as saving goes, how to call save game in the game. Rather simply, just put:

saveGame();

Put this wherever you want to save the game and it will save. You can mess around with this (pass a DataToSave here, change the logic etc), but for my game this was the easiest way of doing so. Now on to loading the save game back in.

Loading your saved game

So once you have saved your data, you’ll probably want to load it back in at a later time, so I might as well show you how to do that. Unsurprisingly, it is essentially the same as saving the game, but in reverse. This is the code for loading the game back in:

async Task RestoreAsync()
{
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(“UserDetails”);
IRandomAccessStream inStream = await file.OpenReadAsync();
// Deserialize the Session State.
DataContractSerializer serializer = new DataContractSerializer(typeof(DataToSave));
var StatsDetails = (DataToSave)serializer.ReadObject(inStream.AsStreamForRead());
inStream.Dispose();
topScore = StatsDetails.topScore;
}
catch
{
return;
}

}

Unlike saving the game, this method finds the file, opens it up, deserializes the information as a DataToSave object, creates a new object to temporarily hold the information, closes the stream then allows you to copy the data back into the relevant (global or otherwise) variables. Again use of your own logic can be tried and tested here, though my game works like this so I didn’t want to break anything. The try – catch is in place in case it doesn’t find a file. If there is no file, the game has nothing to load, so continues regardless.

Again, you cannot call this directly, because of how asynchronous methods work, so you need the following method:

protected async void loadGame()
{
await RestoreAsync();
}

Which will runs the RestoreAsync method and load in the data from the file. This method can be called in at any point in your game using the following line:

loadGame();

Seems pretty straight forward doesn’t it. Now at present my game is only using this for saving the topScore, but using dictionaries or lists or a selection of other types will allow for storing high score tables, game progression, unlocked items, anything you want.

If you have any problems with the above code please don’t hesitate to comment below or message myself, and I will try to fix the code and update the above. For peace of mind, here is all of the code in one, so you can double-check:

using Windows.Storage;
using Windows.ApplicationModel.Core;
using Windows.UI.Xaml;
using Windows.Storage.Streams;
using System.Runtime.Serialization;
using System.Threading.Tasks;

public class gameData
{
public int topScore { get; set; }

}

async Task SaveAsync(gameData Stats)
{
StorageFile userdetailsfile = await ApplicationData.Current.LocalFolder.CreateFileAsync(“UserDetails”, CreationCollisionOption.ReplaceExisting);
IRandomAccessStream raStream = await userdetailsfile.OpenAsync(FileAccessMode.ReadWrite);
using (IOutputStream outStream = raStream.GetOutputStreamAt(0))
{
// Serialize the Session State.
DataContractSerializer serializer = new DataContractSerializer(typeof(gameData));
serializer.WriteObject(outStream.AsStreamForWrite(), Stats);
await outStream.FlushAsync();
}
}

async Task RestoreAsync()
{
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(“UserDetails”);
IRandomAccessStream inStream = await file.OpenReadAsync();
// Deserialize the Session State.
DataContractSerializer serializer = new DataContractSerializer(typeof(gameData));
var StatsDetails = (gameData)serializer.ReadObject(inStream.AsStreamForRead());
inStream.Dispose();
topScore = StatsDetails.topScore;
}
catch
{
return;
}

}

protected async void loadGame()
{
await RestoreAsync();
}

private async void saveGame()
{
gameData Stats = new gameData();
Stats.topScore = _score;
await SaveAsync(Stats);
}

saveGame();

loadGame();

I hope this fixes some problems for you.

Adam

References:

http://www.c-sharpcorner.com/UploadFile/99bb20/save-user-data-to-local-application-storage-in-windows-8-app/

http://monogame.codeplex.com

Advertisement

5 thoughts on “Saving and loading your game, the Windows 8 way

Add yours

  1. Great job Adam, i tried many other tutorials before, but they haven’t worked for me… Big Thanks!
    But one thing gets me an exception:
    The first time i call “saveGame();” it works without any problems, doesn’t matter an existing file is overwriten or a new file is created. But the second call of “saveGame();” throws this exception:
    “A first chance exception of type ‘System.UnauthorizedAccessException’ occurred in mscorlib.dll”
    When I start the App again, the first call works again fine and the second will not.
    Maybe you know what I made wrong…
    I use Visual Studio 2013 and Monogame for a Windows Store App.
    Sorry for my bad english 🙂

    1. Hi Carlos,
      Not sure on that one, I did get this issue when I didn’t have the saving and loading code in my Game1.cs file (or in the same file as the main game code). If it isn’t that I’m not sure. Let me know if that’s not the issue

      1. Hi Adam,
        I made a little change in the “SaveAsync” method, now it works fine.
        I added “raStream.Dispose();” after the using block. Seems like the stream remained opened and blocked further file operations.
        Thanks again for this tutorial !

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Website Powered by WordPress.com.

Up ↑

%d bloggers like this: