If you want your game to remember important
information between play sessions, such as what levels your player has completed, their
maximum health, damage they can deal, or even treasures they’ve collected. Then we’re going to need to save some data. Howdy, and welcome to the Game Endeavor. If you want to learn more practical dev skills
and improve the quality of your games, then subscribe and ding-a-ling that bell. If you’ve never tried to save data before,
then this topic might seem a little intimidating at first, but it’s a lot easier than you
might think. Godot makes this very simple by providing
us with several easy and convenient ways of managing this. For this example I’ll be demonstrating how
to create binary save files that your player will not easily be able to break into and
modify. Let’s get started. I have a scene prepared here for demonstrating
the process of saving and loading data. This scene is very simple with two buttons
that I’ll use to save and load respectively, and a text box for displaying information
to you. If I click on the buttons, then they will
print out to your text box the words “saved” and “loaded”, which don’t get too excited
because it’s a lie. They’re not doing anything at the moment,
this is just to demonstrate that the buttons are functioning properly. If we open the script to the scene then you’ll
see it’s just the two methods for the buttons among other non-important things. The purpose of saving data is to store information
on the user’s machine that we can access at a later date. To do this, we’re going to need to know
where we want to save our data. Thankfully Godot makes this easy for us as
well, by providing us with a nice and cozy little folder where we can store whatever
we want, known as the “user://” directory. To easily find this, you can go into the Project
tab and click `Open Project Data Folder`. You may need to run the game at least once
for this folder to be generated. This folder is yours and you can stick whatever
you want in here. Notice the pathing to the folder. Godot crams your little folder in with all
of the other little projects that you’ve ran previously on your machine. Users will be able to see this directory path
on their machine as well, so if you want to seem a little more sophisticated, then you
can tell Godot that you want one of the private folders in the back. Go into Project Settings, under the config
tab, and enable `Use Custom User Dir`. You’ll need to run your game so that Godot
sets up the directory, but once you’ve done that, you’ll find that you have your own
special directory path. This is completely optional though, and will
not affect anything in this tutorial. To demonstrate saving data, we’re going
to need some data to save. So right quick I’m going to create a dictionary
and stuff it with some arbitrary information. You can store whatever you like here, even
more dictionaries. This is useful if you want to store things
like the player’s data in one dictionary, world data in another, levels completed, collectables
collected, and so on. This doesn’t have to be a dictionary though,
I just find that it’s a lot easier to manage, especially with larger save files. But note that it is not the most optimized
way to save data because the keys will get saved in this file as well. In order to store file data, we’re going
to need to create a File reference. This is what’s going to do all of the work
for us. We’ll create it by saying `var file = File.new()`. We then need to open a file for us to write
to, which we’re going to do by calling the method `file.open()`. This method will need two parameters. The first parameter is a string to the path
that we want to open, which I’m going to create a class property for called save_path
and set it to “user://save.dat”. We can then pass in `save_path` as the first
parameter for our open method. We’re going to be telling Godot to write
to this file. Because of this, Godot will go ahead and create
the file for us, so it doesn’t need to exist already. The directory however does need to exist,
so for now we’re going to save it directly in the user directory. Later on in this tutorial I will show you
how to create your own directories. The second parameter is binary flags that
tell Godot what we want to do with the file, the options being reading, writing, reading
and writing, or writing and reading. The difference between the latter two being
whether or not Godot creates the file for you. We’ll be using the flag `File.WRITE` because
we want to save data to the file, we have no interest in reading it. We’ll read the data later on when the player
chooses to load their game. After opening a file and reading or writing
to it, we will need to tell the engine to close it so that it can flush buffers, sprinkle
magic engine dust everywhere, among other fancy things. I never trust myself to remember to do this,
even in a scripted tutorial, so I’m going to go ahead and call my `file.close()` method
now and get it out of the way. With that crisis averted, we can focus on
saving our data, which is as simple as saying `file.store_var(data)`. data is the dictionary that I created earlier
with everything that I wanted to save. This is pretty painless so far. There are other methods for saving data. For example you could save 8, 16, 32, and
64 bit integers, floats, doubles, strings, variable types of variables, truly an array
of things. But in my opinion, it’s convenient to store
your things into dictionaries or arrays. If you write multiple things to the file then
they will be saved in that order, and will need to be read in the same order that they
were written. Our setup here assumes that the file opened
without issues. This may not always be the case however, any
number of things could go wrong while trying to open a file. The file’s open method will return an error
code to inform us of how it went. You can look at Godot’s documentation to
find the various error codes that you could get, if you want to try and collect them all. I’ve put a link in the description should
you wish to learn more. We’re going to store our error code in a
variable named `error`. We can then check to see if `error == OK`
before continuing with our file handling. You’ll probably want to have an else condition
here as well that handles what happens in case of an error. Such as letting your user know that something
went wrong and booting them back to the previous menu. Saving data is fantastic, but completely useless
unless we can also load the data back in as well, so go ahead and work on that. Inside of our loading method, we need to create
the file reference again, which will be what handles the file manipulation. When loading a file, we need to make sure
that the file exists by creating the condition `if file.file_exists(save_path)`, save_path
referring to the string variable that we created when saving our data. We’re going to again open our file by saying
`var error = file.open(save_path`, but this time using `File.READ` as our flag, so Godot
knows that we want to read in data from the file. `if error == OK` then we know that the file
loaded without any issues, so we’re good to start reading in data. Again I like to close my file before I get
started. And then loading our data is as simple as
saying `var player_data = file.get_var()`. This will load the entire dictionary that
we created when saving the game and store it into a variable, which means that accessing
this data is as simple as accessing the keys as you would in any other dictionary. This is the basics of saving and loading binary
data, but there are a few more tricks that we can use to improve the functionality of
our saving system. For example, just because you have your own
little directory, doesn’t mean you want to cram each and every file into it. You may be storing multiple things here such
as your save files, screenshots, bank account details. Throwing all of these into one folder can
be quite messy. We can create our own directories to keep
things nice and tidy. We’ll do this in our save method by saying
`var dir = Directory.new()`. Much like the file reference, this will be
what manages the directory for us. I’m going to create a constant string that
will store the directory path by saying `const SAVE_DIR = “user://saves/`. Making sure to add the forward slash at the
end, it’s rather important. We then need to insert this constant into
our save_path by adding it before our save file. Back in the save method, we’ll then check
to see if the directory does not exist by saying `if !dir.dir_exists(SAVE_DIR):`. If it does not exist, then we want to create
it by saying `dir.make_dir_recursive(SAVE_DIR)`. The recursive bit of this method means that
it will make every folder along the path if needed. For example if you were to create individual
character directories inside of your save directory. If you’re confident that you’re only creating
one folder, then feel free to simply use `make_dir` instead. Something we need to take a quick look at
is how the data is being saved. If we open up our save file into a text editor,
then most of it is not going to be shown to us properly. That’s because text editors are meant for
displaying text characters, but our file has integers, floats, and other nonsense that
isn’t limited to text characters. Instead, to get a better look at our file,
we should open it inside of a hex editor. I will be using the free software HxD. HxD will display the file’s contents to
us in various ways. On the left column we have the hexadecimal
representation of our file, which is just a more human readable form of binary. And on the right column it will have the text
value for us. In the data inspector on the far right, we
can select values in our data file and see it converted in the inspector. If I were to select this value here, which
is where I have saved my max_health value as 6. I can change this value to whatever I want,
along with any other value exposed to me in this file. When I load the file in my game and print
its values, my character’s max health will have been changed as a result. This means that the player will easily be
able to open up this save file and manipulate their values however they want. Whether or not you want to allow this is up
to you. But let us assume that you’d rather not
have anyone digging around in here. We can encrypt this file so that it’s not
so easy to manipulate. Back in our Godot editor, this is as simple
as opening our file as encrypted by changing the `open()` method to `open_encrypted_with_pass`. This method requires a third parameter however,
that being the password to encrypt the file with. This is just a string value and can be whatever
you want to set it to. You will need to do this for loading the file
as well. Now after saving this file again, you’ll
see that the values are a jumbled mess that won’t be easy for someone to manipulate. If you want to continue learning practical
dev skills, then watch this video on how to create a simple yet flexible state machine
in your Godot games. And if you’re new, then join the sub-club
to get notified for future videos.