Save/Load in C# XNA

Started by
6 comments, last by dworm 9 years, 3 months ago

Hello Guys,

I have gone through several articles and posts within this community and other websites to figure a way to program a Save / Load Feature for a game. Most of the ones I've seen are for RPGs which I guess it would work just fine but as the total Newbie I am I prefer to ask someone who actually knows... meaning You.

As a Background, the game we are working on is a 2D Gun -n- Run, sort of like Zombies Ate my Neighbors (If anyone has played it) of course plot and else is totally different but is just so you can imagine the platform. I'd like players to be able to save their stats/weaponry and else.

I must say, this is a 4 player co-op.... I am unsure on where to start... I've read about Threading... I'll be totally honest, I looked into it but couldn't really understand it, and my job has been consuming a lot of time so I haven't gotten around to dedicating it more time this week. If someone could point me in the right direction with "Threading" or Understanding it, I will consider him/her a hero.

Thank you guys.

Advertisement
The relevant keyword here is "serialization", not "threading".

The general idea is that you write a representation of your game state to a file, and subsequently construct a game state from said representation.

For almost all modern programming languages, a library exists (often in base class library) that allows you to serialise a given object to permanent storage (or other stream) and to deserialize it back to a runtime object instance.

Niko Suni

TLDR: C# has a BinaryReader/BinaryWriter.

Give them File.Open( ) when you make them.

When you save use simple data types in a specific order you choose. String, Int, Int, Float, String, etc.

When you load you read them in that same order, String, Int, Int, etc..

You basically save information for yourself, you just need to be able to reconstruct the scene.

This is simple to do but tougher to explain.

Nik02 is correct, serialization is what you're looking for.

Specifically look into binary serialization.

You basically take a simple object like a string or an int and you turn it into 1's and 0's.

Its hard to serialize complex objects but its not an issue once you understand the process.

So to save your game you basically decide what information you need to reconstruct the game as it is.

An example would be a string:LevelName, float:x, float:y, int:WeaponType, int:AmmoCount, int:Health, int:Lives

You don't want to save the entire level, textures, enemies, particles, that would be a huge file and that data is fleeting. (These things are achievable but lets cut corners for now)

So you save a simple string, level name, which is enough information for you to know what textures and enemies you want to load later.

When loading you can create a new player and just pass in simple parameters like x, y, health, weaponType, etc.

ENough to make a player just like the one we had when we saved.

You can even just save numbers, 102315

When you load the file read each number,

for the number 1, if its a 1 then its the first level

for the second number, if its a 0 then all secret skulls have been found

etc. You are basically leaving hints for you to use later, when you load you just need to know what to do with the info.

To do the actual saving you probably want the binary writer and reader in C#

http://msdn.microsoft.com/en-us/library/system.io.binarywriter%28v=vs.110%29.aspx

They will do the serializing, to put the serialization data into a file you need to give them a file to write into!

Use File.Open to turn a fileName into a stream we can give to the binary writer.

http://msdn.microsoft.com/en-us/library/b9skfh7s%28v=vs.110%29.aspx

You can read that page to see what data types are supported for serialization.

To do the loading is more difficult to explain.

You use the binary reader and file.open just like before.

But you need to know what you are reading, it will be all 1's and 0's which could be anything.

Binary is used intentionally sometimes to prevent unauthorized access to data, 1's and 0's are useless unless you know where an object begins and ends.

For instance 11001010 is a byte, a byte can be an int, it can be a char, it could be a bool, and thats only 1 object, imagine our 7 mlti-byte object example * 4 players.

Complete gibberish, unless you know what the data represents.

So basically we need to know what we're looking for, and to do that we need to save ina specific way.

Write name, x, y, health, etc.

Read string, float, float, int, etc.

You must code this specifically.

If you have a variable number of players you can write an int:PlayerCount as the first thing,

then when you are loading you check the very first object and then loop through your load player code that many times.

Another option is CSV (comma separated values) or XML. These are human readable formats but C# doesnt do CSV by default and XML may be overcomplicating it.

Even though I said alot I am still being brief, it requires more eplanation but this should be enough to help you understand this subject.

It is very hard to understand at first but it is quite simple so good luck on the steep learning curve.

I didn't proof read so hopefully you manage to get something out of the post.

Thank you very much RenderBlows, That was in fact really helpful and I have a WAY MUCH BETTER idea of where to start now (Something I didn't have before) Thank you very much!

Some example code (based on what I do) - doing it this way makes it UAC compliant and I find it simple:

    [Serializable]
    public class PlayerData
    {
        public int level;
        public Vector2 player_position;
        public int life;
        public int points;
 //etc...
    }
    [Serializable]
    public class EnemyData
    {
        public Vector2 enemy_pos;
        public Vector2 enemy_vel;
 public int enemy_life;
 //etc...
    } 
// IE:
    public EnemyData[] monsters;
    public PlayerData player;
    //...
    monsters = new EnemyData[MAX_MONSTERS];
    player = new PlayerData();

public bool SaveGame(int saveNumber) {
    string fileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); //CSIDL_LOCAL_APPDATA
    fileName+="\\GameTitle\\SaveGame"+saveNumber.ToString()+".txt";
    bool success = File.Exists(fileName);
    if (success) { }
    else {               
        Directory.CreateDirectory(Path.GetDirectoryName(fileName));                              
    }
    bool success = true;
    FileStream fs = new FileStream(fileName, FileMode.Create);                   
   
    BinaryFormatter formatter = new BinaryFormatter();       
    try
    {
        if (player != null) formatter.Serialize(fs, player);
 if (monsters != null) formatter.Serialize(fs, monsters);
 // etc....
    }       
    catch (SerializationException e)        
    {
        success = false;
        Console.WriteLine("Failed to serialize. Reason: " + e.Message);           
        throw;
    }       
    finally { fs.Close();}
}

public bool LoadGame(string fileName)
{
    bool success = true;
    if (File.Exists(fileName) == false) { Console.WriteLine("File does not exist: " + fileName); return false; }
    FileStream fs = new FileStream(fileName, FileMode.Open);
    try
    {
        BinaryFormatter formatter = new BinaryFormatter();               
        player = (PlayerData)formatter.Deserialize(fs);
        monsters = (EnemyData[])formatter.Deserialize(fs);
    }
    catch (SerializationException e)
    {
        success = false;
        Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
        throw;
    }
    finally { fs.Close(); }   
    return success;
}

Also I found this recently which is probably the preferred way to do it if targeting xbox also:

http://msdn.microsoft.com/en-us/library/bb203924.aspx

and demo zip:

http://go.microsoft.com/fwlink/?LinkId=198913

Saving and loading in xna has a few gotchas if you want to support xbox 360, as it has to support unexpected removal of the device, e.g. A memory card etc.

You might want to look at a library called EZStorage, available on codeplex which handles a lot of this for you as well as asynchronous saving and loading.

Edit: EZStorage might have disappeared from the net. If it has let me know, I can make a copy available.

Thank you very much for the visual Example and the links Renman29!

And all of you who took time to read and reply to this post, I hope the information also help other people inquiring about the same thing.

like you i had a lot of problems serializing in xna for many reason but then i truly studied intermediateserializer and well i cant even explain how much it is PERFECT

dont ever think of doing anything different from it is my suggestion

intermediateserializer solves all of xmlserializer problems very important to games like circular references its super much readable (yeah even xmlserializer is but you have to make it be.. intermediateserializer is just ready to be read as is) it handles super well every kind of collections, null references and usual stuff common in games

This topic is closed to new replies.

Advertisement