Hello and welcome to another episode in the Godot basics tutorial series. In this episode we will be taking a look at saving and loading from a file. First we must learn what persistent data is now persistent. Data is data that doesn't change over time and change in memory. Most games have the intention of saving games state. For example your player's stats, perhaps Player Score, and even levels unlocked. Now there are two different types of persistent data.
We have local storage which is just basically saving to a physical device such as a computer or a tablet. And we have cloud storage which is just basically saving to a server. In this episode we will be looking at local storage. We will not be touching on cloud storage now when saving and loading data from a file. There's usually four steps and these first steps are common no matter what programming language you use whether it's GD script, C++ or even Java. You
You will adhere to basically four steps. The first step is you need to open a file. The second step is that you need to open up a file stream and file streams generally come in different types and we will look at that later. After you've opened up the file and you've opened up a file stream you are going to read and or write to your file and what you are able to do is dependent on these type of file stream you have open.
And then once you're done you're going to go ahead and you're going to close your file again these are four basic steps no matter the programming language. Now there are different string types. The first type is an input string. Now you use an input stream when you want to read from a file. The second type of stream is an output stream and you use an output stream when you want to write and or create a file. And lastly you do have an input output stream which just allows you to read write and or create a file.
Now the stream we choose determines how we're able to manipulate the file. For example if we open up an input stream we are not able to write to the file and if we create an output stream we are not able to read from a file. Again this is all dependent on the programming language and Godot has something similar before we can write or read to a file. We need to create an instance class object of the file class the file class inherits from reference and the file class handles the reading and writing of files.
Let's go ahead and take a look at how to write to a file in Godot. This is pseudocode. So first we need to create an instance object of the file class so file that new method. And over here we have a variable called Save File and that is our file class variable from our file class variable we use the open method and the open method takes in two arguments. The first argument is a file path in the string format. The second argument will take in an e new value that represents what type of file string we want and because we're saving a file we want to write to a file and so on one line of code we've already completed steps 1 and 2.
After that we would like to manipulate our data. Basically step 3 and so in this case we're going to use the store line method because we want to store our values line by line and then when we're done we're going to close our file. Keep in mind that when we use the file stream right we are going to replace an existing file if it already exists and we're going to create a new file. If it does not exist let's go ahead and see how to read from a file. What we want to do is again create a file class instance object using the new method.
So file that new from our class instance variable we want to use the open method. The first argument needs to be a string value that represents the path to the file followed by a comma followed by the read stream type. And so again in one line of code we are able to complete Steps 1 through to open a file declare a stream type and then we can manipulate our file. And so in this case because we're loading we just want to read and we're going to use the get as text method in this case because it's pseudocode.
We aren't really doing anything we're just converting the entire file into a string value. And then lastly we're going to close our file now in Godot. There is a way you should be saving your files and first line by line. What I mean by that is you have a variable you want to save your variable should be a dictionary. You take that dictionary and you convert it into a javascript object notation file also known as a JSON File and then from there you can use the store line method.
Now how should files be saved. Well let's take a look at pseudocode. We're using the for keyword which just means we're going to loop. In this case we have saved data in an array. Now again don't write your variables like this. This is just pseudocode and I'm just letting you know that we are looping an array and over here we have our already created file class instance objects save file and we're going to use the store line method. And over here we're going to use the 2 J song method provided to us by the Godot application and what it does is it takes any dictionary value so our saved data is a dictionary value and it will convert our dictionary value into a J some file format and that JSON File Format.
We're going to save line by line in our file. Now how should files be read. Well file should be read in line by line. As a matter of fact saving and reading line by line is common in many programming languages and in Godot we will be reading line by line and we will convert every single line into a dictionary value that will be stored in a variable. And so again we take JSON object we convert it to a dictionary variable and this is pseudocode again. But imagine we have our instance file class object called data file.
Well we're going to use get position which is at what position in the file are we at. We start at 0 which is the first line in our file and then as long as we are less than the length we're going to get our file or rather get the line so data file that get line and we're going to use the pass J some method. And that's going to convert our JSON File Format into a dictionary value that we can pass into a variable. So that would mean that our node data is in fact a dictionary.
Now one quick thing to mention is path strings so far in the Godot series we've only touched on resource paths and we use the R Yes keyword. Now the problem with this is that when a game is exported to a device the files become read only that means we cannot write to it. And so you may have no issues whatsoever. If you were to use the resource path string file when reading and writing in quotations persistent data. But once you export that into a game into a device you will no longer be able to write to it.
And so writing becomes useless you are unable to save to get around with this issue you need to use user path strings user path strings or similar to resource path strings and that instead of the arias yes keyword we use the user keyword and that will allow us to write our files onto the device or rather somewhere on the devices operating system in a folder most likely unreachable by the average user. Now if you want to debug what you're writing to a file keep in mind that the file paths in development is not the same as the file paths for production.
So if you're using Mac OS like myself your files will be saved in development under the following it will be under your user folder, followed by the library folder, followed by the application support folder, followed by the Godot folder, followed by app underscore user data, followed by the project name of your Godot project and then saved in that folder will be a list of files that you have saved. For Windows it will be similar using the Windows file path and for Linux it will be similar as well using the Linux file path.
Let's go ahead and take a quick look at some code. So over here we have our GD script file. Nothing special about it. It's just a simple reading and writing to a file but it will illustrate the point of what we need to do in order to read and react. Now first you do need a dictionary and so in this case we have our saved data dictionary variable which just has to information player name which is John Snow and location which is the north. Now we do need a path string. And so over here we have a variable name to hold that the variable name is save game file name.
It's a string data type and we're using the user keyword and we're going to save it to a player data that text file.
I have the ready virtual method and all it does is it's going to print to the screen the original data. So John Snow location the north we're going to load a data and then we're going to display on the console the newly created data. Now the data we're going to show if we saved correctly is that our player name is going to be called Godot and our location is gonna be called Tron City. Now let's go ahead and take a look at the save data method because that's how we're going to save our file.
So the save data doesn't do anything it doesn't return a value however we're going to the edit data method which just changes are dictionary value and then we're gonna go ahead and going to create a file class instance object called Safe fail safe file. We're going to use the open method. We're going to insert our user path followed by an enum that represents the file stream we want. In this case because we're saving and data we would like to write. And then lastly we're going to save line by line using these store underscore line method provided to us by the file class.
We're going to convert our dictionary into a JSON object. Using that to underscore JSON method and then it takes in an argument which should be a dictionary. And then lastly we're going to close our file now in this case. The saved data method will go ahead and create a file if it doesn't exist. And if a file does exists we're going to write over it. So keep that in mind. Now when exactly do we call these same data method.
Well a few places we should call these same data method is when we pause our game and when we quit our game
now we haven't talked about notifications yet but in this case we're going to save our file. When we quit our game. So as you can see here when our game quits we're going to call our notification.
And then when we notice that our game is ready to quit we're going to call the save data method. We're going to save our new file in our local storage system and then we're going to go ahead and quit the game. Now let's go ahead and take a look at that right now.
Now when we open our game it does nothing.
However we can see towards the console look that our original data is player named John Snow and location at the north end our altered data is John Snow followed by the North again because we didn't save our data and we didn't load data from a file remember our file does not exist at this point in time. And so we close and just keep in mind that now are safe file should have player name as Godot and location as Tron sit. So let me go ahead and open that file.
So as you can see here in our phone we have location Tron City player named Godot. One thing to keep in mind is that your dictionary when you transform it into a JSON File, your JSON File will in fact re organize the order of your data in alphabetical order. So notice how our safe data. It was player named first then location. However when we saved the data our location is first because alphabetically L comes before the letter P. So just something to keep in mind it should not matter when dealing with dictionaries.
Okay. So good. Now we see that our location and player name values have changed. They are no longer John Snow and the north they are Godot and Tron City. Now let's go ahead and take a look at how we load data. Now one thing to keep in mind is that loading data is tricky. And the reason for that is if our file doesn't exist and we try to load our file we are going to throw an error on top of that. Even if our file does exist when we try to load data from a file that is not fair we will throw an error and we'll take a look at that as we go through the code.
Now again our function load data will do exactly as the name implies we are going to load the dictionary JSON formatted file from the text file into our dictionary variable which again is called saved data. So first we need to create an instance object of the file class and the instance object variable is called data file. Now first we need to make sure that our file actually exists on the system. Now to make sure if a file does in fact exist we're just going to use a simple if statement if not keep in mind that the not keyword inverts are boolean value.
So again if not data file that file exists and we have to pass it in the user path file which again is inside our save game file name variable. And so in this case if our file doesn't exist we are going to exit our function and do absolutely nothing. That way we don't crash. If our file doesn't exist. However if our file exists we're going to continue on. And so since our file exists we're going to open that file. We're going to use the user file path followed by the read enum which just lets the application know that all we want to do is read from the file.
We don't want to erase it. We don't want to add onto it. And because we don't know how many lines we have in our file we would like to loop it. However because you and I both know that our file should only have one line The while loop is actually unnecessary. So now let's read from our file so you're gonna have a while loop. In this case our file instance object data file and we're gonna use the get position method in this case because we're starting the loop we're gonna start at zero. We're also going to make sure that we are less than the total length of our file.
In this case our data file that get linked should return back to us an integer value that represents how many letters. And this includes spaces as well. There are in the file. Now our variable node data is a value we're going to keep inside our while loop. So it should refresh every time we iterate through the while loop and then we're going to convert our JSON file into a dictionary object for our variable called node data using the pass underscore JSON method and inside we're going to grab the entire line.
And that's because every line in our file is basically our dictionary object. And so our dictionary object gets converted or excuse me our JSON value gets converted into a dictionary object that we pass into our node data variable and because we're still in the while loop we're gonna take that value or dictionary object and we're gonna grab its player name value and the player name value should be Godot. And so Godot is going to replace the current value in our saved data dictionary object which is John Snow right now but in this line of code it will be replaced with Godot and we're gonna do the same thing on the second line.
We take our node data dictionary object that we just created from our file and the location value should be Tron City and we're going to replace the current value of our safe data location which is the norm. Now when we jump up here we're going to iterate through a while loop again. And in this case position should be forty six. I'm not sure it should be a value greater than the total length because we only have one line in our file and get line users up the entire line. And so since we only have one file and I believe it's like 40 lines or excuse me 40 letters or get positions should also be around 40 letters and because 40 is not less than 40 we're going to kick out now.
This is where things get a little tricky and this is why I wanted the while loop because it's a good example. Now let's say we have more than one line then that one line. We have a different set of dictionary objects or maybe just like an integer value one on the second line. Well we're going to enter the while loop again. But when we reach here. Notice how there is no checks for what our object is. And so it's a good idea to have an if statement here that checks if our data object is infected. Dictionary and if in fact our dictionary happens to have a key called player name and a key called location.
Now I'm not going to show that in this episode because that's a little more advanced. I'm gonna show that in the next episode when we take a look at multiple objects being saved. So for now just keep that in mind. This load data is very basic very amateurish and that's because we don't have a way to make sure that the data we're grabbing is data we need because this line of code can throw an error if something changes to our file but nonetheless in our example it's not gonna throw an error as long as you don't change anything again I'm uploading this to get hub.
Now once we run everything we're going to close our file and then we're gonna exit load data. Now when we come back to the ready virtual method because we're running low data after we print to the screen original data we are in fact going to show a new file. So let's go ahead and take a look at that. So when we run our game if you look at the console log you're going to see our original data which is again the North and John Snow and it's being replaced by Tron City and Godot. Well that's all I have for you in this episode.
Thank you so much for joining me. In the next episode, ee'll be taking a look at a more advanced example of saving and loading a file in Godot. If you have any comments or questions please feel free to leave them in the comments section down below.
Thank you for subscribing and thank you for clicking the Like button. I look forward to seeing you in the next episode. Have an amazing day.