The Basics
The simplest, and easiest to use method for anyone with a basic understanding of ActionScript is the SharedObject, available in ActionScript 2.0 and above, and all recent Flash players. Using this is dead simple, like so:
- Code: Select All Code
savedGame = SharedObject.getLocal("LoKSavedGame");
savedGame.data.items[0] = "PrincessOutfit";
savedGame.data.items[1] = "FlightSuit";
savedGame.data.location = "SharpClawVillage";
savedGame.flush();
This is a simple example that gets a saved object, puts some items in and a note of your current location. It's worth noting that all data is added to "savedGame.data", adding to any other part of the object, for example "savedGame.value = 1234" will set the value as normal, but it will not be saved.
The .flush() method is what actually saves the data, and while it is performed automatically when you close a .swf, it is worth controlling when .flush() is called to avoid half-updated data being saved at unusual times. For this reason, you may wish to save automatically at designated locations or checkpoints, or upon entering a new area. The following example is the simplest and easiest case, which is a button that when pressed will save a player's important information; since this can be made visible on all scenes it is the easiest solution for simple games:
- Code: Select All Code
on(release) {
_root.savedGame.data.items = _root.player.items;
_root.savedGame.data.location = _root.player.location;
_root.savedGame.data.flush();
}
Which will immediately save the player at the current location, and save all their currently held items. In this example _root.player contains all current player-data for the game to interact with, and this data is simply copied into the SharedObject for saving, ensuring no unusual partial updates occur.
Validation and success
SharedObjects, just like cookies in a web-browser, are made available based upon the domain-name that the .swf is accessed from, meaning that if you play the game on site A, then play another copy on site B, you will be unable to access your saved game from site A. This isn't usually a big deal for most games, and requires a more complicated solution, which I'll describe at a later time.
In the mean time however, SharedObjects, just like cookies, may be rejected by a user, and it's worth making sure to test for such cases, as you may wish to inform the user of a failed save-game so they can do something about it, you can do this by simply testing the return value of .flush(); a value of true or false indicates success or failure, while a resulting of "pending" indicates that the user has been asked whether to allow the save or not.
If you wish to know what a user chooses for a pending request, then you can do the following:
- Code: Select All Code
_root.savedGame.data.message = "Save me!";
success = _root.savedGame.flush();
if (success == "pending") {
_root.savedGame.onStatus = function(code) {
if (code == "SharedObject.Flush.Success")
trace ("Save Successful!");
else
trace ("Save Failed!");
}
} else if (success)
trace ("Save Successful!");
else
trace ("Save Failed!");
This might look a little complicated, but it's easy to simplify depending upon which cases you're interested in (if any). Quite simply .flush() is called, if it succeeds then save was successful, or if it fails then it failed. If it is pending then a function is provided and called when the user makes a decision.
One last note, is that you can provide a size (in bytes) to the flush command, allowing you to specify a minimum amount of memory required by your SharedObject, useful for ensuring it has room to grow, it's important to keep the value sensible!
Sharing data between .swf files
If for some reason you have multiple .swf files (for example, updated versions of your game), then you can share data between them by making sure to specify as non-specific a domain as you can when fetching your SharedObject, but you must remember to do this in all of your .swf files, as by default a .swf can only read shared objects created by the .swf that created them, and only if it isn't relocated!
Like so:
- Code: Select All Code
savedGame.getLocal("LoKSavedGame", "http://legendofkrystal.com/game");
This will fetch, and later store, a SharedObject accessible to any .swf location in the domain legendofkrystal.com/game, and so long as other games in that domain fetch their SharedObject the same way, then they'll gain access to the shared data! It's worth noting that if you do do this with different versions of your game, that you need to remember that data stored by previous versions may not be in quite the format you expect, for this reason it may be worth storing a version number in your saved-games, and deleting any saved game that is too long out of date. Which brings up the next topic:
Deleting SharedObjects
Default behaviour for a SharedObject is to retain all data entered into them, which means you need to delete all data in the SharedObject before flushing the (empty) result, like so:
- Code: Select All Code
savedGame = SharedObject.getLocal("LoKSavedGame");
for (i in savedGame.data) delete savedGame.data[i];
savedGame.flush();
This can be useful for deleting old saved-game data that is no longer compatible, or for creating a new saved-game that overwrites the first, as other old values may still be left in the SharedObject that can result in a corrupted game!
For works in progress
For those of you wanting to add save-games to something you're still actively developing, then it's best to provide some resistance to data corruption or odd save-game glitches by designing core statistics for your game as early as possible. So let's take a look at combining some of the ideas covered.
Let's say you have a game with levels, and experience for upgrading characters. These two stats should allow you to preserve old player-games, without needing to worry about current level, checkpoints, or character upgrades, in such a way that you can trash old data without inconveniencing players too much.
So, let's take a look at saving the game:
- Code: Select All Code
savedGame.data.version = _root.saveGameVersion; // Save game version, increase this as you change the save-game data.
savedGame.data.level = 4; // Save the highest game-level that the player reached, so they can return to it, even if they can't pick up exactly where they left off.
savedGame.data.experience = 123; // Save experience points total, this should also cover the value of all upgrades purchased, so if you have to nuke a user's upgrades, they can re-purchase them again.
And here, some compatibility checks for older saved-games:
- Code: Select All Code
// Grab the crucial progress stats
playerLevel = savedGame.data.level;
playerExperience = savedGame.data.experience;
// Check save-game version
if (savedGame.data.version < _root.saveGameVersion) { // We should delete old game data
for (i in savedGame.data) delete savedGame.data[i];
} else if (savedGame.data.version > _root.saveGameVersion) {
// Save game was created by newer version of game! Best to warn the user they need a newer copy of the game, to avoid losing data.
// Alternatively, remove this section and test above for "savedGame.data.version != _root.saveGameVersion"
} else { // Otherwise, it should be safe to load remaining game data
currentLevel = savedGame.data.currentLevel;
currentCheckpoint = savedGame.data.currentCheckpoint;
}
This is a good format even for release games, as you never know if you're going to add stuff later that may be vulnerable to unexpected values from old saved games.