Workflow and User Events - Grisgram/gml-raptor Wiki
I've tried to simplify the workflow for the complicated task of creating a savegame file as much as possible and ended up with only two user events that need attention while the game is saved or loaded.
In addition to that, some objects might need to know, when they are created, whether it is a regular object spawn or if the instance just got created during the game load workflow.
An example for this could be an object that creates additional child instances when it is created (like preparing some bullets so it can shoot or some animated objects surrounding it). If the object just gets restored from a save game, it does not need to create those childs, as they are probably part of the savegame anyway and will get created by the Savegame
system.
This is the moment, where you might want to query the SAVEGAME_LOAD_IN_PROGRESS
or SAVEGAME_SAVE_IN_PROGRESS
macros to skip that part in this case.
The next logical thought is now "Ok, but when those child objects are also created for me, how can the Savegame
know, that these 25 Bullets are my Bullets? What about the links between objects, restoring pointers to other instances?".
This very complex question is answered. Savegame
can do that!
But before I go into detail on that, let's take a look on the timing in the workflow, especially the two *_IN_PROGRESS
macros mentioned above. You need to know, when they are true
or false
to understand how instance link save and restore works.
Saving | Loading |
SAVEGAME_SAVE_IN_PROGRESS = true |
SAVEGAME_LOAD_IN_PROGRESS = true |
onGameSaving (User Event 14) | onGameLoading (function) |
onGameSaving (function) | SAVEGAME_LOAD_IN_PROGRESS = false |
SAVEGAME_SAVE_IN_PROGRESS = false |
onGameLoaded (function) |
onGameSaved (function) | onGameLoaded (User Event 15) |
You can see, the present time ...ing
(Sav_ing, Load_ing) functions are invoked while the progress variables are true
and the past tense ...ed
functions are invoked, after the flags returned to false
. So, from a timing view, after the process has completed, but before the control is given back to the game. On a call stack view, we are still in the save
or load
function respectively.
Saving and restoring instance connections
GameMaker assigns each object an unique id
when it gets created. This will very likely not be the same, when the game gets saved and loaded back into memory. So we need some kind of reference that allows us to "re-link" objects after they have been loaded.
raptor
offers two helper functions for this task.
You have to do this in one direction when the game gets saved (in User Event 14
or in your implementation of onGameSaving
) and restore it in User Event 15
or your implementation of onGameLoaded
.
This sounds more complicated than it actually is.
Let's play through this with a short example of an object that holds 25 Bullet
private child instances and another instance of an AnimatedShield
Object that surrounds this object as a kind of a visual damage shield.
Create
// Create event
// Note: this is NOT held in .data! A normal instance variable!
// The objects `Bullet` and `AnimatedShield` are assumed to be also a Saveable objects!
my_bullets = array_create(25);
my_orbiting_shield = undefined;
// Take care, to create bullets only, if you are not currently restored from a savegame
if (!SAVEGAME_LOAD_IN_PROGRESS) {
var i = 0; repeat(array_length(my_bullets)) {
my_bullets[@ i] = instance_create_layer(x, y, "Instances", Bullet);
i++;
}
my_orbiting_shield = instance_create_layer(x, y, "Instances", AnimatedShield);
}
onGameSaving (User Event 14)
The function savegame_get_id_array_of
saves the instance ids of the Bullet
s to an array.
This array is stored in data.my_bullet_ids
and will therefore be written to the savegame.
// User Event 14 (onGameSaving)
data.my_bullet_ids = savegame_get_id_array_of(my_bullets);
data.my_shield_id = my_orbiting_shield.id;
onGameLoaded (User Event 15)
The function savegame_get_instance_array_of
takes the stored ids and restores the corresponding instances after all objects have been loaded.
This mapping is possible, because Savegame saves the ids of all existing objects in the savegame.
So it can find out, which id the object had when it was saved and can find the exact object after loading.
// User Event 15 (onGameLoaded)
my_bullets = savegame_get_instance_array_of(data.my_bullet_ids);
my_orbiting_shield = savegame_get_instance_of(data.my_shield_id);
You can see, storing and restoring of linked objects is done in a single line of code!
More details on the helper functions above and all other available supporting functions of the Savegame
system can be found in Savegame functions.