Link to project file if you care to study it
Quick Tutorial
For saving/loading variables
Saving
This is for users who already did some stuff in gdevelop
Event
Action from above event
Be sure to pick Save a text
Loading
Event
*! Add TempSave variable in scene variables window
Actions from above event
Be sure to pick Load a text NOT a value
Be sure to pick Convert JSON to variable NOT object variable
You can test it here
Click here to learn how to load at beginning of the scene (Auto load)
And here how to create save data if save data don’t even exist
And how to load save data if it exist both at beginning of scene
And do the same but for key pressed (Could be done with button press)
In at beginning of scene variant we wait 1 sec in action 1st if save don’t exist to let variables from variable window load 1st then we perform a save
In e key pressed variant
We simply set these variables to some values then perform a save if save don’t exist
In both cases if save data exist or to be accurate if MyGroup exist in MyStorage then data will be loaded into variables
This is enough if you know what to do
If not then what is below is for you
Common mistakes
Read this before you come to me asking why it is not working
Double or even triple check have you done it correctly
Click here to read about most common mistakes
-
Putting “quotes” when you should not
Pay close attention
Save action have ToJSON (Name of Global variable to save) then “group name” in quotes and “storage name” in quotes
Load action have 1st “group name” then “storage name” in quotes then scene variable without quotes
While convert to JSON have both scene variable and Global variable you are loading without quotes -
Temporary scene variable gives you error? Add it in scene variables window
-
PAY CLOSE ATTENTION to names i am dyslectic i have no shame in it
Yet i tend to write Stroage instead of Storage
1 character missing or in wrong place can ruin here everything -
Did you put storage and group names in proper fields?
Same for variables
To help you look at this pic again
In order from left to right top to bottom we have
For SAVE
ToJSON(Global variable you save) expression then GROUP NAME then STORAGE NAME
For LOAD
GROUP NAME then STORAGE NAME and Temp scene variable
Temp scene variable then Global variable you load
Or maybe this will help you
-
Did you select Save/Load a text and NOT value?
-
Using WAIT action for saving or loading
DO NOT DO IT
I did it only cause its at beginning of the scene to create system where your vars will not be set to 0 and you don’t need to set your vars in actions before loading
So their default values will be loaded from variable window -
Issue with wait action is
IF you have condition button clicked and action wait 1 sec then save
Like here
-
Then if you click 3 times fast it will wait 1 sec from each click and save
So if you spam that save button you have fair chance to corrupt your save data
While if you would go with timer like here
-
Then clicking it resets it to 0 so even if you keep spamming it as fast as you can
You are NOT gonna execute save action multiple times cause you did not let timer reach that 1 sec value
That is why DO NOT use wait action in save/load events unless you absolutely know how/when to do it
Go with timers instead or other means
If you still don’t get it
Think of it as wait action is throwing ball of stairs
You can’t stop it
Now resetting timer is like having little dog or cat
And they wanna go away from you to your plate and eat your food
And you are pulling them back to you
So as long as your pet did not reach your plate your food was not consumed
Useful tips
My best practices what to do and what not to do when managing your save / load events
Click here to read some tips i have for saving and loading
-
Do NOT name your storage the same for every game
Cause if you gonna delete save to see if it works
You gonna delete it for all projects you are testing since storage name for them are shared
We are talking here about testing games in your gdevelop and in browser
I go with GameNameStorage
For example i made game called Expand When Four
So i go with EWFStorage instead of MyStorage or just Storage -
I would also suggest giving your nickname as prefix to storage name
For example ZeroX4EWFStorage
Cause if someone would follow this tutorial and made game called Even With Friend then he would name his storage EWFStorage so it would create shared storage for both our games (that is for ones played in browser)
So after you get familiar with saving/loading storage you could forget about Storage suffix and just go with NicknameGameRelatedTag in my case ZeroX4EWF or any unique name i could go with 0104EWF
0 zero 10 roman ten so X and 4 well four and here goes my nickname
Even ZX4 would do or X4
But again that is case just for browser games i believe
And chance other person make game with same name of storage is slim
YET not impossible
Better to avoid such situation than be sorry for lost save data -
When you separate your game save from your settings save
Use group name as means to decide what you save/load and when
While splitting stuff you save/load into separate structure vars
For example
Here i split game progress (game save) and settings save into two structure variables
So saving settings and game progress is independent and don’t affect each other
Now i could go with GameStorage for storage name and two groups
SettingsGroup and GameGroup for group names so i could go with
And so in 1st event i save each 10 secs (where 1st save starts at 5 sec) my game progress (Yeah i just made auto-save)
TimeFromStart() is counting time from scene start
modulo expression is looping that number around whatever you type there i did 10
But it does not go 1 2 3 4 5 6 7 8 9 10
Nah it goes 0 1 2 3 4 5 6 7 8 9 it starts from 0 not 1 where in both cases we have 10 numbers
So checking if its greater than 10 would be stupid cause it will never reach 10
(That is why i check if its greater than 5 i could check if its greater than 1 or 8
Well i could check if its greater than 9 also
BUT NOT from 0 cause it is always greater than 0 so condition would never return false)
So 1st save is performed after 5 secs and then any following save is performed in 10 sec intervals -
!!! DO NOT !!! Try to spam saving cause it can corrupt your storage and you can kiss your save bye bye
If you don’t need to save often then don’t
Saving each 10 sec is ok
But if someone get idea to save every second then that is just dangerous for your save data -
Since we are using different names for groups we can target which group we want to delete
For example delete game progress which won’t affect settings since they are stored in different group
But if you wanna go all out on it there is action to wipe out whole storage
I added to my project that pressing space delete whole SLStorage -
If you need to delay your save / load anywhere else than at beginning of scene
DO NOT USE WAIT ACTION use timer or TImeFromStart() in compare two numbers condition if you know how to handle it
WAIT action is asynchronous so if you press save button 2 times fast
Game will try to save it 2 times after that WAIT time
And so you are open to corrupting your save data
Timer or TimeFromStart() would never have such problem
YET TimeFromStart() is more tricky to set up
Cause you would need to set variable to TImeFromStart()+1
And now check if variable value is less than TimeFromStart()
For example at the moment of when you click save button
TimeFromStart()=5 if you go TimeFromStart()+1 it will be 6 while actual time IN THAT MOMENT is still 5
And you set that variable to TimeFromStart()+1 so you did set it to 6
And you have another event to check if your var is less than TimeFromStart() then only after it will be +1 sec from the moment of when you click save button
Save would be performed
Exactly like here
-
Doing exactly the same thing but instead of setting var to +1
We check if var is less than TimeFromStart()-1
-
I show you this just so you could get the idea how it works
It is confusing at 1st but can be used for A LOT of things
In Depth step by step tutorials
Saving/loading variables
This is for users that are totally lost and have 0 idea what is what and how to do it
Click here to read step by step in depth tutorial
-
1st of all you are not saving your game state nor does you are saving your game like making snapshot or screenshot of what you have at the moment
You are saving and loading variables
Then changing stuff to these variables so for example
You set your sound to be played with volume of 100
Instead you set your sound to be played with variable SaveGameVariable.VolumeSound
And now you only change that variable from 0 to 100 to play it with different volume
But if you want to save it you just save SaveGameVariable and then load it
Instead of each individual variable -
Next thing to address you most likely want to save global variables which are structures
Global variables cause they exist globally in your game so like between scenes
Think of it as your PC master volume it will affect every sound in your PC
Where if you change sound on youtube it will affect only sound on youtube
And only on your account -
What are variables?
Think of them as price tag
It is nothing else than just container of some information
I can slap price tag on you and write on it $100 so you will be worth 100 dollars
And when going shopping i can tell you to buy only stuff that are not more expensive than $5 (so you can’t buy yourself)
So you can check price of each product and check if its lower higher or equal to 5
Same exact story with variables
Just for number vars you can do equations with them for example
Player.HP+20 when you collide with healing item will add 20 to your player variable HP
Where text variables stores text so you could save like player nickname in it or whatever
And adding text to text var like adding 2 to 4 will end you up with 24 -
Why structure?
Imagine having folder with your player images like 50 of them
Wanna copy/paste them from one folder to another 1 by 1?
No? So how about copy/paste whole folder?
And that what structure variables are like a container
You shove in your vars under some structure variable and only save/load that structure variable instead of each individual variable
Or to put it simple
If you save/load structure variable (or array)
It will save/load all its child variables
So exactly as you would copy paste folder -
Step 1
Let’s create some Global variable and call it SaveGameVariable -
Open project manager panel in upper left of gdevelop
-
Click Global variables and now add new variable call it SaveGameVariable
It could be named anything but just for sake of simplicity UNTIL you learn what is what in these event let’s go with that
Change it to structure
And add to it child variables which you care to save
I will go with 2 child variables called PlayerPosX and PlayerPosY
And this will be used for game progress save -
Step 2
In your events sheet add event for when save will be performed
For me it will be when Q key is pressed
And i gonna add to it trigger once
Saving SHOULD NOT run every frame but only once when condition is true
Spamming it may corrupt your save data
Next you will need to give name to your group and storage
I gonna name mine SaveGameGroup for group and SLStorage for storage
I suggest naming your storage with something related to your game name
For example i could go with SaveLoadStorage
But not to confuse ppl i went with SLStorage as in Save Load
This way if i work on multiple projects i will not affect storage of other projects
While not affecting games someone else use storage for with same name if i run games in browser
-
Pay attention here to select Save a text NOT a value
-
Because i want to save Player position
I also need to 1st set Player position to variables BEFORE i perform my save
And this would do it
-
Now i wanted you to see it with your own eyes
On purpose i did choose so long name for my save variable
Look how long it is in action itself
This is perfect moment to use your brain to come up with shortest names possible
Cause right now its one child variable so NameOfStructureVar.NameOfChild
What if you would have multiple structures under structures? -
I could totally go with save name like Save or even Sav
But trust me keep it this way FOR NOW
Just so you can learn where is what
When you master this stuff you can rename it to S for all i care -
Step 3
Now for loading
Event
-
And actions used in it
Be sure to choose Load a text NOT value
-
And here Convert JSON to a variable NOT object variable
-
If variables you saved are some stats like HP variable or Score variable or LevelUnlocked vars then this is all
-
BUT if like me you saved your player position NOW you need to change your player position to variables you just loaded
-
Change position action will do the trick here
So in my case it will look like
-
Pay attention that above when i was trying to save player position
1st we had actions for setting player position to variables
And BELOW it action to perform actual save
Here we 1st load it then change position to variables
Because in gdevelop all events are read from top to bottom
So order is here crucial -
Now how about we check does Q saves position of Player while E loads it?
I made small example here
So you can test it out
There are bricks around player so move somewhere and use bricks as your reference to where you are
Press Q to save move somewhere else and E to load
Or just move somewhere press Q close example and open it again then press E -
WASD or arrows to move around and well Q and E to save / load
Save Load Example | Play on gd.games
I say it works pretty fine
Loading sound/music volume at beginning of the scene
And saving it while you change volume with sliders
Click here to learn how to save/load volume using sliders
-
1st we gonna add new structure variable called SaveSettings
And add 2 child variables to it
Naming one VolumeSound and other VolumeMusic
-
We need 2 sliders one called SoundSlider and other called MusicSlider
There is no need to change anything
I went with duplicating same slider and putting Sound on the left and Music on the right
Design tip
It would be cool to have text object above them explaining which is which
Of course you can move them to hear which volume will change
But it should be obvious just by looking at them -
Anyway look at this black magic
-
Wanna bet it is ultra stupid? And more simple than you can imagine?
Let’s read it from top to bottom -
At beginning of scene
1st sub event we check if SaveSettingsGroup DO NOT exist in SLStorage
And if it does not we wait 1 sec
Set our volume vars to bar values and create save -
2nd sub event we check if SaveSettingsGroup actually exist in SLStorage
And if it does we load variables from storage
And we change value of each slider to our volume variables
(To clarify this sub event CANNOT run if 1st sub event did kick in
Cause they are checked almost at the same time while 1st takes action 1 sec later
So 2nd sub event will never be true if 1st was true cause 1st will become false 1 sec after it was detected of being true) -
3rd sub event we are playing music with play sound on channel action
(Pro tip - play sound on channel action for playing music
Play sound action to play sounds)
Instead of providing volume number we are just typing there our variable
And we are setting loop to yes so it start playing again after it finishes -
SoundSlider is being dragged (TIP it actually checks if its pressed and not dragged so you can click and hold it)
So as long as its pressed/dragged we are setting our sound volume var to value of this slider -
In sub event we are using condition compare two numbers (that is its name)
To check if mod(TimeFromStart(),1) is greater than 0.5
Your game by default is counting time from scene start
Think of it as native timer for each scene that is running
If we use modulo expression MOD it will loop around whatever number we specified
So if we put there 1 it only checks its mili seconds so from 0 to 0.9 and then it loops back to 0
We check if its greater than 0.5
And if it is with trigger once we play sound
So when dragging this slider each half second you can hear sound so you have audio indication what actual volume level is
And in play sound action we did not specify volume by number
We did just put there our variable name so volume is set to that variable value -
For clarification Play sound ON CHANNEL allows you to manipulate sound volume on that channel at any time
While Play SOUND action only allows you to change volume of sound with which it will be played
So after sound starts to play there is no way to change its volume
Think of it as flying a drone vs throwing a ball
When you fly a dron you can adjust its speed at any given moment (This is how play sound on channel works which should be used only for MUSIC)
When you throw a ball with some speed you can’t change it
As fast as you throw it that fast it will fly (This is how play sound action works which should be used to play your SOUND)
And main reason is you can’t play more than ONE sound at a time on ONE channel -
If you don’t understand what channel identifiers are (I did set my to 1 as you see)
Its like variable that allows you to refer/identify in events this specific channel
Literally imagine it is variable to which i just give value of 1
Same as tween identifiers
Or same as giving your object names
You can tell which object is which just by its name and in events reference them by their names
Here instead of names you have numbers -
Next one is Music slider being dragged
So as long as it being dragged/pressed we are changing our music var to to value of our slider
While 2nd action is there to actually change volume of our music played on channel 1 -
Pay attention here since we had in event above to play sound on channel (our music) with volume of our variable
We here are changing volume on channel to value of same exact variable -
Here we have OR statement (If one of these conditions is true)
To find it in conditions add condition and type OR in search bar then just add it
What it does is check if at least ONE condition listed in it is true
IF so it executes action
And here i wanted to show how to use timers
We are constantly resetting timer when at least one of sliders is being dragged/pressed (So its like setting it to 0 constantly as long as you hold it)
So when we release it it starts counting time -
And in last event we check if value of this timer (or if its time value) is greater than 1 sec
And if yes we are performing a save and then we delete this timer from memory
Idk if timers running forever affect your game but i know there are ppl
That are sick about anything running when it does not need to
So let’s just delete it
USING Trigger once it is very important here
Cause whole idea of this event is NOT to allow save spamming
We just created AT LEAST 1 second gap between saves
So clicking it will not allow it to be spammed
While save will be performed 1 sec AFTER last interaction with slider
And interacting with slider before that 1 second is reached will result in timer being set back to 0 -
So was it so much black magic after all?
-
Try it (Change volume with sliders and reload page)
Save Load Example | Play on gd.games
Save/Load ALL your objects
Let’s go with something harder like creating fake save state of your scene
Click here to learn how to save your objects and their attributes
Screenshot for users that know what to do and are here just for events setup
-
I followed this tutorial from official gdevelop youtube channel
https://youtu.be/9ReOBFoSD3g?si=em0aX62PSVJzSKql -
What is below is same as in the video above
Just with new variable system
And explaining few things you should consider when doing such save/load system -
I added hidden feature to my project which is different modes
-
You activate and switch modes by pressing Middle Mouse Button (MMB)
I put all my building items and enemies in AllObjects group
-
All slimes have variable called HP
-
I added SaveAllObjects var to my global variables and changed it to array
It have NO child vars
And here 1st thing to consider
Since to use object group variables you need to add it to all objects
I added HP var to group AllObjects meaning all of them have now this variable where only enemies need it
So this is the part that will hardly vary depending on your game
BUT in most cases it won’t matter if you give empty vars to your objects -
So let’s save everything
-
So let’s break it down (Again black magic)
-
What is in red rectangle is limitation for when you press any button Save/Load/Del so they can’t be pressed again for at 1 sec
And this is NOT part of save/load system but something i added cause i wanted to prevent spamming and it to look better -
Going from left to right top to bottom
1st we have condition ButtonSave is pressed (i am using button state behavior just add to your object behavior and type button in search bar)
So it checks if its interacted with (and that works perfectly for touch and mouse controls and nothing needs to be add here)
In action we clear ALL child vars from our global array variable -
1st sub event is repeat for each object instance
To add it right click any event or + in upper right corner of gdevelp and go to Add and then For each object -
In object name we put name of group of objects we want to save/load
And in which we placed all our objects we wish to save/load -
Leave conditions section empty
-
In actions section we are adding variable for each of our object to array as new child variable
So each action is this one
-
And repeat it for all attributes we care to save (so add new child variable for each one)
-
Next we have loading by pressing ButtonLoad
We are setting scene variable Climb to 0 (Climb is just number scene variable i added)
Delete AllObjects group to delete them all
Also i added here delete HPBar cause they are created dynamically and does not automatically get deleted by just deleting slimes but only by their HP variable going below 0 -
Now sub event which uses repeat event type and to add it
Again either right click any event or press + in upper right corner of gdevelop
Choose Add then Repeat
-
In how many times to repeat it we use expression VariableChildCount(Name of our array variable) / how many variables actions we had in repeat for each object event above (save event)
So since we are creating 7 child vars then it will be /7 -
Condition again empty but in Action we have
1st we click add action and select our AllObjects group (groups are always on the bottom of object list)
-
And we gain access to new action called Create an object from its name
And here we type SaveAllObjects[Climb] where SaveAllObjects is global array variable i use for saving/loading and Climb our scene var -
1st we have that SaveAllObjects[Climb] meaning we are putting here 1st child var from our array
Then or X position of our object SaveAllObjects[Climb+1] so we are taking 2nd child var here at index 1 and then Y pos we get SaveAllObjects[Climb+2] so 3rd child variable at index 2
Next we repeat it for Z order with SaveAllObjects[Climb+3]
Opacity with SaveAllObjects[Climb+4]
Angle with SaveAllObjects[Climb+5]
HP variable with SaveAllObjects[Climb+6]
And here we are adding 7 to our climb variable
So next object will get next 7 set of child vars to it
In same order it was saved
So next name given to 2nd object will not be form 1st child but from 8th (which is child at index 7)
Where next X pos will not be from 2nd child but from 9th since 7+2 = 9 (So again it should get 2nd child at index 1 but since we just add 7 to climb it will be 9th child at index 8 and so go on)
Something important here to address
Order of actions in which you save child vars
Needs to be the same as order in which you load them (not actions but Climb+Number) -
What i mean is if in save event 4th action was to add child to our array with object Z order
Then in load event it does not matter what will be position of Z order change
action but it does matter what number it have in SaveAllObjects[Cllimb+3] meaning it was 4th action when saving and now loading 4th child variable which index is 3
It could be 2nd or last action
But it would need always be +3 since it was 4th child we added
BUT 1st action always needs to be create object (like top most action)
So we are shoving in all other informations from variables to object that already exist -
OK and lastly we have here delete button
It is just delete action to delete all objects on scene which are in AllObjects group
And again i need to manually delete here HPBars
So now you can go to build mode paint something or in attack mode spawn slimes and delete them all at once if you don’t like their positions or whatever -
So now we can place some objects in build mode with LMB then change their opacity with Z or angle with X
Spawn some slimes in attack mode with RMB then damage them with LMB and click save button
Now delete button to remove them
Then we can click load button to load them and see how all attributes we wanted to save are saved and properly loaded -
I wonder what would happen if i would add save/load storage from previous part of this tutorial here?
Damn i think i did
-
Again gdevelop read stuff from top to bottom
So 1st we save our info to array then perform storage save
And in load we 1st load var from storage then load stuff from var -
And that is pretty much it for saving and loading all objects
Again does it still feel like black magic?
Let’s test it (Press MMB and use Save Load Del buttons)
Save Load Example | Play on gd.games -
Something to pay attention to
Look closely for what you are writing here and in which order
Like does some actions are not above others and it looks now different from my tutorial
Also does it is X pos then Y pos and not X and X pos two times
OR 1st Y pos then X pos
You think i am so smart? Yeah i am making this tutorial i for sure did to eat all brains and am so smart i could fart in frequency of PI number
Well let’s see how it went for me when i was doing this save all objects for the 1st time
[SOLVED] Save/load stuff from arrays while using child index -
We ALL make mistakes have no shame in it
We are here to learn something and its better to ask stupid questions than stay stupid (well did not work for me i am still stupid)
If it does not work seek help either here or in gdevelop discord help channel
Where most likely you just made some stupid mistake like i did
Saving timers between scenes
This will be ultra easy
Click here to learn how to save timers between scenes
It will work for any kind of timer
But just for this tutorial i went with countdown timer
We are counting from 100 to 0
-
I made global variable called it SaveTime and left it as number variable
-
In events this is all you need to count down running timer
-
We change text of our text object to
ToString(roundTo(abs(TimerElapsedTime("CountdownTimer")-0.01-100)-SaveTime,2))+" Change Scene ->"
-
Just to clarify while i am counting down to 0 if you would let timer run in elapsed time to just count time as it goes then you would + variable instead of - variable so it would look like
ToString(round(TimerElapsedTime("CountdownTimer")+SaveTime))
-
Where in counting down roundTo is rounding our number so we don’t get 99.0000000000
abs is Absolute number so even if its negative -Number it will display it without minus
TimerElapsedTime displays our timer
-0.01 will make it stop at 0 and not 0.01
-100 is from how much we are counting down so without abs we would go from -99 to -98 then -97 and so go on so again abs just removes -minus sign
-SaveTime so we are subtracting any possible value of our global variable from timer itself
And lastly ,2 is roundTo 2nd decimal digit so we are getting 0.00 not 0.000000000
And Change Scene → is there cause i was too lazy to make button for changing scene so i used text object as button -
Now when that text object is clicked we 1st save timer value to our
global variable and then we change scene -
And what we need in other scene for it to work?
Pretty much same thing
We just change scene back to our main scene here -
Where in both cases whole magic is that timer is untouched
We are only adding timer value to our global variable
And we are displaying value of our timer - our global variable -
Technically you could save this global variable to storage
And now you can save game progress mid mission/level while some timer is running -
Let’s see if it works (Press MMB to get to normal mode and follow instructions)
Save Load Example | Play on gd.games