TUTORIAL: Designing a Save/Load System

Hey all,

PeterB on gameblender.org asked how one could make a save game feature for a Blender game using external save files, so I thought I’d write out a quick tutorial on the subject.

You can find it on my website (blendenzo.com) in the Tutorials section or just follow this link: Designing a Save and Load System

3DPoiko on gameblender asked for some example files showing usage of the principles in the tutorial, so I’ll probably write some in short order.

Hope this is helpful. Let me know what you think. Post questions here, or contact me through my website.

Nice Blendenzo. Glad you included pickle because it’s surprising how many people don’t know about it and it can be very useful and easy to use. I’m currently working on an adventure game and saves are going to be something I have to think about. I think I’ll probably save last scene, GameLogic variables, and inventory items. I plan to keep the GameLogic variables and inventory items in a list so it will be easy to save and load them.

The funny thing is, I just found out about pickle last night doing some research reading while writing the tut. It does sound great, and I’m really excited about it because this means I can try to write my “pyMod” script to play mod file music again. (Last time I attempted, I was having the worst time with the hexadecimal values. read() was giving me strings, and hex() wasn’t working to convert them to hexidecimal. Hopefully pickle will do the trick.)

Now you mentioned saving certain things in the game, how would you say, save the entire game at once as in everything and then load everything where you left off when pressing a key at the menu or something.

Like you have a platform game with a character, enemies, score, platforms, and physics objects.

You would just use a list to keep track of all objects, and their location values at the time of a save.

Actually didn’t herman already write a pdf tutorial on how to load objects with python?

blendenzo>

Great work, as usual.

Thanks blendenzo, this tutorial will save me alot of time designing the saving system for my current project.

Glad to be of help, and thanks for the compliments.

Icoxo: I don’t believe a “save state” or “snapshot” method like that exists for Blender. As I was about to write why it couldn’t be done, I had a ludicrous idea. Why not just use “currentState = GameLogic.getCurrentScene()” (of course, that wouldn’t save your global variables…) then output the whole shooting match to a file? (If it’s possible, that is… You’d definitely want to use pickle for this one.) Now if you only could figure out how to load the saved scene back in… Unpickle it, of course, but then what? Maybe use a Scene actuator and a Python script to run the unpickled scene? I don’t know… it’s all a bunch of theory, and I seriously doubt it would work. You could try it out if you wanted to.

Edit: Hmm… didn’t work. Pickler doesn’t understand Blender objects.

Ahh, found it:

http://blenderartists.org/forum/showthread.php?t=77024

Just thought it would be a good thing to cite this here.

Thank you Blendenzo, thats very helpfull :slight_smile:

Thanks! This will prove to be very useful in future GE endeavors = )

You mentioned a MOD file player for blender. Can you write a tutorial on that?

Well, I also mentioned that I had not been able to finish it last time I tried. I really haven’t gotten around to trying it again, and I might just try to implement SDL_Mixer instead, since it has MOD support along with mp3, ogg, MIDI and others. For now, you can use the latest version of Pygame to play MOD files. The only thing is, the end user has to have Python and Pygame installed in order to hear them. When I get the time I’ll read the mixer.py code with Pygame to see how they implemented SDL_Mixer and I’ll try to work it in to Blender (First with a Python script, hopefully with custom logic bricks later).

Right now I’m setting up an example blend on offering custom display modes without having to include three or more different versions of your game. It’s really pretty straightforward, so it shouldn’t take me long to finish with that. Of course, I still have to make the save/load example blends after that, and somewhere in there I wanted to play with ashdid and saluk’s multiplayer online setups… Plus I still haven’t beat Super Metroid. As you can see, I’ve got a lot to keep me busy.

Man that really stinks we can’t make a save/load system for the entire game’s state, if it were true then it really kills most reason to make really long games in Blender. Maybe someone can dig into the source code and make a save/load actuator. Or you can assign each level a password like in a lot of old Sega Genesis games (Ecco, Tiny toon adventures, ect…).

BlendEnzo YOUR MY SAVIOUR LOL. man u got tuts. on stuff ive been askin about on here lol. thanks alot.

an awesome tut … thanks

I have a little problem with this one.
When I try to load the data back in it says “invalid literal for int()”. I think it’s because it loads the
too. Because when I did the "this is a valid save file
" thingy I had to put if head == "this is a valid save file
":, could that be it? that the int() won’t work when it hits a "
"? (the string looks like "10.32424243
" I think) If so: does anyone know how to remove the
? If not, what do you think is the problem?

Interesting error. I actually never tried my save/load system (it was all theoretical), so I’m glad to see that someone has. The easiest way to solve your problem would be to read the line, then find the length of the string and make a new string that consists of all but the last two characters.

loadFile = open("Quest1.sav", "r")

<i>...If you have a header, read it first, then test...</i>

# <i>Read in the line to a </i><i>temporary variable</i>
playerLevelTemp = readline() 
# <i>Find the length</i>
playLevLength = len(playerLevelTemp)
# <i>Write new string without newline symbol</i>
playerLevel = playerLevelTemp[0:(playLevLength-2)]
# <i>Convert to integer and assign to global variable</i>
GameLogic.playerLevel = int(playerLevel)

<i>...Read in any more data you may have...</i>

loadFile.close()

This could be done with a bit less code by combining a few steps, but you get the idea. Let me know if it works.

Edit: BTW, if you’re curious, the code uses something called “slice indices” to write the new string. The line where the new string is written is saying “start at the beginning of the string (0) and read everything except the last two characters.”

hmm… still getting “invalid literal for int()”… maybe I missed something when I changed the script, will give it a few more tries.

Edit: BTW, I’m always curious

Some progress! I made function (is it called right?) of it, mostly to train my almost non-existing python skills.

def oneLine(line):
    tempLength = len(line) 
    newLength = line[0:(tempLength-2)] 
    return(newLength)

it works! now I get “invalid literal for int(): 16.7999973297”… it’s sligthly better I think:P… any ideas what to do now?

Edit: to be clear: it has changed from “invalid literal for int()” to “invalid literal for int(): 16.7999973297” or whatever number I put in the file. And only if it’s decimal. If I put 10 there it works perfectly… And I could do a int() before I save it instead but I would like to know what’s wrong here

Sim, I just realized your problem. The error code “invalid literal for int()” is saying “Hey! This isn’t an integer, so it can’t be converted.” The problem is that your number (16.799…) is a float type variable, not an int variable. Int variables are whole numbers (like 1, 2, 3, etc) where floats can include fractional numbers (like 1.12345 or 9.87654). You need to use the float() method instead of the int() method. So your code should read

GameLogic.<i>yourVariable</i> = float(<i>yourStringData</i>)

I tried it out in the IDLE Python Shell on my computer and it worked. Here’s what I typed:

&gt;&gt;&gt; x = 12.3456
&gt;&gt;&gt; y = str(x) + "/n"
&gt;&gt;&gt; z = float(y[0:(len(y)-2)])
&gt;&gt;&gt; print z
12.3456

Notice that you still need to subtract the newline character to get a proper conversion.