Construct 3 provides an easy way to make savegames. These allow your players to save the game, then come back later and load it from exactly where they left off. It's important for long games, especially when the levels or stages are lengthy. While it's possible to have a very simple "last level reached" type save using Local Storage, it's usually very difficult to use it save the full state of every last object. The System object's Save and Load actions conveniently allow you to do just this, allowing you to easily add a complete savegame feature with very little effort.
Basic savegame support
A simple way to add savegames is just using the system Save and Load actions when a certain key is pressed. For example:
For mobile games you'll obviously need to use some kind of touch input instead, but to keep things simple we'll focus on a desktop game.
Savegames are stored on the local system by the browser. This means players can switch off their computer or device, come back the next day, and the savegame can still be successfully loaded. Note however savegames are associated with the specific browser. For example, Firefox and Chrome will store savegames separately; if a player saves a game while using Chrome, then switches to Firefox, they will not be able to load that savegame.
Savegames are not saved in the cache. The browser cache is a very much temporary storage that is used to save things like images on web pages without having to re-download them every time, and it's regularly cleared. Savegames are saved instead to IndexedDB storage, which is more permanent. However the user can still manually clear their storage which will wipe IndexedDB as well.
It's often useful to allow players to have multiple savegames. This is what the save slot allows. Each slot is like a separate file that stores a different save. You could offer the player a set of slots to save to, or allow them to enter their own savegame names.
Note that most browsers have a limit on how much data a web page can save to disk. This is unlikely to be a problem for most games, but if you have a huge number of separate save slots you might hit the storage limit. Offering a limited number of save slots is a good way to ensure you never hit the limit. Appropriate use of the No Save behavior can also help make savegames smaller (see below).
Saving can take a moment to complete, and the game keeps running in the mean time. Once saving has completed, the System trigger On save complete triggers. Similarly loading can take a moment to finish, and triggers On load complete when done. Note any changes made after the Save action, but before On save complete triggers, may still be saved.
If you try to load from a slot that hasn't been saved to yet, On load failed will trigger. If the user is choosing a save slot to load, you may just want to start a new fresh game in this event.
'No Save' behavior
Anything with the No Save behavior will not be saved, and won't be affected when loading. It is good practice to add the No Save behavior to any static objects, such as scenery and backgrounds. It can also be used on automatically-updated objects like the HUD and text objects which are updated every tick. This won't make any difference to the game, but it makes savegames smaller and faster to save and load, since the unnecessary information is omitted.
Changing the project after saving
Savegames should be robust to changes in your project. You should be able to add, remove and reorder various things like variables, behaviors and other objects, and still have old savegames load successfully. Note however anything new you add won't have save data for it, so will not be affected when loading. Also note if you remove anything from the project it won't be able to load again either. You can delete individual instances without affecting savegames, but if you remove entire object types, layouts or layers, they will never be loaded back from a savegame.
Everything covered so far is enough for most games to easily add a savegame feature. However advanced users may be interested in the following topics which go in to further detail about the savegame system.
Tracking which slots are used
The system save/load actions don't tell you which slots have been saved to. The best way to track this is to store some extra meta-data yourself in the Local Storage object. For example, whenever you save to a slot, also write a Local Storage key that indicates the slot has been saved to. You could add some other metadata like the player name or even a small screenshot of the game as a data URI. Then you can tell which slots are in use from the Local Storage data you've saved. You can perform other operations like resetting or clearing save game data just by adjusting these meta-data keys, such as removing them to make it look like the slot is empty again.
What is and isn't saved
The full state of the game - including instance variables, global and local variables, behavior properties, effects, particles, currently playing audio, etc. - is saved. However there are a few exceptions, hopefully none of which are surprising. The following things are not saved and won't be affected when loading:
- Input state (i.e. mouse position, or whether the player was holding keys or touches)
- AJAX requests
- WebSocket connections
- The XML object
- User Media video or audio feeds
- Login state for any services like Facebook
- Local Storage state
- Any in-app purchases on any platform
- Anything with the 'No Save' behavior
Using the JSON data directly
In both the On save complete and On load complete triggers, the system
SaveStateJSON expression returns a string of all the JSON data for the savegame. Note the
SaveStateJSON expression will return an empty string outside of these triggers; the triggers are your only opportunity to access the data directly.
If you have your own server, it's possible to make shared savegames by posting the JSON data to the server with the AJAX object and storing it in a server database. Alternatively some platforms allow you to store data for the logged in user, where it's shared anywhere they log in. This is a useful for allowing users to take savegames with them wherever they go.
Once you get the JSON string back, you can load the game from it using the Load from JSON system action.
Usually you'll be able to change your project and old games will still load just fine. However some advanced users may wish to track precisely which version of their project a savegame has come from. You can do this using a global variable. Call the variable Version and initialise it to 1. Later, if you publish a new version of your game, change the initial value of the variable to a new number, e.g. 2. Now when On load complete triggers, the global variable has been loaded and set with the value of Version at the time the Save action was used. This might be useful if you add lots of new objects to the game, but want to make sure they're destroyed or hidden when loading old savegames.