Difference between revisions of "Creating a game save"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(RPG / Platform Game)
(Tower / Racing Game)
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
After trying to save the game in mid play, i have essentially discovered it is difficult if not impossible to save the game mid play.
+
After trying to save the game in mid play, i have essentially discovered it is difficult if not impossible to save the game mid play. This is because many of the monogame classes can't be serialized (for example textures, vectors, Game, etc).
  
 
==Tower / Racing Game==
 
==Tower / Racing Game==
For a Tower Defence game, or racing game you will only need to record the data about the game such as score, lives, credits, level etc.  
+
For a Tower Defence game, or racing game you will only need to record the data about the game such as score, lives, credits, level etc.
  
You could create a struct for a GameSave:
+
This method will use serialization so we need to add the following into the using section at the top of your Game1.cs:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
 +
using System.IO;
 +
using System.Xml.Serialization;
 +
</syntaxhighlight>
 +
 +
You could create a struct for a GameSave, the serializable bit will allow us to serialize this struct:
 +
 +
<syntaxhighlight lang=c#>
 +
[Serializable]
 
public struct GameSave
 
public struct GameSave
 
{
 
{
Line 20: Line 28:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
public GameSave gameData;
+
public GameSave data;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
This method will use serialization so we need to add the following into the using section at the top of your Game1.cs:
+
The method below will actually do the saving. You need to set the values of your data structure, and then create a stream which will be used to link to the file. The binarywrite is able to write the data structure to the file, the Serialize line is the bit which writes the file. The example below accepts a vector for the current position, sets the save name to test and stores the X & Y from the vector.
 +
 
 +
<syntaxhighlight lang=c#>
 +
        public void SaveGame(Vector2 pos)
 +
        {
 +
            data.name = "test";
 +
           
 +
            data.x = (int)pos.X;
 +
            data.y = (int)pos.Y;
 +
            Stream streamwrite = File.Create("mygame.bin");
 +
            BinaryFormatter binarywrite = new BinaryFormatter();
 +
            binarywrite.Serialize(streamwrite, data);
 +
            streamwrite.Close();
 +
        }
 +
</syntaxhighlight>
 +
 
 +
Now to deserialize you need a load method. The third line of the method casts the serialized data back to an instance of Data. This method returns a Vector2 to move the player back to the saved position:
 +
 
 +
<syntaxhighlight lang=c#>
 +
        public Vector2 LoadGame()
 +
        {
 +
            Stream streamread = File.OpenRead("mygame.bin");
 +
            BinaryFormatter binaryread = new BinaryFormatter();
 +
            data = (GameSave)binaryread.Deserialize(streamread);
 +
            streamread.Close();
 +
            return new Vector2(data.x, data.y);
 +
        }
 +
</syntaxhighlight>
 +
 
 +
In your update method, i have added the following to test the loading and saving:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
using System.IO;
+
            if (keyState.IsKeyDown(Keys.B))
using System.Xml.Serialization;
+
            {
 +
                SaveGame(new Vector2(map.ObjectGroups["Objects"].Objects["Player"].X, map.ObjectGroups["Objects"].Objects["Player"].Y));
 +
            }
 +
 
 +
            if (keyState.IsKeyDown(Keys.N))
 +
            {
 +
                Vector2 testpos = LoadGame();
 +
                map.ObjectGroups["Objects"].Objects["Player"].X = (int)testpos.X;
 +
                map.ObjectGroups["Objects"].Objects["Player"].Y = (int)testpos.Y;
 +
            }
 
</syntaxhighlight>
 
</syntaxhighlight>
  
==RPG / Platform Game==
 
For an RPG or Platformer we can focus on saving the player position in the game, and recording the game events in order to reprocess to a similar state. This will require you to  think carefully about what your game will need to be able to save its current position. For example a list of the items collected, a list of the enemies killed, a list of completed challenges, and also the standard information such as player position, score etc.
 
  
This example is the constructor of the GameSave class i created.
+
===Save Game Slots===
 +
You could create an array of GameSave, to allow you to have a number of available GameSave slots:
 +
 
 +
<syntaxhighlight lang=c#>
 +
public GameSave[] gameData = new GameSave(4);
 +
</syntaxhighlight>
 +
 
 +
you can then specify a slot to use:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
         public GameSave(Vector2 pos)
+
         public void SaveGame(Vector2 pos, int slot)
 
         {
 
         {
             data.name = "test";
+
             data[slot].name = "test";
 
              
 
              
             data.x = (int)pos.X;
+
             data[slot[.x = (int)pos.X;
             data.y = (int)pos.Y;
+
             data[slot].y = (int)pos.Y;
 
             Stream streamwrite = File.Create("mygame.bin");
 
             Stream streamwrite = File.Create("mygame.bin");
 
             BinaryFormatter binarywrite = new BinaryFormatter();
 
             BinaryFormatter binarywrite = new BinaryFormatter();
Line 48: Line 99:
 
         }
 
         }
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
You can then specify a slot for LoadGame:
 +
 +
<syntaxhighlight lang=c#>
 +
        public Vector2 LoadGame(int slot)
 +
        {
 +
            Stream streamread = File.OpenRead("mygame.bin");
 +
            BinaryFormatter binaryread = new BinaryFormatter();
 +
            Data data = (Data)binaryread.Deserialize(streamread);
 +
            streamread.Close();
 +
            return new Vector2(data[slot].x, data[slot].y);
 +
        }
 +
</syntaxhighlight>
 +
 +
==RPG / Platform Game==
 +
For an RPG or Platformer we can focus on saving the player position in the game, and recording the game events in order to reprocess to a similar state. This will require you to  think carefully about what your game will need to be able to save its current position. For example a list of the items collected, a list of the enemies killed, a list of completed challenges, and also the standard information such as player position, score etc.

Latest revision as of 07:32, 4 May 2018

After trying to save the game in mid play, i have essentially discovered it is difficult if not impossible to save the game mid play. This is because many of the monogame classes can't be serialized (for example textures, vectors, Game, etc).

Tower / Racing Game

For a Tower Defence game, or racing game you will only need to record the data about the game such as score, lives, credits, level etc.

This method will use serialization so we need to add the following into the using section at the top of your Game1.cs:

using System.IO;
using System.Xml.Serialization;

You could create a struct for a GameSave, the serializable bit will allow us to serialize this struct:

[Serializable]
public struct GameSave
{
    public string SaveName;
    public int Score;
    public int Lives;
    public int Credits;
    public int Level;
}

We can create a variable based on this struct:

public GameSave data;

The method below will actually do the saving. You need to set the values of your data structure, and then create a stream which will be used to link to the file. The binarywrite is able to write the data structure to the file, the Serialize line is the bit which writes the file. The example below accepts a vector for the current position, sets the save name to test and stores the X & Y from the vector.

        public void SaveGame(Vector2 pos)
        {
            data.name = "test";
            
            data.x = (int)pos.X;
            data.y = (int)pos.Y;
            Stream streamwrite = File.Create("mygame.bin");
            BinaryFormatter binarywrite = new BinaryFormatter();
            binarywrite.Serialize(streamwrite, data);
            streamwrite.Close();
        }

Now to deserialize you need a load method. The third line of the method casts the serialized data back to an instance of Data. This method returns a Vector2 to move the player back to the saved position:

        public Vector2 LoadGame()
        {
            Stream streamread = File.OpenRead("mygame.bin");
            BinaryFormatter binaryread = new BinaryFormatter();
            data = (GameSave)binaryread.Deserialize(streamread);
            streamread.Close();
            return new Vector2(data.x, data.y);
        }

In your update method, i have added the following to test the loading and saving:

            if (keyState.IsKeyDown(Keys.B))
            {
                SaveGame(new Vector2(map.ObjectGroups["Objects"].Objects["Player"].X, map.ObjectGroups["Objects"].Objects["Player"].Y));
            }

            if (keyState.IsKeyDown(Keys.N))
            {
                Vector2 testpos = LoadGame();
                map.ObjectGroups["Objects"].Objects["Player"].X = (int)testpos.X;
                map.ObjectGroups["Objects"].Objects["Player"].Y = (int)testpos.Y;
            }


Save Game Slots

You could create an array of GameSave, to allow you to have a number of available GameSave slots:

public GameSave[] gameData = new GameSave(4);

you can then specify a slot to use:

        public void SaveGame(Vector2 pos, int slot)
        {
            data[slot].name = "test";
            
            data[slot[.x = (int)pos.X;
            data[slot].y = (int)pos.Y;
            Stream streamwrite = File.Create("mygame.bin");
            BinaryFormatter binarywrite = new BinaryFormatter();
            binarywrite.Serialize(streamwrite, data);
            streamwrite.Close();
        }

You can then specify a slot for LoadGame:

        public Vector2 LoadGame(int slot)
        {
            Stream streamread = File.OpenRead("mygame.bin");
            BinaryFormatter binaryread = new BinaryFormatter();
            Data data = (Data)binaryread.Deserialize(streamread);
            streamread.Close();
            return new Vector2(data[slot].x, data[slot].y);
        }

RPG / Platform Game

For an RPG or Platformer we can focus on saving the player position in the game, and recording the game events in order to reprocess to a similar state. This will require you to think carefully about what your game will need to be able to save its current position. For example a list of the items collected, a list of the enemies killed, a list of completed challenges, and also the standard information such as player position, score etc.