DS Map Based Save System

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey game makers pixelated Pope here and today we are going to be talking about save data I know there are a lot of tutorials for how to use ini files out there but we are not going to be using them honestly I've never used an ini file and I don't really get the appeal for data that you don't want to be manually manipulated by users by the end of this tutorial I think you just might agree with me and if not at least you'll have another option for how to manage your saved data so let's get to it before we get started here's a brief overview of how this works for those of you who are unfamiliar a DS map is a data structure that uses key value pairs to store and retrieve data if you're unfamiliar with data structures in general I highly recommend you read the documentation on the topic or check out the myriad of tutorials out there I wrote one a couple years ago and I've put the link down below if you'd like to read it DS maps have built-in functions specifically for reading and writing to save files making them ideal for this so once you have all your saved data populated in a DS map it's as easy as calling the DS map secure function done data saved want it back in called DS map secure load it's really that easy and since DS maps are so freaking fast you can just leave your values in there and read and write to the map as needed while your game is running no need to pull all the values out and store them in individual variables to actually use them in your game so let's get into the code and really show off how simple versatile and fast this system can be so I have an extremely basic project here I have five rooms each containing three treasure chests I also have a game manager a persistent object that handles moving between rooms if I click on the treasure chest it opens and unleashes a shower of coins but if I leave the room and come back the chest is once again closed and can be opened again obviously that makes it way too easy for our players to firm treasure we're gonna set up a safe system that will make sure each treasure chest can only be opened once the entire system hinges on a DS map so let's go set that up in a create event of our game-manager object first we need to create our DS map just like creating an instance and you create a DS map you get an ID back and you need to store that ID in a variable so we can work with the data structure we've got the structure where we will save all savable data so let's go to our chest object and get it to save whether it's been opened or not open up the chest object and look at the create event in here we have a simple state engine and you can see that the chest can either be closed opening open or already opened let's look at the step event to see how we switch between these states so if the chest is closed we check to see if we've clicked on the chest if we have we move to state opening this is the ideal place for us to save that our chest has been opened you could wait until the coins are paid out or whatever makes sense for the object in your game but I'm going to add this line immediately after I change the state there are two scripts that add a value to a DS map DS map ad and DS map replace 99% of the time I use replace because if the value doesn't exist it will be added but if it does exist it will be replaced by the new value so there's almost no reason not to use replace over add it takes three arguments the ID for the DS map you want to change the key of the value you want to change and then the value you want to change it to our data structure is called save data and is contained in the object game manager and now it wants a key hmm so a DS map works sort of like an index at the front of a book you have the list of chapters and then the pages those chapters are on so if you want to know which page chapter 5 starts on you look down the list for chapter 5 and the index gives you the value 56 or whatever but we don't know what we are looking for right we have like 15 treasure chests and in a real game you'll have a lot more that you'll want to keep track of so do we go back to where we set up our data structure and give each chest a unique entry so we have a place to put the data no of course not that would be horrible instead we're going to write a script that will dynamically generate a key for any object we could possibly want to save in our entire game so let's do that create a new script and let's call it save data get key so how can one script generate a unique key for every single object in the game it's actually quite easy now you're free to change this formula all you want to make sure it's a hundred percent unique for your game but I think this will cover the vast majority of cases return room get name room + object get name object index + string X + string Y all this does is build a string because a key in a DES map can be either a number or a string and gives it back to whoever called the script for example if this left chest in room middle called the script we would get the string middle object chess 200-300 which is likely to be a hundred percent unique among all objects in our entire game back in the chess create event let's create a new variable and call it key and set it equal to save data get key and now we can plug that in as the second argument for our DS map replace back in our step event finally let's just set the value to true because the chest has been opened so we are now saving our state but that doesn't do us a lot of good if we don't react to it when the object is created so obviously back to the create event we need to check our save data and determine if the chest has already been opened if so we want to immediately go to the already open state but if it hasn't then it should default to the closed state so first we just need to pull that data out of the DS map once again using the key we got above so we have our data loaded into a variable let's change the state based on the value we found in the map in this case there are actually two possibilities for that value either that key doesn't exist in the DS map or the data stored in that key has the value true because we set it in the step event we need to handle both cases when you ask a DS map for a value from a key that doesn't exist it doesn't crash the game instead it will return the value undefined which is a special value in game maker usually found when dealing with pulling data out of data structures so this if statement is saying if we didn't get an undefined value that means there is data in the DS map for this chest so we just check if it's equal to true and if both of those checks pass we set the chest already open if either check is false then we set the chest to its default state of closed now that we are saving our chest state and reacting to it in the create event let's run the game and open some chests so I'm going to open a couple of chess switch rooms and switch back and the chests are still open that's cool but if we close the game and run it again the chests are all back to being closed so we really haven't saved anything in the traditional sense let's fix that we want to save our data to a file so we need a filename and a path to save this data to let's let the object game manager handle that open up the game managers create event you can give this file any name you want but it needs to be a string I'm going to call mine save data SAV and store it in a variable called file name this isn't just the file name for our saved data it's also the path to our saved data we're just going to drop it right in the sandbox the working directory for our game if you're unfamiliar with the details of filesystem i/o and sandboxing definitely read the documentation on the topic but for the sake of this tutorial this is all you really need to know and providing a more complicated path for our save file is completely unnecessary now let's create two new objects one that will save our game when clicked and one that will load it when clicked I've set both of them too persistent so that they come with us from room to room let's go drop an instance of each in room middle these objects are fairly simple let's start with saving as it doesn't make a lot of sense to try and load when we haven't saved anything yet add a mouse event for left pressed okay ready for this this is how you save your game with object game manager DS map secure save save data file name that's it your game is now saved ready to be loaded whenever you want loading is a bit more complicated though let's head over to object load let's add a mouse left button pressed event and again we're going to do this code with our object game manager since we were loading we want to first destroy our current saved data so we don't create a memory leak then load in the other data reusing our old saved data variable finally since we just loaded some data and in this game we are likely currently in a room with savable objects let's restart the room but we need to put a little safeguard in here what if that save file doesn't exist we obviously don't want to delete our current saved data nor do we want to restart the room if there is nothing to load we don't want to do any of this code so up above the line where we destroy our current saved data let's make sure the file we are loading actually exists so if our save file doesn't exist stop executing this code our current saved data will be retained and we won't go looking for a file that doesn't exist which would have crashed the game with everything in place let's run I'm going to open the middle box of each room then hit save close the game run it again and hit the load button and all middle chests are still open so real quick let's talk about a few interesting things that you can do with this system the key should always be generated in the create event if I were to move any of these chests somewhere else in the room editor and try and load my game they wouldn't load so as long as you don't move the object from its position in the room editor it will always work but that doesn't mean the object itself has to be a mobile after it's been created say you have a push block puzzle in one of your rooms and you want your player to be able to move blocks around but leave the room and come back to keep working on the puzzle then you'd want to save the X&Y positions for that block as well so you'd need two keys generated for the block that's super easy just add a unique suffix onto the end of the generated key and you can have as many keys as you want for a single object so if this treasure chest could move I would do this to get a key I could store its x and y values under then I would update those values in the save data map as the chests moved around finally when loading just like before if the value doesn't exist I leave it where I put it in the room editor but if the value does exist I set the x and y values equal to the saved values it is so simple and incredibly powerful so this all works really well for when you have doors or chests you want to remain open or enemies and bosses you want to remain dead but what about other things like how far the players progress through the story or what was the room they were in when they last saved we need a way to handle these non object based values fortunately it's really not too hard first we have to create a key for that value to be stored under in our save data open the object game manager and go to the create event right after we create the map let's just add a value to the map for our current room again I'm going to use DS map replace for this two things to note here first you'll notice the key I used is just a plain old string it's not some fancy generated key like we use for our objects it's an easy to remember normal string there's only ever going to be one current room so this is unique enough for this value second you'll notice that I don't just save the ID for the room I get the name of the room in a string format with the room get name function the reason for that as I've explained in other videos is that room IDs are not guaranteed to be permanent especially while you are still actively developing the game adding removing or reordering the rooms in your room list can completely change which IDs align with which rooms as each room will get an ID at runtime from the top of the list starting at 0 the names of your rooms are much less likely to change so it's a good idea when saving your room to use the name not the ID now we need to keep this value updated let's add a room start event to this object and drop some code in there and here we're just going to do the same thing we did in the create event every time we enter a new room replace the value in the map with our current room and we're done the code we wrote for saving will automatically work with this since we were simply changing the data in the map that we're already saving out to a file but once again loading is a tiny bit more complicated let's go over to object load and get that working so the file exists we've destroyed our old data and loaded in the previously saved data from the file now let's check the current room value and react accordingly you again we need to make sure that the value we got back is not undefined and then check whether or not we are already in the room we are supposed to be in if not go to the room saved in the data structure we just loaded a sec get index will find the ID of any asset in your tree if you give it a string for the name which is exactly what we have saved in our data finally if either we got an undefined value or we are already in the room we need to be in let's just restart the room so all the objects in the room reload properly let's run the game and see if it remembers where we last were so I'm going to go to the left room open up two boxes save then go to the far right room so what should happen is if we hit the load button we should be in the teal room with two boxes open and one closed and it worked let's close the game and run it again and this time hit load immediately right back in the till room with two boxes open and one closed you now have a very effective and easy to manage safe system so I just wanted to show off a little bit I actually designed this system while working on my zelda project that you've probably seen on my channel this is the script where I initialize the save data values that track links progress inventory and equipment let's look at how harp pieces work since they both control how much help link has and are controlled by an item pickup in the world let's look at the heart piece object itself in the create event you can see I have a tag which is my dynamically generated key as well as a key that's just the string heart pieces then right underneath I checked the data stored under the generated key to see if this object has been picked up if it has destroy the object immediately so it can't be picked up again now let's go look at the user event zero which is what I execute when link collides with an item so I use a custom script called save data add to increment the value stored under the given key which is heart pieces by one I then check to see if that increased my total number of heart pieces to 4 which means link gets a new heart container so I set the key back to zero since he no longer has any heart pieces and increment the heart containers key by one increasing links total health finally I set the value for the generated tag to 1 indicating this heart piece has been collected which will force it to destroy itself next time link enters the room where this heart container exists I recently got this project up and running on the latest version of GM studio so if you want to download the source and poke around in it there's a download link in the description but don't ask too many questions it's been like two years since I've really looked at the code and it's a real mess in there finally you'll notice as we've been going through the zelda project there are a lot of utility scripts for dealing with save data in the sample project for this tutorial which I've also linked in the description I've included a few of these types of scripts so if you get tired of typing DS map find value object game manager dot save data a blah blah blah creating your own scripts can really make things smoother so check those out and figure out the best way to adapt them for your game thanks for watching everyone I honestly can't say it enough I really appreciate everyone of you for being here it's been a lot of fun for me to watch my subscriber count rise by almost a hundred every week since I started doing this and I have you guys to thank for that I hope I can continue to put out content that you guys enjoy and find helpful if you found this video helpful be sure to hit that like button if you have any questions or suggestions for future tutorials leave them in the comment section below if you want to see something else right now check out my soon to be obsolete tutorial for animated tiles in game maker studio if the cryptic screenshots yo-yo has been posting to their Twitter the last couple of days or any indication it looks like this is natively supported in studio 2 but if you don't plan on upgrading immediately it could still be useful for you so check it out again thank you so much for watching now go make something awesome
Info
Channel: PixelatedPope
Views: 30,952
Rating: undefined out of 5
Keywords: Game Maker Studio, YoYo, GML, Tutorial, GM:S, Learn Gamemaker, Save Data, Data Structures, Saving, Loading
Id: bNsfbCDL2XA
Channel Id: undefined
Length: 18min 56sec (1136 seconds)
Published: Sun Oct 30 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.