Writing your own Load / Save routines
by Bruno Sousa

This is my first article for GameDev.net so go easy on me. If you want to say thanks, correct sometihng, or just flame, just mail me, all feedback is good feedback (no death threats please).

I’m here to (try) to explain how to make a Load/Save routine. I’ll use non-platform-specific C so people can use the code in DOS/Windows/Linux/whatever supports ANSI C. (I was thinking of also doing a C++ version of the code, but most people prefer C for pure write and read functions. If you need the code for C++, mail me and I’ll send you the C++ version.)

Saving the file

I’ll try to explain the best way I can how to do a save routine in 5 easy steps. The main loop goes like this:

  1. Create file and verify that it's valid
  2. Write signature to file
  3. Write important file description to file
  4. Write all variables necessary
  5. Close file

Ok, now let’s analyse each of these.

1. Create file and verify that it's valid

This is probably the easiest thing to do, you will just have to create a file and check if it was created correctly.

#include <stdio.h> // Game stuff here FILE *SaveFile; char FileName[] = "MyGame.svg"; SaveFile = fopen (FileName, "wb"); // opens file for writing and in binary mode if (SaveFile == NULL) { // Error while creating file }

Now that was easy, let's check the next one.

2. Write signature to file

I must be honest with you, this is not necessary to your save game file, but is a help for loading, I’ll explain why later, when I cover the Load routine. So to write a signature file to the game you just have to add a string to your file.

const char SIGNATURE[] = "LSD"; // for Load / Save Demo fwrite (SIGNATURE, sizeof(const char), sizeof(SIGNATURE), SaveFile);

For you C genius out there I think I don’t have to explain the fwrite routine, but I’ll do it for the sake of the beginners out there. So, it is as follows, we supply a pointer to the string as first parameter (SIGNATURE points a pointer to SIGNATURE[0], now is the weird part, we must supply the size of the type of variable we are trying to write to the file, in this case char, and then, how big is the string, in this case 4 bytes (LSD + "\n" for end line). Now we just supply the pointer to the file stream and off we go.

3. Write important file description

Now for the hard part starts, for this part we will imagine we are making a invaders clone, so we will need some variables to old score, life, etc. We will use a struct so it can be easier to write and read from.

const int ENEMIES = 20; const int PLAYERS = 2;
typedef struct { char PlayerName [11]; unsigned char Lives; int xPosition; int yPosition; int Score; int BulletsLeft; int Level; } sPlayer; typedef struct { unsigned char Alive; int xPosition; int yPosition; int Speed; } sEnemy; sEnemy Enemies[ENEMIES]; sPlayer Players[PLAYERS];

In this piece of code we created two arrays, one of sPlayer and another of sEnemy, so we know we have two players and 20 enemies, this is what we will write to the file.

fwrite (&PLAYERS, sizeof(int), 1, SaveFile); fwrite (&ENEMIES, sizeof(int), 1, SaveFile);

You already know how fwrite works so no more explaining to do. Just want to remember when passing single variables to fwrite you need to pass the address of them.

After completing this step, we can say we have written the save file header !

4. Write all necessary variables

Now for the real, real hard part (ok, not so hard but I like to glorify myself), we shall write all the data to the file. We will use fwrite so we can write the entire info of players and enemies in two simple calls.

fwrite (Players, sizeof (sPlayer), PLAYERS, SaveFile); fwrite (Enemies, sizeof (sEnemy), ENEMIES, SaveFile);

Again we need to give fwrite the size of the variables and all it is done.

5. Close file

This is the hardest part you need to close the file.

fclose (SaveFile);

It was hard right?

Loading the file

If you got all the stuff this far, then this will be a singe. Loading a file is like saving it basically, let’s see the steps we need.

  1. Open file and verify if valid file
  2. Read header
  3. Read all variables necessary
  4. Close file

And another type, step-by-step.

1. Open file and verify if valid file

We will open the file and see if it exists.

FILE *LoadFile; char FileName[] = "MyGame.svg"; LoadFile = fopen (FileName, "rb"); // opens file for reading and in binary mode if (LoadFile == NULL) { // Error while creating file }

Just like for saving, but instead of writing mode, we open it in reading mode.

2. Read header

We only have in our header three variables, below is a table explaining the all file. Name Size Description SIGNATURE 4 bytes Signature file PLAYERS OS dependet (int) Number of players ENEMIES OS dependet (int) Number of enemies Players PLAYERS * sizeof (sPlayer) Players information Enemies Enemies * sizeof (sEnemy) Enemies information

Now we load the header info into some variables.

char SIGNATURE[4]; int PLAYERS; int ENEMIES; fread (signature, sizeof (char), 4, LoadFile); // you should check the signature to see if is equal to LSD fread (&players, sizeof(int), 1, SaveFile); fread (&enemies, sizeof(int), 1, SaveFile);

And that’s it, you have yourself the header loaded.

3. Read all variables necessary

Now this is just like the save part (again).

fread (Players, sizeof (sPlayer), players, SaveFile); fread (Enemies, sizeof (sEnemy), enemies, SaveFile);

We use the variables we loaded (lowercase) to know how many were saved.

4. Close file

Again

fclose (LoadFile);

And that’s the end of our Load routine.

Further Sugestions and Remarks

This part is the cooler one in my opinion, I’ll give you suggestions I think it should be cool to implement in the Load / Save Demo.

Encryption

If you don’t want that the more experienced user to pick up your saved file and edit it so he has a 100000000000 * 10 ^ 99 score then you should had encryption. It’s cool and it protects you from players that want to be number one, even if they can’t play the game.

Compression

In this article we used very small structs and variables, but imagine you have 100 floating values, about 1000 structs for objects and more information you want to save, this would create a very big, big file (I still remember Championship Manager 2 where I needed 16 Megabytes of free space just to save). To compensate this, one idea is to compress the saved file

Multiple files

This is just to simplify loading and reading routines. It’s a good idea to store all player variables in one file, world variables in another, objects in another and so on.

Filenames

Allow the user to choose the filename he wants to save to, this is an obvious subject but sicne in this demo I made it hard coded, you could forget right ?

Now for the regards (I hate this part).

Restoring things

Remember, after loading the file, to load all images needed, maps, and stuff, because you will probably need to load all that stuff again (it should very bad if you loaded a game in level 6 and the artwork would still be from level 1).

Make a header

Always make a header for your files, so you can load the header first, and then see what you will load (you don’t want to pass by the end of file do you ?).

Enough is enough, conclusion !

Ok, it is time to say goodbye, but… "I’ll be back". Just play a little with the source code, experiment, and if you discover something cool, send it to me.

Oh, not to forget, if you have ideas of articles you would like me to write, send your suggestions. Heck, send me even if you don’t have suggestions, even if it is only to say you learned something or not, I WANT feedback !

Bruno Sousa (Akura)
Akura@Logicmatters.cjb.net
http://logicmatters.cjb.net

Discuss this article in the forums


Date this article was posted to GameDev.net: 1/15/2001
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
General

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!