Advanced Saving in Unity - Part 1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys before we get started I wanted to tell you about all of the cool courses I've worked on over the last year or so I've done a complete uni 101 course for complete beginners I've also covered how to create various RPG systems like inventory and crafting questing and turn-based battling and we also recreate some cool classic games such as Mario Bros and Missile Command if any of this sounds like fun to you find the links in the description below and be sure to use the coupon code AG 39 QZ to save 15% on any course your purchase alright so first of all let's talk about the problem that we are going to try to solve and then we'll get into the solution or at least a solution for that problem so what I'm gonna do is roll around my little game here and I'm going to collect these items that I have lying about it's gonna add these items to an inventory list that I'm just playing in the UI here and it's going to destroy the world item of that object after it adds it to my inventory and what I want to be able to do is save my inventory list and then whenever I load the game again later I will have the same items very straightforward it would seem but also a huge requirement for any kind of game right saving progress but there's a bunch of different types of stuff that we have to save to actually save the progress for our player you just think about over the position of the player or the level of the player the lives the player has left but then you have to think about progression things like stats unlocked areas discovered recipes whatever you have like that and these were all just lists of things right pretty straightforward but then also think about well this item was just collected from my world and added to my players inventory if I save my players inventory and I come back in here look I have all four of my items but these items will still be in the game worlds we have to have a way to save the state of those items in the game world so they do not get spawned in if I have already collected them and the way we're going to do that is we're going to keep a collection based on a unique ID for every item in our game world and at the start of each scene we're going to check to see this item been collected if it has do not let it instantiate do not let it spawn or if it is spawned destroy it whatever we have to do but if it hasn't been collected then let it come in the game as you would expect let the player collect it and then add it to that collection so that we know next time and then all we have to do is save that single collection and load that single collection and all of our scenes will have non collected items be available and already collected items be unavailable now obviously this is a huge requirement for an RPG with loot or for just any game with collectibles but this will also teach you how to save a lot of different types of data because the serialize err that we're going to use doesn't really care what it is it's very good at serializing anything as long as it is serializable pretty straightforward that is pumped my Mike pretty straightforward so let's go ahead and get into this so we can see what we have to do now I already have a bit of a game here but the stuff that I already have doesn't really matter I have a ball I can roll around to my little scene I have a portal system I have collectable items and a basic inventory system with some events in between so I have if I collect an item at update the UI through an action an event very basic stuff there but it's also not important for this just want you to understand where we are now this project is available link in the description below if you want to go ahead and grab this projects and follow along or at least have the same base that will be great so what I want to do first of all is I want to go and start creating our save system now this safe system is something that is available it hasn't been available for a while now on my github page but it's just something that I made looks like a year ago and was planning on doing a lesson on this exact thing then but work got in the way big time and that's where I've been if you've if you've been wondering the the first 30 seconds of this video probably give you a hint but it's all here and what I'm gonna teach you is not how to use it but also how to make it not just how to use it but also how to make it so what I'm gonna do then is we're gonna write that on our own here I want to go to save load I have a folder I want to create and you see sharp script you know call it save load name yours whatever you'd like I could not come up with a name that made sense for saving and loading in my instance so this is where I'm at and I want to show you really quick the unique ID all this does is just creates a string with some properties that would be something that would make it easy to identify this item so the position square magnitude which unless you have the same coordinates or like 1 0 and 0 1 then they're not gonna be the same but if that's the case then we also have a name tacked on to that and then we also get the sibling index just because it's another value but we could do seeing index maybe so this one's specific to this scene that one's specific to that scene whatever you want to do but what we do there and then our collectable item set is just a hash set a string hash set and the reason we're using hash sets is because all we care about is whether an item exists in that set or not in that collection or not and a hash set is the best way to do that because it doesn't care about anything else other than does it exists and can I get our reference to it if it does exist ok so in our save load class we're going to start writing the actual system to save and load our data get rid of these default methods and I'm going to create a static system so we can access it with just a simple class of reference so we're just gonna have public static void it's going to turn nothing because this is going to be the save method we're going to use a generic method for this in fact the entire system is going to be generic so that means we have to take in a type of T so we can define the type whenever we call it that way it'll know oh I'm working with this type so we can save any type of object that is serializable by just saying this is an item or this is a tooltip' or whatever you want to say those are all valid as long as they can be sterilized and then the first parameter McClintock is going to be of that time because it's going to be the object we want to save so object to save the second parameter would just be a key you could reverse these if you want but I like to have my key after the actual object I'm saving for absolutely no reason so now let's construct our path it's simply going to be the application persistent data path which is going to be a folder or directory on any of the platforms that we can build for that will allow us to store files persistently between game loads we're going to take that persistent data path and we're going to add to it just the folder that we're gonna create I'm just gonna call it saves now inside of this is where we're gonna have our save files but for now all I care about is this path and what I want to do we're gonna work with files and directories now so let's go ahead and grab that name space system dot IO input alpha it allows us to do directories and file work which we have to do but first of all create a new directory if it doesn't exist if it does exist this won't do anything I want to create that directory at that path so we have that saves folder and now what I want to do is I'm going to create that binary formatter that we're going to use to serialize our data now there is a ton of different sterilizers we can use for this we could sterilize it to XML or JSON JSON being my favorites and those are more human readable formats that we could actually serialize to view it in a text file make edits in the text file and then whenever I load the game in again we will have those changes made so we can actually edit the game values without editing the actual game itself which is pretty cool and really the strength of something like Jason but in our case we're going to be using binary which is not human readable it's a bit more difficult to tinker with which is also a good thing if you don't want people to tinker with your values on your data in my case I like that so I can use Jason but I understand making a little more difficult may be best so what we're going to do is create a binary format err and the way we have to do that in fact is we have to go through the the serialization namespace certain let's say using system runtime da serialization and also using system runtime da serialization dot formatter and the one we're looking for is binary a lot going on there but just makes it a bit easier for us to handle all of this so I'm gonna create a binary format err I don't want to call it formatter and we're gonna construct a new binary formatter nothing fancy going on there and now our formatter is going to take whatever object we're trying to save and it's going to serialize or deserialize it into binary or into whatever object we're trying to get back but we also have to have a file stream that we can take that formatted data and use it to write it to a file or read it from a file or whatever we have to do so we're going to create a file stream to do that now there's a couple ways we can do this the easiest being using a using statement which is simply just using resource now the reason you want to use this is because once you are done using the file stream or really any stream or any resource in general you have to dispose of it you have to say I am done with this I no longer need this to be open I want you to close it and I want you to dispose of it and release it from memory what I want to do is inside my using statement I'll say use a file stream and I was call it file stream it was create a new file stream now this is a resource declaration that we've made inside the using state but that's completely fine that's how we're supposed to do it because now this knows okay well everything inside of my block within my scope once I am done with that I will take this resource that they declared for me and I will dispose of it but until then I will use it for the things that are defined within my scope so what I will then do is take for matter and serialize data to that file stream but clearly we have to fail some stuff before file stream first so file stream needs a path where is the stream where is the file we need a path and I also want to pass in the key for so the name of the file that we're looking for so we go to persistent data path saves slash name a file and then we have to have that file extension which in my case simply gonna be a text file you could do whatever you wanted to hear but I when he's a text file and then we have to give a file mode all you want to do is simply create the file just keep it very simple and say file mode don't create now if i zoom out of here to get just another look at what's going on this is what we have so then all I have to do is take that file straight but look at the serial Iser here it's looking for a stream that it's going to serialize this data to but also the object that it's going to serialize so the stream I want to use is file stream the one we just created and then the object I want to save now this says object graph so the cool thing about the binary for matter about formatting things in binary serializing objects to binary is that it doesn't just serialize the object you passed in it will serialize the entire graph of that object as long as it can so what you do is you pass in the route object the route of the graph say this object but then it's object inherits from this object which implements this interface which does all this cool stuff it can just keep going down the graph until it finds the end point which is exactly what we want to do you can save an entire game object in that way as long as you serialize the data properly you can save the entire state of it which is pretty cool so I want to take the object we want to save and pass that in as the second parameter and that's all we have to do to save now we have to load so I'm going to do to make this a little more easy for us a little easier they'll just take that copy and paste it now one changed this to load the return type is going to be the type of object that we are trying to save or trying to load in fact and we do not need the object itself we just need the key we just need to know what file we're looking for well the same path the directory we do not care about creating it we want the same formatter to be created or at least an instance of the formatter to be created we're going to use the file stream the same way so all this makes sense but I want to change the file mode from create to open I want to open an existing file to read the data that file has and what I want to do for this is I want to create a variable of type whatever type this is so whatever type I defined whenever I call this the generic type I want to create a variable called return value and what I'm going to do is set this to be the default value of that type and in fact I can explicitly say of whatever generic type that we're looking at here and the reason that is is because if we do not find a file that has data in it for this load then just give them the default for that type so if it was an INT give them 0 if it was a string give them a null if it's a float to give them the 0 and there's all kinds of different default types like that but we could talk about but we want to make sure that if we do not find that then give them default value but if we do find the value we want to give them that value so what I'll do is I'll say return value inside of our using statement here is equal to formatter then I simply want to deserialize now I'm taking already serialized data and I'm deserializing it back into whatever object it was before and all we have to do for this is taking the file stream because that has the path and the name and the mode that we're opening with and all that fun stuff what this is going to do now is say we cannot convert object to type T so this returns just an object which is good that means it can return pretty much anything but it's not nearly as type safe and you're going you can run into more errors more issues if you rely on object in place of a generic so what I want to do here is just cast this to whatever type that we're loading just like that so it'll just say oh the return value is of type T as well now whatever we do serialize we will construct it into that type and we will set it to be equal to or set return value to be equal to that result so now return value if I'm loading a list of items will be a list of items and this will be a null list then all I have to do is once I'm done return the returned value if found that file with save data it'll be whatever we're looking for if it did not it'll be the default of that value type now there's one more thing or at least two more things I could think of that we're gonna need for this the first thing we wanna be able to check if a save already exists for an object or for a key so that we can see do I have an inventory to load does it exist should I try to load it that way we don't run into errors of of trying to load a file that doesn't exist so I'll create a public static it's gonna return a boolean so bool I'm gonna call it save exists and this method is gonna take in is gonna be a key and now we're gonna do is it going to again take that path will take the path construct it once again here but this time I'll just throw on the rest of this we could probably just create a formatted string for this but this will be okay for now text that's the entire file that I'm looking for with the path on it as well so what I can do then is return the result of file 'don't exists which is gonna be true if the file looking for exists and false if it does not at whatever path I pass in so if that exists we know hey I won't try to load that file if it doesn't exist then I'm not going to load that file and the last thing I want for the save system itself another static void this time and this is going to be a way to delete all save progress which is not something you want to be careless with but for the testing it's fine I'm just gonna do a seriously delete all save files and again we'll just do the path now this could be a constant somewhere it's because this is not going to change I don't have that set up for this to work like that but you could do that if you wanted to be pretty simple to do what I want to do is convert that path to a directory or to a directory info object directory info I'll call it directory create a new directory info object this is gonna give us the ability to simply delete the directory itself and the reason we want to do that we could delete each individual file recursively we'll go through and say how many files do we have OOP there's one delete it oh there's one delete it but what I would instead like to do is just delete the entire directory that these safe files are in and then create the directory again now you wouldn't want to do this if you were if you had an actual game where you add multiple characters say files you don't delete the entire character directory instead of the entire save directory so keep that in mind if you wanted to do something like that but in this case it'll work just fine so directory dot delete there we go and then just create that directory once again create directory at that path and there we go so that is our safe system ready to go so all we have to do now is start using it and there's a lot we could do with this so what we're going to do first of all is we're going to save our inventory list
Info
Channel: GameGrind
Views: 42,155
Rating: undefined out of 5
Keywords: saving in unity, how to save in unity, advanced saving, unity saving data, unity serializing data, writing data to file, binary formatter, c#, game dev, game development, gamegrind, game grind, saving collection, saving list, gamegrind rpg, unity 3d, unity saving, unity tutorial
Id: Rgxbl5uIKO0
Channel Id: undefined
Length: 18min 29sec (1109 seconds)
Published: Wed May 08 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.