Save game feature preferences

One thing that almost all of my games have lacked is the ability to save progress. How long does a game have to take before you really notice the lack of a save feature? 10 minutes?

My one game that had a save feature had only a really simple one: one save slot, and saves were automatic. I kind of liked that. Do you prefer auto-saves, or do you want to be prompted or have to select it from a menu? How many slots do you want? Do you want the ability to name your game, or is "slot 1", "slot 2", etc good enough?

(log in to comment)

Comments

I think this really depends on the sort of game you're dealing with. Part of that is the length of the game, certainly, but part of it is also the kind of game you're dealing with. You notice the lack of save feature much more quickly in a strategy game or RPG than in a shoot-em-up or platformer. On average though, 10 minutes does sound about right, although I wouldn't get annoyed at the lack of a save feature in a game that took less than about an hour. For the majority of Pyweek entries, this means that a save feature is fairly unnecessary.

From a Pyweek standpoint, one strong point in favour of save systems in general, and automatic saves in particular, is that a lot of games in Pyweek crash unexpectedly. You'll get a lot of goodwill from me if that doesn't mean I lose my place!

Another thing to consider is what "saving" means in the context of a particular game. If you look at some of the Super Effective games from Pyweeks past, Robot Underground had a quite complicated savegame system, storing all sorts of state about the player and the plot. After The Fall, on the other hand, simply stored how many feathers you had collected. Both systems were appropriate to the games in question (or at least I think so) but they were vastly different in terms of scope.

As to the question of multiple slots, I'm not sure it's really a big deal. We included the option of five save slots in Robot Underground, but I'm not sure anyone ever used more than one or two. Similarly, naming your save game seems like a nice feature, but I doubt it's something which would improve the game experience much. I think usually the effort would be better spent elsewhere.
Yeah I agree with Martin: be aware that your choice on this front can really affect the game itself if you let it.

I always bang on about Nethack to anyone who'll let me: It's a nice extreme example of this. Saving is mandatory when you quit, erasing any previous save. There is no other way to save. The only way to load is when you start the game. Hence, you can never go back to a previous save to have a 'do-over'. You have to live with every action and every setback. A single game can last weeks, so this makes players *terrified* that they are gong to maim or kill their precious character, especially since the game is wildly exuberant about handing out sudden deaths or comical handicaps. (You got turned into a worm. You drop all your belongings. "Take wand of death." You have no arms. "Cast magic missile." You cannot speak.) The thing is, that players would rather work around awful setbacks like this (figure out how to survive as a worm long enough to make it to throw yourself into a that polymorph trap you saw six levels back) than restart the whole game over. So it changes the way people play, and the whole emotional feel of the game. It is possible to reach into the install dir and make a backup of your save games, known as save-scumming. It's noticeable that when you do it, and use your backups to restore whenever things go badly, the game isn't half as exciting.
Then again I couldn't imagine playing the original X-COM game without constant restarts from savegames - that game was merciless :-)
In a couple of FPSes I've played I've been frustrated by checkpoints that coincidentally autosaved a fraction of a second before I got fragged. Then you have to reload about 25 times trying to escape the chain of events. But in more polished, more recent games, the checkpoints and autosaves seem to be placed very carefully, at natural lulls, and before encounters that are more likely than average to kill you. The hint that the autosave gives you sadly takes away some of the spontaneity but at least it makes for a more enjoyable game.
Yeah, I guess it obviously makes a huge difference in the kind of game. At one end of the spectrum are games where the only progress you make involves unlocking levels or more challenges, such as those puzzle Flash games with 30 levels. In that case it only makes sense to auto-save and have just one slot.

The game I'm working on now is close to that end of the spectrum. The only thing you'll miss out on is, if you replay a level, it won't show you the same dialogue again. So I'm almost sure that auto-saving is the right thing to do. However, I also want to implement a shop, where you have a choice of what powerup to buy. In that case, I can see players wishing it didn't auto-save on them, because maybe they don't want to be locked into a powerup if they try it out and change their mind. I don't want people to be tempted to do save-scumming, but I find "wanna save?" prompts so annoying in most games, since I always pick yes.
Allow players to sell back to the shop, with depreciation?
That's a pretty good idea in a lot of cases. In my case, there are 10 items in the store, each of which costs one coin, and there are only 10 coins you can possibly collect in the game (one for completing each of 10 side quests). I originally planned to have each item associated with a specific side quest and leave out the coins, but I thought it might be a little more fun if you could choose.
Just remember that in python saving is EASY to implement.

import pickle

