Hello and welcome to another episode in the Godot basics tutorial series. In this episode we will be taking a look at part two in saving and loading files in Godot. Let's go ahead and take a look at what we will be trying to say.
So here we just have a basic screen with 10 circles present. They all have the same radius color and different positions. And we also have a button towards the bottom center of our screen every time you press it or buttons change over. We have
We have an issue every time we decide to close it. Notice how our positions are not saved. So in this episode we're going to take a look at is how exactly do we save these circles. So every time we start the game they are present in the same positions that they were in when we previously closed them. Before
Before we get into that let's take a look at what we need to save at minimum.
So first we need to save our positions the positions of each circle. We need to save the script file path for each circle. We would like to save the names that each newly created circle instance object has. We would also like to save the group that these circles belong to. And we would also like to save the color and the size.
Notice how the color and size are gray it out even though we would like to save them now we're not going to implement a feature that takes advantage of these saved data. However we would like to save it because perhaps in the future we may want to add features that modify our circles color and size. And in this case size would be its radius. Now when we run our game right now as it currently is and we head over to the scene tab and we click the remote option.
Notice how we have our route viewport followed by our two nodes that are inside our seen circle manager and button. And
And notice how we have 10 circle instanced objects. Now these are instance objects that are created during runtime. Because if you check our local option notice how we only have two nodes on the scene
During editing.
We have the circle manager which is a Node 2D and a button which happens to be a button.
However when our game is running we are creating 10 circles that we display to the scene
and that is inside one of our scripts primarily our circle manager script when we want to change the position we're going to change its position through the circle manager script and each individual circle is created from a circle script.
And so we will be dealing with two different scripts. Again one script handles the position radius and color of the circle. And the other script the circle manager script handles changing each individual position.
And we would also like our circle manager to handle the saving and loading of our circle values. So every time we quit the game and we start the game again we can have our circles start at its last saved position.
Let's go ahead and take a look at that.
So here we have these circle script we extend from no 2D because no 2D inherits from a canvas item.
And we need canvas item in order to draw our circle and have access to the draw virtual method. We
We gave our circle script the class named circle. So we don't have to load it. Through its file path. We can just call circle dot new in these circle manager class. We have three variables.
The first variable is circle color. The second variable is circle radius. And the third variable is circle position. These are are three class properties. As you can see here keep in mind that are two properties circle color and. Circle radius. Have values initialized to them. And that's because we're not going to pass any values down from our circle manager. And so we would like to give it default values or our circles are consistent when they are created.
Our circle position doesn't have a default value set.
And that's because we are going to pass its value down from the parent node.
And so every time we create a circle we are going to pass down or rather initialize it with a vector to value that represents its position and in X and Y coordinate system.
Now to do that we need to declare and initialize virtual method and that's what we have right here. And it takes in a vector to data type as the first argument returns and void value which means we don't have to return anything.
And notice how we assign the past in value position into our circle position property.
And that is how we determine where we're going to position each individual circle.
And of course to draw or circle onto the screen we need to use the draw circle method provided to us by canvas item.
It takes in three arguments. The first is a positional value that is a vector to data type the next represents a radius which takes in a float.
And the last argument represents a color which takes any color data type.
And lastly we would like a function that our parent node can call upon in order to change the current position value for each individual circle. And we have the update position method for that.
It takes any vector to value representing the position in the x and y axis. And we just reassign that new past in data into our circle position property and we call the Update method which just basically forces our script to call the draw method updating the scene.
Now in the circle manager this is where the magic happens. This is where we create our circles and where we're going to add functionality to save and load our circles. And again it's similar to last episode in this case we have a variable called button node. And the reason we want that is because we would like to connect to it.
And as you can see here that is exactly what we're doing we are connecting our button Node 2 are update circle positions method.
We also have a variable that's going to handle our random number generator.
I'm going to introduce the concept of object pulling in this episode and we're going to use a variable for that again object pulling is just an array that stores in values in this case we're going to store in our circle objects.
And lastly we have a constant value called Total circles and that just determines how many circles we're going to create when we start the game in our ready virtual method. We're going to randomize are random floats random number generator.
Again we're going to connect the buttons pressed State to our update circle positions method. And right here you can see the magic happening for the creation of
Our circle objects.
And so we're using a simple for loop and we're gonna do several things The first is we're going to call the create random circle node method and we're going to assign its return value into a variable x. And once that variable X represents the circle class. Now I'm gonna go ahead and type that real quick so we can see what's going on. Now after we have our circle. Instance. Object we are going to give our instance object a name and this case it's just gonna be circle appended by an integer value representing the iteration in the for loop after we're going to push our circle object into the array.
In this case our race called Circle pool.
And lastly we're going to add our newly instance circle object on to the scene. Now
Now let's go ahead and take a look at the create random circle note. If you take a look at our create random circle note function what we're doing is we're creating a variable known to name because our circle script happens to be known 2D data type. In the next line. What we're doing
Is we're creating a new circle instance object and because it takes in one argument we're passing in a method which returns back a vector to data type and if we quickly look at that here it's just a simple randomize method that takes in a variable width which uses the rand f range and it takes in a variable height which takes in the rand f range and this just randomize is where we're going to position our circle node and return it back in the vector to format. And so when we come back here because we're passing any vector to data type into the new method what we're saying is create the circle and pass in a single vector to argument which is what our circle needs in order to instantiate.
And lastly when our circle node has successfully instantiated we're going to return it back. And of course when we return it back it gets stored in our temporary variable X and then it goes through the process of creating a name pushing it into the circle pool array and adding that circle object onto. The scene
Every time we click the button we're going to call this method here called update circle positions and all we do is we loop our array and we say that for every circle object in our array we're going to call its update position method and we're going to pass it in a new vector to data type and this is where we get our randomized circles. So
So if you take a look here every time we press change position. Notice our circles change. Now the issue here is that we're not saving. So I went ahead and created two functions called Safe circles and load circles. Now let's go ahead and take a look at saving and loading circles. Now let's go ahead and. Create our function that saves our circles every time we close. The game window. And remember we have four steps when we want to save
Or load from a file. First we need to create that file. And or open that file then we need to create some type of stream whether it's input or output or both.
Then we need to manipulate our data by either reading from the file and or writing to the file. And
And then lastly we need to close our file. And so let's go ahead and do that. We're gonna create our file variable so let's go ahead and do that we're going to create our file variable now once we've created our file variable what we're going to do is we're going to open it
And create some type of stream. And in this case we would like to save or. Write. To the file
Now once we've created our file and we've opened up our file and or created it. Let's go ahead and actually save data into our file. To do that we're just going to use a simple for loop and we're going to loop over our object pool variable which again is just an array and from here we're going to create our dictionary and the first value we're going to save is the position.
And here we're going to use the variable to string method and that is because our vector too is in fact a special data type that can't just be saved. And so we need to convert its variable data type into string format and to do that again we're going to use the word to string method. And from here we have the circle position which in fact is our stored vector two data type inside our circle object. Next we're going to save the color.
And again we're going to use the variable to string method because color is a special data type.
And from there we can save the name next by the way this is also the same as the following. After that.
Let's go ahead and save the radius. And lastly
We need to save the script.
The most important thing is the script because that's what we're going to need when we want to create newly instantiated game objects.
And as you can see here in order to get the file path of our script we need to use the get script method followed by the get path method that's provided to us by our circle instantiated object which again we are iterating through with the variable x. Once we've created our variable dictionary let's go ahead. And. Actually save that into our file
And once we've created that into our file we're going to iterate till we exit the for loop and from there we can close our file.
And that's basically it. Keep in mind that our safe circles method doesn't actually do anything. We do need to in fact call these same circles method in order to save it to the circles file that text file and since we didn't go over notifications I'm not going to do that in this episode.
I will copy and paste it but it's basically the same as the last episode when we received notifications we call the notification virtual method we take in an argument we have to check that that argument is equivalent to the notification value that we are seeking in this case. We would like the value that represents when the user has exited the game screen. And that would be the notification W M quit request provided to us by the main loop and from there we're gonna go ahead and save our circles or rather call our save circles method
Followed by quitting the actual game screen and when we press play and we change our positions magnificently.
Notice how when we play again it doesn't save the positions because we haven't created a load file method however.
Let's go ahead and quickly check if in fact we are saving positions.
Now we do in fact save our file as you can see here we're saving color or saving the name. Most importantly we are saving the position and notice here. How we have vector 2 followed by
Our x and y positional values. We are saving radius and most importantly we are saving the script path file in string format. Now let me go ahead and close this and we're gonna go ahead and create the load method.
Now when we load scripts it's gonna be in the similar format of saving in that we need to open a file. We need to figure out the stream followed by manipulation of data and then we need to close it or excuse me close the file.
So let's go ahead and do that. Now next this is very important. We need to make sure that our file does in fact exist because if it doesn't exist we need to exit out of our method or else when we try to open a file that does not exist.
We will be thrown an error
now over here you can see that we're passing in a string value representing the path file which is called Circles file that texts and if it in fact does not exist with the not keyword we're going to exit out of our load circles method.
Now everything else will be the same or rather similar.
We're going to actually open the file and then we're going to iterate the file grabbing the necessary information and then we're going to exit the load circles method after we close our open file and let's go ahead and do that
next we're going to iterate. And so let's make sure that we use the while loop because we do not know. How long our file is
But we're making sure as if our get position or rather our current position is less than the total amount of lines or excuse me characters that are file has we're gonna continue to iterate.
Next we're going to iterate our file line by line and passing that line and converting it from Jason format into something usable. Basically a dictionary
and from there we are now able to create our circles
and that's basically it. We went ahead and we created our load circles. Now we need to make sure that we do in fact call it. When. We. Start the game. So I'm gonna go ahead copy our function. I'm gonna go ahead and add it into our ready virtual method and I'm gonna do some cleanup I'm basically going to get rid of our for loop add that into a function and add it here in the not open file statement check. Because if our file does not in fact exist we would like to go ahead and call it
But for simplicity's sake I'm just going to go ahead and I'm just gonna leave this code here but I'm gonna clean it up before I upload this to get help for you to see him play around with. Now if we play I got an error cannot convert string to Vega I know why
Cats right here so string to var which was the second method I was showing you in the slide show that but now that we fix that and we press play.
Notice how we have one two three four towards the top right corner of our game screen and if we exit and we press play again.
Notice how they are in fact staying in the same positions that they were in when we exited and if we change position.
Notice how there's only one at the top right.
And if we go ahead and press play. Notice how it's still at the top right. And so now we know that our saving and loading of values works in our script. Now let's go ahead and see what I did in the while loop.
So we are all on the same page now.
Again when we enter the load circles from the ready function we're gonna open up a new file.
And if that file doesn't exist we're gonna go ahead and we're going to create our own circles. However if a file does in fact exist we're not going to create our own circles from scratch anymore.
What we're going to do is we're going to read from the file and then in good faith and I say good faith because we're assuming that our file is not empty.
We're gonna go ahead and run the while loop we're going to convert our J son file or excuse me the Jason format that was saved and we're gonna pass it into something readable that we can pass into our dictionary variable called data. And notice how we're just opening our file we're reading line by line we're passing the Jason into a format that we can take in into our variable data which in fact is a dictionary data type and now our data can be used.
Like you what a dictionary data type.
We create our variable called Circle load and it is a reference. It's a reference because what we're going to do is we're going to load our script which again is a file path to our circle script. And so our circle load X to the prelude of a class instantiation because with the circle load as a reference to the script we can use the new method and it takes in one argument which is a vector to data type. Now it through the error because I just gave it the value in the dictionary called position and keep in mind that the position value although it has the correct format vector 2 followed by the x and y position values it was in a string format remember we converted from variable to string and now we need to convert from string to variable and so with the string to variable method
We go ahead we call that and we run this line successfully no errors thrown.
And then next we would like to give back our circle objects the name that was saved. And so we go ahead and do that with the set name method followed by the dictionary key name. Which has the value. Of the actual name in the file we call the ADD child because we would like to add the child onto the script and our instantiated object is circle object
Variable so keep that in mind. And then after we want the circle pool
Array to contain or circle objects and so we use the push back method and we pass it in our circle object and when we're done iterating we close our file and that's basically it. I'm going to upload this onto get up not this exact file I'm gonna do some modification because for example there's gonna be an error thrown in this while loop if the link. Now I'm gonna upload this file to get hub I'm gonna modify it a little bit because I notice here in the while loop we do in fact we'll throw an error because when we try to create our circles we are under the assumption that even though the file exists it still contains something.
And so in that case I'm just going to make sure to check that we are not opening an empty file.
So look for that and the uploaded get Hub project I'm gonna do that.
Off screen thank you for clicking the Like button and thank you for clicking the Subscribe button if you have any questions or comments please feel free to leave them in the comments section down below.
I look forward to seeing you in the next episode.
Have an amazing day.