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.)
[size="5"][b]Saving the file[/b][/size]
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:
[list=1][*]Create file and verify that it's valid[*]Write signature to file[*]Write important file description to file[*]Write all variables necessary[*]Close file[/list] Ok, now let's analyze each of these.
[size="3"][b]1. Create file and verify that it's valid[/b][/size]
This is probably the easiest thing to do, you will just have to create a file and check if it was created correctly.
// Game stuff here
char FileName = "MyGame.svg";
SaveFile = fopen (FileName, "wb"); // opens file for writing and in binary mode
if (SaveFile == NULL)
// Error while creating file
}[/code][/indent] Now that was easy, let's check the next one.
[size="3"][b]2. Write signature to file[/b][/size]
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.
[indent][code]const char SIGNATURE = "LSD"; // for Load / Save Demo
fwrite (SIGNATURE, sizeof(const char), sizeof(SIGNATURE), SaveFile);[/code][/indent] 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, 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.
[size="3"][b]3. Write important file description[/b][/size]
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.
[indent][code]const int ENEMIES = 20;
const int PLAYERS = 2;
char PlayerName ;
unsigned char Lives;
unsigned char Alive;
sPlayer Players[PLAYERS]; [/code][/indent]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.
[indent][code]fwrite (&PLAYERS, sizeof(int), 1, SaveFile);
fwrite (&ENEMIES, sizeof(int), 1, SaveFile);[/code][/indent] 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 !
[size="3"][b]4. Write all necessary variables[/b][/size]
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.
[indent][code]fwrite (Players, sizeof (sPlayer), PLAYERS, SaveFile);
fwrite (Enemies, sizeof (sEnemy), ENEMIES, SaveFile);[/code][/indent] Again we need to give fwrite the size of the variables and all it is done.
[size="3"][b]5. Close file[/b][/size]
This is the hardest part you need to close the file.
[indent][code]fclose (SaveFile);[/code][/indent] It was hard right?
[size="5"][b]Loading the file[/b][/size]
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.
[list=1][*]Open file and verify if valid file[*]Read header[*]Read all variables necessary[*]Close file[/list] And another type, step-by-step.
[size="3"][b]1. Open file and verify if valid file[/b][/size]
We will open the file and see if it exists.
char FileName = "MyGame.svg";
LoadFile = fopen (FileName, "rb"); // opens file for reading and in binary mode
if (LoadFile == NULL)
// Error while creating file
}[/code][/indent] Just like for saving, but instead of writing mode, we open it in reading mode.
[size="3"][b]2. Read header[/b][/size]
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.
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);[/code][/indent] And that's it, you have yourself the header loaded.
[size="3"] [b]3. Read all variables necessary[/b][/size]
Now this is just like the save part (again).
[indent][code]fread (Players, sizeof (sPlayer), players, SaveFile);
fread (Enemies, sizeof (sEnemy), enemies, SaveFile);[/code][/indent] We use the variables we loaded (lowercase) to know how many were saved.
[size="3"][b]4. Close file[/b][/size]
[indent][code]fclose (LoadFile);[/code][/indent] And that's the end of our Load routine.
[size="5"][b]Further Sugestions and Remarks[/b][/size]
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.
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 add encryption. It's cool and it protects you from players that want to be number one, even if they can't play the game.
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
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.
Allow the user to choose the filename he wants to save to, this is an obvious subject but since in this demo I made it hard coded, you could forget right?
Now for the regards (I hate this part).
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).
[size="3"][b]Make a header[/b][/size]
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)