pickle.dump(gamedata, open('savefile.sav','w')

game saved.
Well yes, that part's easy. The hard part is making sure that your gamedata object actually contains everything you need to save, and that when you load it back, all your modules correctly read the data they need from it. :)
ikanreed:

I don't like pickle, m'self. If you can't easily serialize your data yourself (IE: Using markup or something, rather than something like pickle which handles it for you), you need to simplify things, I think. I can't picture needing anything beyond JSON of YAML for save data. You should be able to deduce the state of things (Including the state of objects) from plaintext in a reasonable way.

That and there's the fact that pickle only works on things that are hashable (At least if I recall), which means (To my understanding) that you'd be just as well off using JSON or YAML. (Or better: You can read JSON and YAML files in a text editor to spot errors you may have made!)
The pickle approach has some serious issues. Saved games can very easily break in interesting, hard to fix ways, if any of the classes that were pickled are later changed. Pickle can also have issues if the version of python changes. The other problem is it leads you to be careless and just save everything, when a lot of the time you DON'T need or even want to save everything. The save system should be as well thought out as the rest of the game programming, because if someone has problems with saving (or problems with loading their saves) chances are they will ditch the game. This isn't to say that pickle by itself is bad, it just doesn't really fit saved games as well as you'd think.
there's the fact that pickle only works on things that are hashable (At least if I recall), which means (To my understanding) that you'd be just as well off using JSON or YAML.

Well that's simply not true. Unhashable objects are no problem. There are some restrictions on what you can pickle - for instance you can't pickle a lambda - but they don't come up very often. It handles things like circular references, which is very hard to get right if you're re-implementing serialization from scratch. If you're writing a FPS with AIs that are FSAs, and you want to save the AIs' state along with the game, circular references are extremely likely.

Pickling works great, and it really is just one line of code like ikanreed says. I doubt that any benefit I would get out of opening my save game in a text editor would be worth the time it takes to write all that extra code.
I have to agree with Akake here - pickling seems great at first, but it can be a serious pain. Separating out the things you really want to save from the things you don't before pickling can be just as complicated as writing out your own serialization code. It's also incredibly fragile - a small change to any part of the code can completely invalidate your old savegames. Finally, it's insecure - you shouldn't unpickle an untrusted file, as it has the capability of running arbitrary code. We came up against this problem with Intestinvaders - we couldn't store replay data as pickles because an unscrupulous individual could upload a replay which did something very nasty to the hard drives of anyone who watched it. Beware of this if you're thinking of passing save games between users, say for debugging purposes.
A lot of that makes sense for bigger games, but I think for a Pyweek game, pickling is the best option. Games generally don't last longer than 30 minutes anyway, so if you give out a patch that invalidates old saves, it's not that big a deal. And the fraction of players who upgrade python over the course of playing your game and who would like their old saves to be valid is minuscule.

And if you're debugging your game and passing data between players, you'd better hope that none of them are malicious, pickling or otherwise. How certain are you that there's no bug in your game that allows malicious code to run?
Of course I'm not certain there are no security issues in our games (although I'm usually relatively confident) but that's no excuse for introducing extra vulnerabilities.

As for invalidating saves, it really is a pain during the development process. If I have a save game that demonstrates a particular bug, it's really quite a pain if trying to fix that bug invalidates the save game. Even a few minutes of playing through to test the bug can really slow down debugging.

Anyway, the opinions I've given are based on my experience making Pyweek games over the last few years. It's true that some of our games have been towards the larger end of the Pyweek spectrum, but I think the principles of making a large game really do help with making a small to medium-sized one. You don't want to end up hamstrung on day five or six because of shortcuts you took on day one.
Okay, you make good points, and I certainly can't argue with your results. However, I would say that in all the Pyweek games I've made, getting "hamstrung" because of shortcuts I took early on is far, far, far less common than running out of time for later features because it took longer than I expected to make early features.

Using shortcuts is probably one of the most important things to do in Pyweek for me. I'm sure the fact that I'm generally a solo entrant has something to do with that, since it means my development is single-threaded: every minute I spend on a save feature is one minute less I have for everything else.
Well, I can't argue with your experience either, and I think the point you make, that every minute spent on one feature being a minute not spent on something else, is extremely important, whether you're one guy throwing something together on the Saturday evening, or a huge team working night and day for the whole week.

Maybe the thing to take away from this discussion is to be realistic about the time you'll have available, and the scope of the project you're undertaking, and to plan accordingly. If early decisions are coming back to bite you, then it's probably a sign that you underestimated what you were going to be able to achieve, whereas if you're struggling to fit in features, you've probably erred a little in the opposite direction. I've certainly experienced both during Pyweeks past!
Err, and into the original topic of the thread (How to handle saving game state):

What I like to do (And I'm liking it more and more) is to use markup. Python's json module is generally sufficient, and less problematic than pickle. All you need to do to save something in a json file is reduce it to number, strings, dicts, and lists/tuples. It's not that hard if you can either consrtruct an entity in an arbitrary state or have a nice entity factory that can construct that entity and set it into that state.

(Mind you, I'm likely to use PyYAML this PW, because YAML is much nicer than json, but python has a json module in the standard library)
The json module looks pretty good. It would be nice if it could automatically handle user-defined objects whose __dict__ is json-able, but that functionality doesn't look too hard to add. Unfortunately, though, it's only Python 2.6+, and I don't know if I'm ready to exclude 2.5 users....
You may be interested in simplejson, which is a pure-Python implementation of 2.6's json module, for 2.5. It's pretty easy to package with your game, and conditionally import like this:

try:
import json
except:
import simplejson as json
Cosmoligicon:

Why are you serializing your game objects? Serialize their state, build new objects and give them the recorded state when the save file is being loaded. It's not really that hard, I don't think. Or am I just too willing to do extra work for code that's unnecessarily clean?


Martin:

Nice find :)
It's not that hard, no. But it is more work, and it's more error-prone. As to whether you're too willing to do extra work, it's certainly possible, if you're talking about a Pyweek game. Every bit of extra work you do for the sake of clean code adds a little more chance of DNF. IMHO, anyway. :)
I respect your opinion, but I believe that it's not a big deal to serialize state and not objects. There are plenty of things that take up more time than putting together a factory (One that can reconstitute saved state into the appropriate objects) as you work, and are thus bigger pains. IMHO, of course. :)
Martin: The bare except makes me shudder. I'd do

try:
import json
except ImportError:
import simplejson as json

even for standard libraries like json. Catching exceptions too broadly is the number one cause of headfuck-level bugs in Python imho.
mauve: Fair point, although I'd say if you're throwing exceptions other than ImportError when importing standard library, your head is already fucked.
Martin/mauve:

Why not just use simplejson if you have it? (IE: Don't bother with the standard Python json module) If it's good enough to use at all, you can probably use it by default.
Mauve, I always just use an exception logger and log EVERY error I find.