Unity3D - Saving and Loading your Inventory with Scriptable Objects | Part 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome back to coding with unity today we'll be extending our inventory system from the last video to allow for saving and loading now since our inventory is a scriptable object and our items are also scriptable objects we can't simply convert our inventory scriptable object to a json and save it we're actually going to have to create a database to hold our items so that we can serialize the scriptable object of our item back into our inventory when it goes to repopulate the scriptable object now that sounds pretty complicated but it's actually pretty easy and sure it would be nice to not have to do this if unity just Auto populated the scriptable object back into another scriptable object but the instance ID of your scriptable object that's saved inside of another scriptable object changes so when it goes to load in the value that is saved for that slot in your inventory it's unable to find the object that saved there so that's why we'll be creating the database so let's go into our item scripts folder and we'll create another script inside of here and call it item database object once you create that object go ahead and open it up in your IDE now the database that holds our items is also going to be a scriptable object the reason we're using a scriptable object for this is so that we don't have to drag and drop an item database into every single scene that we want to have our game in instead we can just reference the database that lives within our project so the first thing we'll want to do is get rid of where it says monobehaviour and replace it with scriptable object now we can get rid of the start and update functions and inside of here we'll save public item object make it an array and call it items this will be an array of all the items that exist within our game now let's also make a dictionary so that we can import an item and easily return the ID of that item so we'll say public dictionary the dictionary is going to use an item object as the key and the value will be an int this way we can put in an object into our dictionary and who returned the ID that that item is supposed to be we'll call it get ID and now since unity doesn't serialize dictionaries we're gonna use a little callback function to create the dictionary so after your scriptable object put a comma and then we'll type i serialization callback receiver and then we're gonna hover over it and click show potential fixes implement interfaces get rid of these throw new systems not implemented exceptions and what this is is that these are functions that you can put code into fire before and after unity serializes the object so we're not going to be using on before serialize for this we'll just be using on after deserialize and what we're gonna do will say get ID equals new dictionary this clears our dictionary out to make sure that we're not duplicating anything now we're going to loop through all of our items and we'll say get ID dot add items I and the ID for that item will be I excellent now every time unity C realises the scriptable object it'll automatically populate the dictionary with reference values based off the items array that we created in the editor now that we have our item database object created we need a way to actually create it inside of the editor so let's go above the public class and create a create asset menu and we'll say file name is equal to new item database then we'll say menu name is equal to inventory system slash items slash database excellent now let's go back into unity and we're gonna create a new item database scriptable object inside of your items folder right click create inventory system items database and we'll just call it database now you can see we have our database which has a list of items on it so let's go ahead and populate it with all of the items that we currently have in our game the easiest way to do this is if you click on your database object and click this little lock button it'll keep your inspector from changing then you can highlight all of your items drag and drop it straight into the items array I can unlock the window if you want to now that we have our database made and the items setup on it let's go back into our IDE and let's go to the inventory object script now we need to make a variable for placing the database object so we'll say public item database object database and then one quick thing we're gonna change is this pool has item and if has item we can actually clean this up and make it a little easier I noticed this from a comment that was left on my previous video so we can get rid of where it says if has item get rid of the bull has item get rid of has item is equal to true and replace break with return so what this is doing is it saying we're gonna loop through all of the items in our container if the item is equal equal to the item we increase the amount in return don't play any more code but if we do not find an item that is currently inside of the inventory we'll create a new item that's just a simpler way of doing it compared to the extra variable that I had before but moving on now that we have our database add it as a public variable let's do something with it so on the Container dot add new inventory slot we're going to push the ID of that item into the inventory so the first thing we're going to do is go into the inventory slot class and we're gonna create a new variable here called public int ID now inside of our constructor we're gonna say int underscore ID and then we're gonna set the ID when it's created by saying ID is equal to underscore ID now right here we need to put the ID of the object and the easiest way to get the ID of the object is by saying database dot get ID and the item ID we want is underscore item excellent now when we add a new item to our inventory we'll use the databases get item to pull the item ID and popular into our inventory slot so how we're going to solve unity not Ricci realizing the scriptable object into our inventory scriptable objects slot which for reference is here so if we go to our inventory and look at our inventory and create a new item say we have an item ID of 1 which I believe was monkfish and we have five of them if we serialize this out to a file and save it it's going to put a ID equals one item equals it's not gonna say monkfish scriptable object it's gonna be a string of numbers that references the instance ID of that scriptable object and the amount will say five then when we go to load that it's going to use the instant ID of this scriptable object to try to find that object but it's not going to be able to so we're gonna use this ID in our item database to repopulate this and how we're going to repopulate it is if we go back into our IDE we're gonna make unity automatically repopulate it based off our database after it serializes the object so after scriptable object put a comma and type i serialization callback receiver add in the two functions that it requires again we will not be using on before we'll only be using on after and inside of here let's do a for loop through all of the items inside of our container and then we'll say container I died item is equal to database die now you'll see that we only have a GUID ID which requires us to put the item in and retrieve an ID but we need to put the ID in and retrieve an item to repopulate the missing field that was removed during serialization so let's go back into our item database object and we could do a double for loop to search through the items inside of our database but when you have a few thousand objects that can be pretty performant heavy so what we're gonna do is use two dictionaries now what we're actually doing is making a trade off but performance and memory since we're gonna have two dictionaries our memory is technically going to be doubled so it's your call on if you want the performance versus the memory and it may be more the development of your games call more than your call but for now until we have an issue with how this is working we're gonna use a double dictionary so just go ahead and copy your dictionary and we're just gonna replace item object and int to say int and item object that way we can use the int as the key and return the item object as the value and we're gonna rename this to say get item now we need to copy and paste this say get item and change this to say int item object so we're creating a new get item dictionary to make sure we're not double populating anything then we need to add it to the dictionary so we'll say get item dot add and instead of items I I will say I comma items I now we have both of our dictionaries set up let's go back into our inventory object and we'll say database dot get item and we'll pass in the ID which is stored under container i dot ID which we populated when the item was added to the inventory and since there's only one line in this for loop we can actually get rid of these brackets so how we have this coded is as soon as anything changes on our scriptable object that causes unity to need to serialize that object we're just going to go ahead and look through all of the items in our container and repopulate the items slide to make sure it's the same item that matches with the items ID so let's go back into unity and after it compiles if we change our item ID it should automatically change the item inside of the scriptable object item variable so we'll change it to a two and we're getting an error the reason we're getting in error is because we didn't set the database yet after we set the database you'll see it automatically changed to a sword we'll put it back to one it's a shield so I guess one wasn't a monkfish it was a shield two is a sword three is sword one sword two bones let's go look at our database and see what it is monkfish is zero and then we work out from shield sword so we can go back to our inventory and make sure that's correct we'll put the item idea to zero and you'll see it says monkfish one shield and you'll see it's automatically populating all the way up to our is it six items or five items go back to our database we have 0 1 2 3 4 and 5 so it's 5 items and the fifth one is bones so we'll put it on 5 and it shows bones 0 it shows monkfish excellent now that we have unity Auto populating our item spot we just need to save the ID and the amount to a file for saving and loading and the code that we added will automatically repopulate the item slot after the scriptable objects serializes so now that we're done with all of that we just need to make our saving and loading functions so let's make a two functions inside of our inventory object called public save and public load now before we start writing our save function let's create another variable to write the path that we want to save our file to so we'll say public string save path the reason we're using it as a string is because we can have multiple inventories and save them to different locations so going back to our save function the way we're gonna be saving it is we'll use a binary format err in the JSON utility first we'll use the JSON utility to serialize our scriptable object out to a string then we'll use the binary formatter and the file stream to create a file and write that string into that file and save it to a given location so the way we'll do that is by saying string save data is equal to JSON utility dot to JSON we'll pass in this scriptable object and we'll put pretty print true now we'll say binary formatter but to say binary formatter we need to add the using which is using system runtime serialization dot for matters dot binary go back save will say binary formatter we'll just call it bf4 by daily formatter is equal to a new binary formatter then we'll say file stream which also doesn't show up so we need to add a using which that using will be using system do will call the file stream file and we'll say file create string dot contact this is to combine multiple strings together into a single string if you don't use string dot concoct an instead you just use a plus something like that you're actually using more memory and causing more garbage collection then is what is necessary so it's better to just go ahead and use stream concat because it's just as easy to use and it's also more performant so stream contact will say application die persistent data path this is a function that unity provides to you to be able to save files out to a persistent path across multiple devices so we'll say persistent data path comma save path now we're gonna say BF diet serialize and we'll pass in the file and we'll pass in the save data now we need to close the file out since we're done using it so we'll say file dot close excellent now let's create our load function it's pretty much the same thing just a little bit different we're gonna say if file dot exists checking to see if we do have a save file to load from will say applications die persistent data path and we can just copy and paste the path that we have here and inside of our if statement will say binary for matter bf equals new binary formatter then we'll say file stream file equals file dot open we can paste in the path that we're trying to open from then we'll say file mode dot open so now that we have our file opened we need to convert that file back to our scriptable object the way we're gonna do that is by saying JSON utility die from json overwrite BF Die deserialize pass in the file dot to store and then say this for the object that we want to paste it to which is the scriptable object now after we do that make sure to close out of the file so we don't have any memory leaks excellent now let's create a way to actually save this let's go into the character file that we created in the last video or I called it a player file and inside of the player file let's make an update for putting in some key downs so private void update and inside of the update will say if input I get key down key code dot space and then when we push the space button will just say inventory dot Save now let's also make another one for loading so we just copy and paste change this to enter and then instead of save we'll do a load go back into unity let it compile change your container size to zero let's create a save path the first thing you always need in your safe path for how we set it up is a backslash and I'll create a name for your safe pass I'll call mine inventory dot Save so let's click play you can see we have nothing in our inventory click on your player pick up some items after we pick up all the items in the world let's click space and try to save so we hit space let's leave play mode click play mode again and if we hit enter you'll see that we get the items added to our inventory and the air that we loaded is just a unity error and has nothing to do with us excellent so let's try to pick up some more items you'll see it's adding to the inventory correctly as we would expect it to be and now it's 6 to 2 to 2 let's not save the inventory leave play mode click play again open reload our inventory you'll see it's 3 1 1 1 1 let's only pick up a couple items so it's 5 1 2 1 1 we'll save this leave play mode go back into play mode click enter to load the inventory you'll see it loaded it correctly excellent you would think we're done now but there's one small thing that we still actually need to do so the way we set this up when we load the we're actually going to be overriding our database location with a saved version of this database which as I explained earlier you can't save a scriptable object within a scriptable object without having some type of database workaround but I'm not gonna make a database to hold my database that would be ridiculous so we're just gonna manually set this database variable through code and then deserialize the variable so that the json utility does not save it and override it when it goes to reload the game and the way we're gonna do that is by going back into our IDE we're gonna change where it says public item database object database and we'll change that to private so now when we do the JSON utility to JSON it's going to completely ignore this variable and it won't serialize it so we don't have to worry about it overlapping itself but now what we do need to worry about is making sure that variable is actually set so the code doesn't break and the way we'll do that is by making an onion and inside the on enable function will say database is equal to make some parentheses and inside of there type item database object then we'll say asset database dot and you'll probably need to add in it using the using unity editor then we'll say dot load asset at path and then we'll put in the path which if we go back into our editor we can find where the path is it's inside our items folder called database so it's gonna be assets scriptable objects items database assets scriptable objects items and then database dot asset then after that put a comma and we'll say type of item database object so every time the scriptable object runs the on enable function it'll automatically set the database to where the file is inside of the editor we can make sure this is working by saving it and going back into unity click play and then try to load an object and make sure it works it worked but since we're doing it as a unity editor specific way we can't even build our game right now well let's try we'll go to file build and run let's make a file a folder to put our build in select that folder and let's build alright we got an error it says well that one's not important right now says the build completed with the result it failed the reason it failed is because it's trying to use a unity editor thing inside of the build so we need to make a check right here to make sure that it's only running this code if we're in the unity editor the way we'll do that is by saying pound if unity editor and then end if now we'll be able to build the game but when we play the game outside of the editor our database variable still is not going to be populated so we're gonna write one more line of code to populate it when the game is built and not just when we're inside of the editor so instead of having an ENDIF right here we're gonna say pound else and then we'll say database is equal to and we can just go ahead and line this else out for now so that this isn't grayed out and it's easier to code so we'll say database is equal to resources load and then the item we want to load is item database object and the path we'll want to load it from is required to be inside of a resource folder but you can see here it's not in a resource folder so let's just move it to a resource folder go to your project clear out your errors if you want create a new folder inside of the root asset directory you can put it anywhere but this is where I'm going to put mine then let's move our database into the resources folder go back into here and let's change this to say assets resources and then here we don't need to put ass /resources we can actually just type database because we only have one resource folder so there's only one place for it to look up this item now we will unlined the LS save go back into unity play it to make sure it's going to load click enter it loaded the items let's build our game well you can see our inventory is a little messed up on the full-screen version of it but that's fine that's just display stuff that's not messing up our code we can change that whenever but now that the game's open let's click enter and pray that it loads our inventory you'll see it did excellent we don't actually have a way to move our character around but if we exit out of here we can replay inside of the editor collect more items and save let's load our inventory pick up some more items then we'll save this so it's 8 2 3 2 2 let's go to our build folder rerun this and let's click enter and see if it loads the new values that we just saved which it did 8 2 3 2 2 excellent everything seems to be working correctly if you have any questions or suggestions please leave them in the comment section below and as always if you enjoyed this video or learned anything from it please give it a thumbs up if you didn't you know what to do but until next time have a wonderful day and stay coding
Info
Channel: Coding With Unity
Views: 88,895
Rating: undefined out of 5
Keywords: unity3d, unity3d inventory, unity2d inventoy, unity, inventory, make an inventory with unity3d, make an inventory with unity, unity3d tutorial, coding with unity, unity inventory system, unity inventory tutorial, inventory tutorial, saving and loading, saving, loading, UNity2d saving, unity2d, unity3d saving, unity3d loading, unity3d saving and loading, unity saving and loading, unity loading, how to save an inventory, how to load an inventory
Id: 232EqU1k9yQ
Channel Id: undefined
Length: 23min 57sec (1437 seconds)
Published: Fri Sep 27 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.