LIVE: Let's build advanced save & load systems - Unity3D

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right hello out there everybody let me make sure yeah i think we're all good to go um today we're going to go over building oh a saving and loading system in unity essentially just a way to save and load game state um across a variety of different types of games i guess so a somewhat generic way to save a bunch of different game state talk about player preps and serialization and a couple other things and then maybe get into some online or cloud saved stuff too if we have enough time and we can get there then we'll go into that too talk about how you can kind of convert the local savings stuff that will go through into something that just saves remotely pretty easily and i think we'll do that with playfab because i've played with it recently it was pretty easy to use and pretty simple to get set up with all right um i guess before we get started i just want to say hello and thanks everybody who's here watching live and thanks everybody who comes by and joins later don't forget to hit that thumbs up button and subscribe and all that stuff i can ask a million times just this once for now go ahead and hit those before we get started and um what i'll do is switch over to a new view we'll start with an empty project we'll go through making out like a very basic little game maybe something where we can move around a little bit change the state of some things and then make it so that we can save that stuff off then we'll just kind of build on it from there so we'll start with something really simple maybe just save a player position and then start moving objects save those save colors states of random different things whatever kind of stuff we can come up with um if people have suggestions and chat as we're going along let's see if we can integrate those into the project as well all right i'm going to switch over to desktop mode for just a minute and give everybody just a real quick view so we're right now in the currently the latest version of unity as of this morning um and we're gonna just i guess build a project now with the empty thing so sorry i talk so fast and so much sometimes i kind of like lose my breath and my train of thought there take a drink and then we'll get going with a really simple empty project i didn't want to start with by the way a already built project because i want to make sure that everybody can follow along and see how they could integrate this right into their own project and not have to go through the process of like trying to dissect my existing game or my existing thing and see how it would work in theirs this would be something simple that you can take and really see how you can just add in whatever special custom properties that you have into your own into your own systems into your own games try to make it as actionable as possible and usable as possible for your other stuff all right so let's get going we've got an empty project here and um this is just in 2020.2.2 f1 so i think this was the latest one as of this morning and i think what i want to start with is just a simple character that can run around real quick and save off its position because i think about saving stuff like i don't know i almost feel like i should just blab about saving stuff maybe i'll just do it while we build things so i'm going to set up a really simple scene that we can run around a character in while we just talk about saving characters and saving um saving data because depending on your game the amount of data you save is gonna vary quite a bit i'm gonna grab pro builder real quick just so we can put together a quick little world so in the package manager just go to unity registry and i actually i'll just scroll down and i need to search for it there's not that many things in here grab pro builder install it and i'm going to add the package this will just let me build out a real quick little level so that i have something i can move a player around on and then know whether or not it actually moved or not really know what to move but know if i'm saving off the position so i'll have places that i can move around too and have it some some point of reference if i just move in empty space and all i can really do is look at like the transform positions and that's kind of boring and lame so let's get at least a little tiny world up here so here i've got pro builder set up i go to tools pro builder pro builder window gives me this little pop-up and i can hit the plus to bring up the new shape tool make a new cube it's right now defaulted to 15 by 1 by 15 that's i think just because that's what i used last um i like to make a lot of floors like this and then i just hit build you can pick a bunch of different shapes by the way i'm just going to do that build it and use that as my main piece and i've got this cube here if i close this shape tool that preview object will go away that's just like a little thing so you can build it see what it looks like um before you've actually created it but it goes away when you close that window all right so now i got the cube here um it's positioned at zero zero zero looks good close out pro builder and let's add a character i'm gonna start with um just a capsule for my character and then maybe we can go grab an asset from the asset store something that animates and runs around once we have more things to save off so we'll start with something simple though just a quick little 3d object make a capsule and we'll reset the position i'm going to switch tools too because i'm on the rect transform tool for ui stuff and it doesn't make a lot of sense for this mode all right so now we're on the move tool which is just w for the hotkeys by the way i'll move this over here let's just hold v and snap it ah snap there let's move it right over actually i'm gonna reset it reset the position drag it over no i'm gonna reset it to zero zero and then i'm gonna move the ground so i'm gonna switch this into snapping mode move the ground over here move the ground over here and then down and down right here so i think i wanna go at um i don't wanna put this i to put my player up at zero but i want his pivot to be down there actually i don't really care so i'm just gonna move the ground down to be i'm gonna put the ground at zero and i'm gonna move the player up i was trying to think of how i wanted to position these things but thinking about it more it doesn't really matter what the position of my player is i'm gonna be saving this thing off anyway so let's just do that i've got my cube here now and i've got my capsule or player there i'm gonna rename this to player so just hit f2 and type player and then i'm gonna grab my quiet keyboard so you guys don't have to listen to me type the whole time i knew i would forget something i got this thing intentionally just for when i'm streaming so that i can type and people don't have to hear all of the clicks um and then i always forget to grab it out so basically the same keyboard just in a silent mode but without 10 keys which surprisingly i use a lot more than i thought i did when i tried to switch to just using this thing without 10 keys as my primary one it didn't work very well because i find like i'm constantly just hitting things over there putting in putting in numbers and stuff all right so now we've got our player here we've got our cube here and i've got a quieter keyboard set up let's save off um by the way i'm just hitting ctrl s constantly to save it's just a habit so you're wondering like why the star is disappearing and i'm not saying anything it's just because i can't stop hitting it all right so now let's make it so we can move this character around i'm going to create a script real quick just like a simple player script that'll let us move the object and then we'll um then we'll go from there to actually save off what we've moved so let's add uh first i'm gonna add a rigidbody i'll add a rigid body component right down here which you can't see because it's right down behind my head so let's bring it up here so that it's not behind my head now you can see i've got a rigid body here and i'm going to add some constraints i'll collapse out the transform i want to freeze the rotation of this thing because i don't want it to just roll around and i'm just going to make it move with some simple velocity and i think i'll change the collision detection to continuous and save that off then i'm going to add a component so right below here right underneath where you can see let me just drag my head down there i'll hit add component and we'll type in a script name i'm just going to name this player and hit enter i had added this player quit handler let's remove that i'm going to go in and create a new script folder and just create it in here so i'll go right click create folder scripts go into that folder right click create c sharp script and i'll name this player that script by the way i think is something with one of the packages that uh let me hit add component again player quit handler if i add it in i bet if i click on it yeah it's part of oh the test runner framework so that's what it is that's where it came from i'm going to remove that though and add the player script that we actually created all right so that that was in the packages by the way that other script in case anybody was wondering where that thing came from i'm going to minimize packages and just look at our actual code so we've got our player script here let's open it up and today we're going to be working in writer so if you haven't used writer it's just the code editor just like visual studio or visual studio code or mono develop it's just a nice one made by jetbrains that i really like so i recommend people use it but it's not free they do have a free trial i pay for it because i love it and i think it's worth money but you can use whatever you want to follow along with this you don't have to use this editor the only thing that will be different is that your shortcuts might be a little tiny bit different and your um your like hints and tips that it gives might not be quite as good but they might be better if you got a better editor than mine but my experience writer's got kind of the best recommendations for stuff so in my player script since this is really just going to be about persistence i just want a simple way to move i think what we'll do is just set the velocity of this rigid body based on the input of our our keyboard or whatever using the input system another option would have been to maybe use like the nav mesh system and then save off the destinations and stuff i think we might do that later but let's i think i want to start with just simple moving around so i can push things and like wiggle around stuff and see how that works first so we'll go into unity or into not unity into writer i'm going to zoom this all down get rid of the start method because we don't need it we'll get rid of that comment about the update and these extra using statements that we don't need get it all down to just the update method here and the first thing that we want to do is just read our input so just want to grab horizontal and vertical and we'll just use the um the version one or old input system we're not going to use the new one because that'd be giant overkill i think for what we need to do all we really want to do is read the horizontal and vertical inputs we'll say var or i'll call it out as a float float horizontal equals input dot get axis horizontal again we're going to keep the gameplay stuff and all this very simple so that we can get into persistence and then we'll copy that and make a vertical one so just copied it pasted it copy and paste go back and capitalize that v the casing on these names does matter it matches up with the axes and the edit project settings and you go to input manager you'll see there names are all there and they have to match casewise all right so we've got our horizontal and vertical and then i want to just set the rigidbody velocity in that direction or something like that times the speed so first let's cache that rigid body i'll add a wake up here and just say underscore rigid body equals get component rigid body probably not super important to do but i figure why not cache that up get rid of the private keyword turn this into an expression body method and get rid of that and shrink it down into something relatively small now on line 13 i'm going to say rigidbody.set velocity or no velocity equals and here i want to set it to something that's using my horizontal and my vertical and i'm just going to name that let's name it velocity whoops and then generate a field port or generate a local variable for it so to be a vector3 named velocity it'll be equal to a new vector 3. we want to give it an x so this will be along like our left and right axis and then a z which will be our up and down so for up and down that's going to be our vertical which is w so that would be the last parameter of the z and for left and right it's going to be our vertical so we'll put vertical there and then a zero for the y because we don't want the character going up and down we just want it moving on the let's go look at we just want it moving on this axis this x axis right here the blue one and the red axis right there the z1 all right so we'll put in a zero for the y and then a horizontal for the z i think i might have just mixed those up um it's okay if i have flipped them which i think i did then we'll know in just a minute when i hit play and it's all inverted on my controls well i'll know when i'm hitting them you won't because you probably won't see the keys and i'm pressing all right so that should be enough to push our character in the direction that we want we don't have any speed control but let me just go make sure that it works and then we'll continue on and then we can start saving off our player's position as the first thing that we do all right so we're in and i can move this so this is w which should be going forward this is s which should be going backwards and here's left and right so i did mix those up and i also definitely need to change my camera position my camera position is all kinds messed up so before we go around fixing anything else let's fix the camera position so take the camera right here i'm in pause mode and i'm just going to drag it up here and get a quick view of what it looks like and then hit e to rotate it move it down a little bit unpause and then start moving around okay so here again my controls are mixed up but i can see my character and i just want to get an idea if this was going to be a reasonable view i think it is for now but i'll definitely change it so i'm going to stop playing well actually first i'm going to copy this transform position right click copy component stop playing does it say move the camera back yeah i'm going to move the oh i see what you're saying i'm going to shrink i'm going to shrink my head everybody i hope you guys don't mind my background is going to shrink and look a little bit smaller but i want to get myself out of the way all right so i've copied that transform position here i'm going to stop playing and now i'm going to paste the transform position again where is it paste paste component values there we go get my camera back up where it goes and then let's um switch that code up so go back into writer and i just need to move these parameters i believe it is there we go ctrl shift alt by the way to just move a parameter so select it ctrl shift alt and left arrow moves it to the left that's just in writer um there's hotkeys are different in all the other editors but writer's got a lot of cool ones like that and that's one of the reasons i like it so save go back into unity i think i'm going to move the camera maybe a little bit more but let's hit play and see it first let's see is it is building i think it's doing a compile real quick yep all right so hit play come in i go left yep that's a s is bringing it closer d goes to the right and w goes forward perfect now we can move let's add some speed and then start saving off positions when we stop playing and then re-save them when we start simplest version of saving and persistent stuff so first though speed we'll add a serialized field up here for a speed variable so go serialize field and then make a float named underscore speed and i give it a default of three um i would put f there and get rid of this private keyword one was way too slow i'm thinking three seems like a good default so we'll find out but i wanna make it adjustable i'm gonna take this speed and i'm gonna multiply it by the velocity but i also want to do one other thing just because we're moving um and we're moving with wasd there's a problem that a lot of people always run into where they don't normalize their input and then they use the vector like this and it essentially makes it so that you can go faster if you strafe so if you go w and d you'll get a little bit of a speed boost you get like a 1.414 speed or basically a 40 speed boost versus going the other way fix it though we can just do dot normalized here and that will bring the vector down so that it will shrink down and not basically not give you a speed boost when you strafe that's why some games especially older games you'll see a lot of time you get a little bit of a speed boost if you're strafing this is an easy way to address it usually so there we go we've got our speed and our velocity is now um normalized hit play try it out one more time all right we run around and there we go okay my player is working and it's time to start actually saving things off all right and somebody was asking in chat there's a lot of chat about um why why to use writer over some of the other editors and i just really wanted to briefly say that the reason that i like writer by the way i should assume that up sorry the reason that i like writer so much is really just the hints and tips and stuff that it gives it gives a lot of really good feedback and when it recommends things it usually gives a really good article and explanation that jetbrains is written on why it's recommending that so that's really why i like it i just find it to be a fun cool like way to learn new things about stuff whenever something pops up i can just go click read the article and learn like why it's recommending this thing what i could be doing better and like this just like little constant learning bit that i get every day just from using the editor all right so let's start saving stuff off now the simplest way to save things is just writing stuff out to player prefs and we're going to start with the simplest and then build upon that and then start adding more and more complication to it first thing that we have right now the only thing that changes in our game is the player's position so we'll just save that off so when we stop playing the player's position saves when we start playing we reload the player's position in fact we could even do it like on enable or on disable but yeah in fact let's do it there let's do it in on enable and on disable so on the player script here we'll add in on enable um let's add this up here say on enable and i'm only adding it up here just to fix the positioning for the camera so on enable we will save or no on disable let's start with on disable starting with on enable is probably the wrong way to go so we'll start by saving our code so on disable we'll just save off our position now the easiest way to save something in unity is to just write with player prefs so we'll start that way we'll go playerprefs.set and if you go hey i want to set like um my position you see that there's obviously not a way to do it there's set flow setting and set string so we could use any one of these well we couldn't use set in but we could use set float or set string and there are two different ways to yes let's do um let's do the set float way first and then we'll go into setting a string and serializing after that so one thing we could do is set a set of variables for our player's position like player x player y and player z has three separate floats and we can read those back in and just reset our position to those and that's what we'll do first so the first key that we'll set in our player press which is short for player preference is a way to easy way to save stuff off um and load stuff i guess and it works cross platform so the first key i'm gonna shut up now and just write in the key is going to be player um and then we could give it and the rest of the name could be position x or position dot x or dash x i think i'm just going to do player x so this will be player x and then we'll give it a value and that'll be the transform.position.x value this will just write off the x into our x player x floating point field that's going to get saved off i don't know how to say it any other way now i'm going to copy this line in fact watch this i hit ctrl d ctrl d because i'm in writer and it'll just duplicate my line for me because hey that's how unity does it right so makes it match freaking awesome i'll change these this to y to a z or x to a y and then to a z and then make sure that these match i missed those it'd be a big giant mess and that will save off my positions x y and z values pretty simple right now we'll just add an on enable and do that i'm just going to copy on disable paste it in here get rid of these private keywords don't need them i'm going to minimize the on disable and then change this to on enable now in on enable instead of setting floats i'll get them so i'll change all of these s's just hold alt click and drag over the s's right here change them to g's now they're get floats now getfloat doesn't take a second parameter just takes a key and returns back a float so cut this out i'll just go open close parentheses and closing a semicolon and we'll cut this part right here so select it all again just holding alt and clicking and dragging shift delete delete delete and then hit home and paste and then do an equals and that doesn't work right but what we can do is say that we'll save these off into variables so we'll say var of those is getting set to those so i've got an x a y and a z now getting red from my players x y and z and then we just say transform.position equals new vector3 and we give it the x y and z oh add the semicolon there at the end and we should be good to go so now this should save our players position the x y and z very very easily um well i guess there's not much to it all right let's go try it out real quick make sure that it works and then let's get into serializing it out and saving it as a string instead so we'll hit play and what happened our player has disappeared the reason for that if i go select them is that well when we tried to load it let's go look we load it up in here and we get a zero back here so because this doesn't have a default value i hit comma here you'll see there's an option for a default value the default is just going to be whatever a floats default is which is zero since i don't have any of these set i'm just getting back zero zero zero and because i spawned my player up above zero zero zero which i guess i'm kind of glad i did he's spawning down here and then just falling down forever so the easy way to fix this is to go back into our code and make sure that we actually have this set so we can just copy this key right here this player x and it's in our on enable say if player prefs dot has key and then we put in our key name and then make that a condition for actually loading up our our position here so save that off there we go so now we'll change it up so that we only save our or we only load our position if we actually have saved one of course now we've already got one saved so it's um oh it's gonna be falling down at whatever that weird position is so let's stop playing and reset our player press you can do that under edit and then there's a where's that option clear all player press right here third from the bottom in the edit menu pops up this little dialog hit yes thanks again to whoever showed me that i forget who it was now but you know lifesaver great feature one of my favorite things in in this version of unity all right so let's hit play again and now it should not load that invalid position there we go it didn't load the position because we hadn't disabled it all right so let's run around real quick i'm going to move just over here stop playing and i'm going to play again and there we go we're back at the position that we were at and if i run over here to the right just kind of hang out back here stop playing play again you see that it's saving and it's now loading up my data as soon as i start playing again all right let's jump back into unity and let's change this up a little bit because i think anybody who's done a lot of player prep stuff and who's done it this way knows that eventually like if you do it this way what you'll end up with is you're saving three floats here and you want to save off the rotation and you're saving some more floats and then you want to save some other values of saving more floats and you start adding more and more and more of these keys in here and it gets to be kind of a pain to manage and you end up having to build like a big management system for it it can definitely be extremely confusing i would say it it can get complicated really fast the easier way to do it or the way that i generally like to do it when things are going to get complicated is to just switch over to a serialization model where we take the data that we have that we want to save off serialize it out and then just write that all out at once either in a json format where it's just javascript or javascript object notation so it's essentially like a key value pairs that are human readable or you can serialize it out in a binary format or you could do like a json serialization and then encrypt it later a bunch of different options on how you want to actually store the data but serializing it in general is just a way to save off a bunch of different data without having to make all these different keys and manage how everything is saved it's essentially going to automatically generate the keys and values for you that's kind of what serialization does let's go through that process real quick with the position then we can look at what that serialized data looks like what the file looks like that well what the data looks like that'll give us and maybe shove it into a file see how we can save that into a local thing and then just keep going from there start building in more things and start hooking up more objects and things so we can like move things around attach stuff all that kind of other fun stuff once we get into it all right so let's go through that process so instead of saving off player x y and z let's just save off player position i'm going to go into on disable and instead of setting all of these floats i want to set the position as some sort of a string and to do that i can use the json utility that's built in so use json utility dot to json and i can pass in my transform.position now this will return back a string and that string is just going to show the position as an x y and z value so i'm going to say var json equals that and json is just java again javascript object notation what's short for i just named it that so that i remember that hey this is my string that's in that javascript notation or that javascript serialized version of it a lot of the time i'll put json in the name of any field or local variable that i'm using that's got it's in json format just so that i remember what it is and i know exactly which object it is all right so now that i've got that there i can just say player prefs dot instead of set float we'll do set string ring there we go and we'll change this to player position and we'll set the value there the json delete out those two lines with shift delete and then we'll go down to our on enable and change that up too so instead of looking for the player x value here we'll see if we have a player position and then if we do we'll just load up our player position as a vector so to do that we'll say json utility dot from json and we have to give it the type which is vector 3 and we'll give it our json text and the json text will get in from our player path so say our json equals playerpress.playerprayerprefs.getstring and we give it our key again which is that player position i'll just copy that and paste it in so i don't make any typos and mess something up all right now copy this json here and we're going to get that from our so what we're going to do here we've got the json text to get it back from our player press this is going to give us that formatted text here we're going to pass it into the json utilities from json method let's just split up the lines here make it really clear and we're going to pass that in as a parameter and we're going to expect back a vector3 so we're going to say hey here's this text turn it back into a vector 3. i need to do something with that and what i want to do with that is just assign it to the position so i'll take that transform position equals and paste it right there that should read the text convert it to a vector and then assign it to my transform position let's save that off hit ctrl shift b see if it works and then let's go through what the data actually looks like and how it works so save we hit play we run in here i don't expect it to load because i've changed all of those keys if i run over here and i stop playing and i hit play again i expect if i didn't mess anything up yep that we're back in the right position so let's look at what that json data looks like real quick and a couple different ways that we could do it i'm going to start by just attaching a debugger hitting a breakpoint showing it in there and then maybe we'll show it in the inspector and then go through putting it into a file saving it off you know into the actual local file system instead of just in player prefs all right so now we're attached i'm in writer i just hit f5 it's kind of the same for visual studio and most editors you just go in there and do whatever the attach hotkey is that you have and then in my on disable i'm going to add a break point right here so right here on line 14 i've added a break point so when i disable this object or turn the game off it should go into my safe i'm just going to click the player to turn them off so our breakpoint triggers and we go into the code and here i can see the data of my json this is another reason i like um writer i know a lot of the editors are kind of catching up with this but the little hints here the the tool tips that it's showing me are what the data of json actually looks like so you can see it has squiggly braces and then quotation marks and x and some stuff it's a little bit hard to read there still if i put my mouse over it i can see it a little bit better i can hit view here and get a little pop up and this is the actual format this is the json format with the x value the y value in the z you see the y is like 2.0 these are just floating point values um because it's a floating point value it's going to give us a nice really long number with way more detail than we need we could change that off in our sterilization we don't really need to though it's not worth our time so we've got our position there and all that stuff saved off to json we set it there and save it i'm going to go back to the on enable add a breakpoint here hit f5 f5 just makes it continue so if you hit a breakpoint if you're debugging you hit a breakpoint um you hit f5 again once the editor or your code editor debugger has um contacts or control hit f5 it will continue on that's the default at least you might have changed your hotkeys you have to go back to it but now if i go back over here and hit enable enable this guy like click the button to turn the object on or put the check box to turn the game object on our on enable hits we hit the break point and now we should be able to read that json back we get back that same exact text and then this thing converts it back to a vector that's it that's all we need to do to save off or serialize off a simple single field right so we wanted to save off just the position there um but if we want to save off more data things are going to get more complicated because i can't just go like hey i want to save let's not save off just this player let's say i want to save off no not just this position let's say i want to save the whole object right i'm like i want to convert this thing i want to do a player instead and i just passed in um uh well that's actually that's not gonna work i don't want to skip ahead too much so sorry i think thinking out loud a little bit but essentially like if i did this for just a single field or a single vector three it's a small win right like i get a little bit of a bonus because i don't have to recreate that vector three but really in the reality i don't want to do it for every single property on my object i really want to save it for like my entire object right like for my player or for whatever other thing i want to be able to serialize that object out save that that thing's data and then reload that thing's data kind of independently so that's what we'll do i guess yeah let's do that next we'll do that with our player we'll go through the process of saving out the position and um maybe something else maybe we'll save the let me think oh i have an idea get let's see let's try this out so if we go into here and i'm going to stop debugging real quick stop the unity editor what we're going to do is make it so the player has some inertia so that it doesn't just stop automatically so in the update method we'll say if the velocity if velocity.magnitude is greater than 0 then we'll set the magnitude to it so this way if we let off the keyboard the character should just kind of go and slow down on its own so it's got a little bit of inertia let's try this out go back into unity we'll hit play and then i expect to see him start going off to the side there we go and then he stopped right so he goes off to the side and then stops and goes off to the side and stops but if i start going um here let's set the speed up like five say i start going to the right or let's go to the right and then i'll stop i'll let's disable him that's that's that's the plan so i'll go right disable him re-enable him and okay he keeps going so what i want to do now is make it so that when he reloads so if i go left let's see go left ah my timing on this is terrible sorry but if i go left and i stop and then i hit play again i want him to continue moving in fact you know what the easiest way to do this would be is to just turn my character into a ball right instead of making him a capsule if i just well make him roll and stuff let's try that out there we go so if i let him roll say i want to make him roll let's let's do that we're going to do that we're going to turn this guy into a ball he's no longer going to be a capsule it's going to turn into a circle so we'll go game object 3d object we'll make a spear this will be our sphere player we'll reset his position set his y up to two let's go grab him real quick move him just over here this is going to be our new player our player that rolls around like a ball add a rigid body to him and we'll just go disable this other player like let's go delete that other player completely and name this guy player now taken over we've got a new player here all right we'll switch this over to continuous and then hit play our ball should now roll around all right so we got a ball there and it just rolls in whatever direction we press and then when i stop playing it should save my position i start playing again it's going to reload my position but it doesn't reload my velocity that's what i want to get so let's get it over here and we're going to make it start rolling up to the top just reproduce that one more time so it's rolling up there i stop playing i start playing it should reappear right here saving our position but the velocity is not saving so let's go back in and figure out how we would change this code to save the velocity as well and to re-add our velocity to our player the easiest way to do it or the first version of what you might want to do is just go hey this is our json for saving the position let's copy it paste it call this velocity json and you'll see how quickly this is going to get messy and then we'll fix it but we'll name this velocity json and then here we can say maybe we'll get the rigidbody.velocity we'll serialize that out into another one and we'll say this is the player velocity it works we'll copy this and go down here oh actually i guess we'll just copy and paste this line right here on in our on enable for getting the player position and setting the position in fact one thing we could do here watch this i take this little line of code cut it and paste it right in here and shrink this down into a single line now i'm not sure i'm a giant fan of that but when it comes to just reloading these parameters and properties like this it's actually not too bad if it's just a single thing like this where i'm just setting a bunch of parameters if it was doing something more complicated or wasn't going to be doing the same thing over and over where i'm just mapping one to one then i wouldn't like this format because it's way too long across the top for me but for doing something like this i'm okay with it now i'm going to duplicate this line and we'll say rigidbody velocity is equal to player.velocity save this off i'm going to zoom that out just a little bit so everybody can see it all we'll go back into unity hit play and now we should be saving off our velocity oh i spelled velocity wrong somebody caught it thank you let me fix it let me go back in there where did i spell yep e-l-o let's right-click come on ryder rename two velocity there you go thank you all right we'll do another build ctrl shift b by the way is hotkey and writer to do a build hit play and then let's roll around so i'm gonna roll to the right we'll stop playing start playing and look at that we continue to roll to the right so now we're saving off the position and the velocity you can see we're getting at least a couple different things here save and stop playing one more time i should see i'm rolling kind of out there to the side all right looking good so far i think we've got a couple things persisting but like i said this is going to eventually turn into a bit of a mess right because i'm going to want to save more and more things on these um oh man and i'm going to lose my voice too let me take a drink um in fact let's add another thing real quick let's add one more thing to the player before we really go about cleaning it because i feel like if i clean it too early though it doesn't really stick right like putting two things there and then shrinking that up and let's make another parameter here let's make something that we can pick up so i'm going to make it so that our little ball here can drive around and pick up um money but we'll make some little cubes that the the box or the player can grab let's go actually i wonder if there's something on the asset store that we could grab like some cash that could spin around i'll just make some money that's that we'll make some money so we'll go game object 3d object make a cube or reset the position move it up here a bit and then hit f to zoom in i'm going to hit the r key to go into our scale mode and then shrink it down oh not that far shrink it down maybe like that and then like that and then like that i don't know something like that maybe i've got my nice little dollar bill there and then i'll go make a material for it so go to assets right click create a new folder i'll call this art for my beautiful artwork and then in here we'll just make a new material and i'll probably just make this thing like bright green let's call this money and let's just make it a big bright green to start and then attach it on here as our money let's go drop that onto my cube there we go i've got this cash right here i'll make some money that our player can go collect and then we'll keep track of that showed in the ui persist that off and then see how we can refactor this to make persisting more and more things easier all right so we got our money here let's move it over to the side let's add a money script to it so go into the scripts folder actually let's go into the player script let's go down to the bottom of it and just start typing say public class money mono behavior as well do it the way that i normally do it right so we'll zoom in a bit and then minimize that and then we'll just move this money class to its own file now in my money i want it to do two things i wanted to listen for a trigger enter so we can pick it up real quick give the player some cash and give us something else to persist that changes and then um i guess eventually i want to persist whether or not the money's been picked up but i also want to make the money spin around in a circle so let's do that first let's start with an update and just say transform.rotate and we'll rotate on zero and then something on the y we'll call this rotation speed and then zero on the z i'm going to generate a field for rotation speed so just hit alt enter generate a serialized field i love it and then we'll set a value of i'm gonna go with like five get rid of that private keyword that i don't need get rid of that private keyword that i don't need and turn that into an expression binding method just shrink this whole thing down get rid of that system statement too all right now i've got money that spins in place should be able to hit play and just watch my money spin it gives me time to take a drink while the money spins around and see what's going on in chat if anybody is watching hasn't tried ryder yet i definitely recommend just going and grabbing their trial it's it's worth a shot it's definitely worth trying but you have to um oh i didn't add the script let's add the money script you have to make sure that you're going to spend time with it though because it does take a lot of work um to get used to it obviously this is broken right um you have to get used to the hotkey is changing and the way that things can move around but i've in my experience the benefit has been very worth it it's just been a nice easy to use one and it's given me a lot of really cool tips so a couple things going on here my money is spinning way too fast because i didn't add in time dot delta time and i'm running at way too fast of a frame rate and um i didn't add the money script so let's stop playing let's add the money script while i'm not in play mode go back into the script and multiply rotation speed by time dot delta time that should fix the issue there it'll spin around and then let's change it so that we can oh i'll handle our trigger so say on trigger enter and then in here we'll say if other dot get component player actually you know what let's do a get component on it let's do this we'll say if other dot try if other dot try get component and then we'll do the component type of player and we say out var player so if we get a player back from the other thing then we'll get it right here as a variable and what we want to do is tell the player to pick up the money so say player dot add money i think that's good and then we'll say we want to do game object dot set active to false for now we'll just disable our object we'll add some money to our player let's go to the player player will just say money plus plus and then we'll update some money ui in just a moment so let's add an exp oh no not an expression body to add a field for this okay let's copy this and go up here and we'll just add a public property for it public int money and it'll have a getter and a private setter so now we've got a way to add money onto our player um it's going to increment whenever we pick one up and then the final thing i want to do is just slap a little bit of a ui real quick all right so let's go into ui development we'll go add a ui under game object ui and text mesh pro import the tmp essentials and then we'll set up a ui element so i've got my text right here and then hit f and go to 2d mode and then we'll snap this up to the top all right there we go and let's see if we can zoom out zoom zoom zoom out that should show our money so i'm going to start this out at zero dollars we'll make it nice and big i don't know make it like 100 tall and then center it out this will show all of our cash all right let's go into um our money ui yeah so i see a lot of people talking about just serialization in general in general once you get as your serialization goes bigger and bigger and you'll see this as we go through this you can um we don't have to serialize as javascript one of the things and i want to recommend this for everybody that's going through this too if you do serialize your data out and you're saving your stuff out so a little brief talk real quick in the middle of this um a lot of time the best way to do it and the the way that i would recommend doing it in a large scale project is set up your serialization so that you can swap it so that it's adjustable generally you don't want to save everything off in a human readable format and json in general isn't the most optimized format it's going to be much bigger making it human readable and easy to read makes it much bigger it's less efficient it's obviously not encrypted or secure in any way right if people can get to the data they can definitely change it they can view it they can modify it but once once you've built your system up you really want to be able to swap between the serialization modes ideally because then when you run into issues you can in debug mode or at least in your local modes swap over your serialization to javascript or json or something else xml something that is human readable so that you can go through that process and figure out what's going on and then just switch back to a binary or binary formatter or a binary serialization method or something that's encrypted afterwards that's that's generally the recommended way to go is having it um so you can swap between both of those we're going to start we're starting with javascript right now because obviously by far the easiest and in 90 of the cases it's probably going to be fine but as soon as you need to actually save this encrypted save it off so people can't read it you're gonna wanna add in that extra layer of being able to swap out the serializer and that's really really easy to do so don't don't worry about like how do you do it it's a very simple process to go through okay let's go through making our money actually show up now i think in this case i'm gonna be lazy and just make this read directly from our player constantly and not set up an event so i'm just gonna call this ui money display and i'm gonna literally just bind it directly up to the player and just have it show the um show the money on there in fact you know what i might even do it worse i'm gonna go to the player no i'm gonna do it on them i'll do it on the money i'll separate it out at least a little bit so i say um uh player equals find object to type we'll just get the player here and cash it in awake uh would generate a field for that zoom this in a bunch here get rid of start and then in our update we'll just say um our text will set to tmp text so say underscore text we got to cache it here equals git component tmp underscore text and then we'll generate a field for that save that off and then in our update we'll just set the text set text text dot oh i gotta add a using statement sorry so alt enter add the using statements up here which is gonna add that using tm pro statement let me get rid of these extra usings up here and then here we'll say text dot set text and we'll set it to underscore player dot money in fact we're gonna set it to dollar sign quotes dollar sign plus player.money now this is definitely not optimized it's gonna be spamming it and just resetting the text every frame doesn't matter at all because that's not what we're worried about i didn't want to set this up with an event and over complicate it distract from the important stuff all right so now we've got our money display script there it's set up and it should show us how much money we've got so if i go over here rename my cube to money switch back into 3d mode and hit f i can get to my cache go place a couple of these out in fact let's turn this into a prefab first go create a folder called prefabs then we'll take our money drop it into the prefabs folder so it turns blue and i'll duplicate it and put a couple dollar bills out there all right hit play and i should be able to now run over my money and let's see if it works i should oh and i'm going to reset my player pref because my player was flying off somewhere clear all player press yes all right now i can go get my money oh i can't get it because i didn't hit the is trigger this is a good reason to make things into prefabs i've got it as a prefab check his trigger save try one more time we'll go pick this up get our cash so we got one we got two we got three and we got four and then there's one more right here got five all right i'm gonna stop playing and let's see what happens with our money so i stopped playing i hit play again and well my positions reset but so is all my money right i have no cash and all of the dollars are reset back into where they were now i want to go through the process of fixing that so we'll make it so that our money actually will disappear well first let's make it persist let's let's do it a little buggy so that we save how much money we have and then we'll save the state of all the money that we've actually picked up so we'll go through the process by going to our player and let's look at where we save when we save right now in on disable we save off our player position and our player velocity and then in on enable we load both of those back in let's go through the next easy logical step of saving off our money so if we want to save off our money we might just go well player preps dot set end and we put in player money and then put in our money value right so this will save it off as a separate integer and then i can copy this or go what do i want to do right down here copy the get string oh no i'm going to paste it right here i'll say playerprefs.getnt so we'll change this from sedant to getint go back here change that s to a g and then paste the money right there and now we're loading in our money obviously when you talk about hacking like this is by far the easiest way to make it hackable because if i do this and i've saved my money like this right i've just got it in this field i could easily just jump into my um registry so if you've never used your registry just type in regreg or type regedit and you'll get this little editor right here let's pop it up right here if you're on windows at least you'll get an editor right here and you can just search in here um you can actually find things by key so i can go find and i could go search for my money key i could search for player position and i could actually go find it as a key in here and then change it i change the value i could do the same with money or whatever other thing that i want to go in and change so that's why people worry about like saving stuff off in serials or in javascript or saving stuff in player press that's the reason if you have important stuff especially multiplayer stuff don't just save it in raw text in player press because that's where you're going to run into problems now this does work though let's play and see how it works because so say i've got a mobile game single player i don't care about other people doing stuff or whatever um i then i i might not even need to go any further and this might be kind of good enough let's clear my prefs hit play though and see if it actually works all right so i run around i'll go get a dollar i'll go get two dollars i'm gonna stop playing and then i'm gonna play again and i've got two dollars but all the money is reset all right i'm going to go back and i'm going to make it so well i don't know what i want to do let me think about this for one second i kind of want my velocity to stop stop sticking around but i guess it's okay i'll just go from premiere so i hit play again remember i get my two dollars but the problem that i've got now is that my other money is you know already out there in the world and i can just go pick it up again so i can go pick up this cash go pick up this cash go pick up this one and this one and this one and i'll get up to nine dollars so i can stop playing i'm back in and then now i'm at ten dollars because i just ran over one and so on so you see that i'll just keep getting more and more money right so the the cash that's in there right now or the cash just keeps responding but it keeps track of the amount of money that i have so we're gonna um make some changes we're going to make it so that our money saves off its its position or its state all of our money saves off its state and we're going to try to get this all into kind of a a single object so there are a couple couple things that i want to do first is let's make it so that the money can just save off its state on its own so that we can just write write a simple script it'll find all of the objects that we want to save their state and just save them off into something and then pull them back out and then we'll make it so that we can serialize that into something even better and make it just keep improving it all right oh it's getting warm in here sorry the the lights on bright so it kind of blinds me and i it's toasty all right let's go through this again um we're going to go into unity and what we want to do is make something for our money so that our money can save off its state and i really want to make like a separate savings system instead of having my player do the saving i want to have a script that handles all of our saving for us but it can save our player and save our money and save anything else that needs to be saved so let's go into writer here and let's just create a new script in fact i'm going to go into the player script i'm gonna take the stuff that saves the player data we're gonna move this into its own save system script or let's call it a um let's call it game state so make a new class public class game state and we'll make that a mono behavior and then uh no let's call this game persist it's not really state management it's going to be our persistence and then in here we're going to have a save method so do public void save and then in the save what i want to do is save off all of the state for my player so i want to have my player save state i want to have my money save state and everything else i'm going to first move this into its own file because i started coding it right in the middle of the player class which doesn't make a lot of sense so i'll move it down paste it and then click on it hit alt enter and move it to its own file and then what we'll do is on let's add in the on disable here so we'll do on disable we'll do save and then on enable do a load get rid of the private keywords generate the load method just kind of stubbing this all out real quick and then we're going to start implementing it so we'll turn that into an expression body turn that into an expression body get rid of that and i don't think that this save method needs to be public all right so our persist is going to do two things it's going to tell our player to save off its data or it's going to save off our players data and then it's also going to save off all of the other savable type of things data so one way we can do this is to just add in an interface of savable or some persistence i can i persist i save data i load data something like that onto the components that we want to save data so this is going to be like the i would say the simplest way to do it that doesn't require you to really restructure your code very much the other way that we're going to get into in a little bit once we get a little bit more advanced will be requiring us to really think about how we structure our data in our game it's a lot more opinionated though and it changes the way that your stuff works so it might not work as well as just a slap in thing this setup here should work relatively easily to just kind of work into your existing game so this way this will work is we'll go through all of the things that can persist and then just tell them to persist if we add in an interface we can drop that onto all types of different objects that we want to persist and then tell them to handle their persistence on their own then we can move how we handle that persistence later so we'll start with a simple save method so in the save we could do something like finding all of our savable objects so we do like a find objects of type i persist seems like a good name p-e-r-s-i-s-t and then we'll generate an interface for that so hit alt enter generate an i persist interface and add that in in the i persist interface we would probably have a save and a load oh i need to add that void save and avoid load i think that that seems good enough now we'll go through all of the objects that we find and then just tell them to save so we'll say find object not find object find objects of type and we'll change this into a for each loop so for each var persist in find objects of type persist just say persist dot save now this is obvious oh what uh where am i no i can do find object type sorry so this isn't gonna work i i just just mixing myself up here so i don't this was one of the things i wanted to show that we couldn't do let me go into my actual solution for it because i had it right up here i got myself a little mixed up we don't want to do the find object we wanted to how did i persist these again oh that's right this i remember there was a simple now again this is going to be the less than optimal way to find all of them i got myself mixed up on my less than optimal way and it's to find all of the mono behaviors so what we can do is find all of the objects that are in the scene and then we want to include the inactive ones and then we want to get them of type there we go and then use the i persist in fact i think i want to rename this to i save state instead of i persist that's right and then we'll turn there we go so that's going to let us loop through all of the mono behaviors that implement i save state and then persist on them so i got myself a little bit mixed up there so this is again getting all of the objects in the scene including inactive ones that implement the i save state so we're going to loop through those and then just call save on these again this is only happening at the end of our game like when we're shutting down so i'm not worried about speeding this up or anything all right then in our load we can do kind of the same thing we'll just go through our 4-h and just do a load instead just paste that in and we can load load our states and load our states and save our states sorry getting myself a little bit mixed up all right now let's go into um so zeke was asking about architecture this is the much more simpler versions of of stuff that will be in architecture at a much bigger level though um what is an interface somebody's asking let's take a real quick brief talk about what an interface is in this implementation right now somebody's saying would give a nice freeze this is literally only running at the end of the game right now because we're going to find all these things we definitely don't want to do a scan through a big project of all of the objects we want to cache these out again i want to make this so that you can just slap this in without restructuring and rebuilding your entire project so this will let you add an interface on and then just find all of those things and save the stuff out and then you can obviously continue on with the stuff that we'll get into later and make it even faster and cleaner so what does an interface do real quick let's talk about it an interface essentially assigns or defines a contract that a class or an object will adhere to so if we say that something implements the i save state interface we're just saying in this case that it will have a save method that takes no parameters and returns nothing that's why it's got void here and it'll have a load method that takes nothing and returns nothing so if we have i save state on any class we have to have those there so this is going to find all of the classes that we have or all of the components or game objects that have something like a money script or any other script on them that has that interface added to the script so let's go add it on and see what that actually looks like let's go to the money script and we'll hit comma after the mono behavior and to add an interface that's how we do it after the base class or after the colon if we just are using object as our as our class um we we put the interface that we want to implement or the multiple interfaces that we want to implement so we'll use i save state here start typing it in and immediately you should get an error and get a little action option here saying that we need to implement the missing members i can hit the button right there and it'll just tell me what members it has that i need to implement and give me the option to check the ones that i want i'm just going to leave them all and hit enter and then i'll get my save and load method but it gives me an exception here saying that it will blow up or that it's not not implemented yet so it's going to essentially blow up or pause or give an error in my game so i need to implement my save and load methods so in the save and load methods um we can start off with the simplest way to save and load things the least opinionated way before we get into serializing it so say my money just wants to save its on and off state right i just want to save this off and i don't want to go into serializing that stuff what i could do is as simple as doing a player press dot set or let's do a set int and we could set our let's say money and then our game object name plus i guess that's probably it we don't even need an enabled and then just set it to one if we're enabled and two or zero if we're not so say gameobject.enabled or is is game object.activeself i get myself mixed up because we're setting it to not active so if the game object is active we'll set it to a1 otherwise we'll set it to a zero pretty simple way to just lock in the object here or set a lock in the state linking it directly to an how am i saying i'm not getting my words out there right let's try again so we call save we get a string here that's money plus our name so each one will have a unique name here and we'll set it to either true or false or one or zero based on whether or not we're active and then we can do this inverse in our load and we just say playerprefs.getint money and then plus our game object that name and then we can set our object to that so say int is active equals that so that's going to be a one or a zero one would be true and then we'll say if is active equals one game object.setactivetrue or even better we just say gameobject.setactive is active equals one i cannot get this autocomplete to work there we go and tap that in so this would again save this off just the player prefs we're not serializing it yet and we're not saving a lot of data on this object yet but this will be an easy way to just make it so that any object can save and you kind of batch save and load things really really easily um and then we'll get into how we can do this across multiple game saves in just a moment and then go into i think serialization after that kind of keep it kind of in a logical order so that it makes sense let's turn these into expression body methods real quick or at least that save one into one and then let's try it out so i should be able to see my data save here states and see them load let's see am i missing anything i think real quick my save is called it's called over here by this thing save and game persist toggles on enable and on disable all right i think that should work let's go try it out so we'll hit play what oh no my oh my ball almost rolled away all right let's go get some cash got one got two got three all right we'll stop playing we'll hit play again and it did not work so let's go see what happened what did oh i know i know what happened i didn't actually add the script so this is what happens all the time i i say this all the time because it happens all the time i write scripts and then i forget to add them to things so i need to add my game persist script to an object we'll go into unity go create an empty game object call it game persist i'm just going to paste the class name right there reset the transform position and then add the component save that off and try again all right so now you see that when i hit play all of my money disappeared right so the what happened was when we loaded here let's in fact let's disable the game persist let's hit play again and let's turn it on and see what happens so here we're in everything's fine i load and bam all my money disappeared that's not because it's smart and it realized that i picked up my money a couple games ago it's because our default value is actually invalid our default value when we load up a player pref is going to be zero and we're using zero as what is active so when we try to load it up if the value isn't there we get zero and we say the thing doesn't or isn't actually activated so let's change that up a little bit let's go into our money and see how we would maybe modify this so instead of saying that we want to set the active state of it what i want to set instead is the picked up state of it and i'm going to restructure the name of my key a little bit in fact i think i'll restructure the name of my key maybe in the oh wait oh i should do an awake let's just do a property for it so i'm going to take this little bit of code right here i'm going to cut it and call this our save key we'll generate a field for it so alt enter generated get only property i said field emit property and then i'm going to move this up which is just ctrl alt shift and the up arrow to move a line up in writer by the way and i'm going to make this return back a string so i do the expression body property there and then we do dollar sign quotes to use string interpolation this let me put variables in the middle and then i'm going to paste it in oh i got extra quotes though so let's just change this up a little bit let's get rid of that second quote so we have money and then i don't need a quote here because i'm using string interpolation we use the braces instead and put the variable in so we use gameobject.name and we'll say it picked up so my key is going to be whether or not it was picked up in fact let's rename this to picked up key that it's very obvious what it is this is my key for whether or not it was picked up so it was picked up will be true if it is not active so if its active self is false it should be a one and if it's not then it should be a zero that's right that looks good right wait active self this is true yup so i got this inverted so i'm going to change this around and then over here we just change this around here we'll invert those now i didn't have to necessarily change the key oh i do need to however make sure that the key matches um i just wanted to clean that up a little bit because i don't like having all these string literals just kind of scattered throughout the code i'm going to put them in here let's just put them in one spot so that should allow me to now have a good default of the thing hasn't been picked up but if it has been picked up we'll turn the object off when we load let's try that out all right we hit play and we go around and now if i load my game persist you see that nothing blew up i didn't lose all my money if i go pick up some cash here and then disable it i should expect to see my money well nothing really changes right but i'll go stop playing let's hit play again and then let's turn on the persist and i should expect that those bits of money on the left fall away or disappear that's looking good i think that things are working let's try it with game persist on we'll save i'm going to reset player prefs go to edit clear all player preps yes we'll hit play then we'll go through and we should see that now our money saves our position saves and everything else just kind of saves obviously that we still want to restructure things and reformat it a bit um but i want to get at least the very basics up and working so i've got five i'm going to leave those two and have the ball rolling towards me stop playing hit play one more time and see if the magic works nope didn't work so what happened let's take a look let's turn the persist off and on what did i miss i've definitely missed something oh i wonder if um a registry pop-up there let's see what did i miss here so we're picking up we're saving we're loading let's add a breakpoint and find out you know let's go through the debugging process together real quick so in writer we'll just add a break point right here on the load and what i'm going to do is the easiest way when you're debugging this kind of stuff just get rid of all the extras just have one thing in there i've got one bit of money in here i'm going to disable all the rest we'll go to edit clear all player press hit yes save hit play and we'll go pick that one up let's see what's actually happening there why it wasn't working so go into into unity oh we hit play alright so it loads and it's checking for that picked up key oh see if money dash money was picked up is active or was picked up should be false so it should be active that's true oh i need to rename this variable that's terrible i've misnamed my variable all right let's go pick this up and then we stop playing and i should expect to see a save oh no did i add a break point in my save let's go check in my save right here let's there we go we're going through we're finding all of the things that persist oh wait a minute i didn't find my object okay let's do it um let's save before we there's a problem the problem is i don't have buttons set up yet so that we can save and i'm just kind of saving when we're exiting right now so let's add in a save and load button real quick let's make it so that we can just save and load without having to stop and start hitting play first though i'm going to fix that variable name so go back to our variable name where was that one the one that i did not like where did you go bad variable is active was picked up there we go now we'll go in and we're going to add in a button for loading a game and saving a game in fact we'll add in a button for loading and saving maybe three different games we can do load game one load game two load game three save game one save game two save game three save off the state of all of those across things so let's go into our ui again we'll go to 2d mode hit f zoom out a ton and then let's add in a panel or right click on our canvas ui and add a panel i'm going to shrink this thing down we'll center it real quick make it maybe like a 300 by 300 move it over here accept these anchors real quick and then we'll zoom in on it and then add some buttons so here we'll add a load but let's start with just a load and save button a single one and then we'll add two and three um right after that or once we get the first one working so add a button this will be our load game one and we'll call this load one or change the text i mean to say load one so go in here load one and then we'll make a save game one button too just save game one and we'll make this call or make this text say save one not what not with an extra line though ah i changed that save there we go okay i keep hitting escape bad habit all right let's get these in position so i'll put a save button up here we'll put the load button up here and uh maybe string resize these a little bit i'm not going to make them perfect because so nobody's going to look at them again after this you can always make your buttons perfect all right um actually i think i'm gonna leave that big so i've got lots of room all right so our load game button is going to just call the load method on that game persist so i hit plus here and the on click so i've got the button selected go down the button component in the on click we'll just add in the game persist object and the load method so go to game persist and look for load and oh it's not there and the reason it's not there is because it's not public so we'll go into our wait it is is it public no go into game persist it is not public we'll zoom out a bunch right here make this public save and we'll make our save method public too so this is gonna let us save game one only right now and then maybe we'll make it take a parameter so we can save game two three four whatever else we wanna do just off of a single button click all right so we'll go to our load button take our game persist again oh it's already assigned i already signed it i just need to go into the drop down game persist and choose load go to the save one same thing hit the plus add in a reference to game persists object so it can find the script go to game persist and choose what am i on save save there it is now i can save and load my game at runtime without having to enable and disable stuff at least it should be able to let's go try it out let's reset my player press one more time the problem with this character just rolling around all the way or all the time by the way is that he just uh is really annoying because he just falls off so i'm gonna go into our player script real quick and i'm just gonna disable this line of code here that made it so that he kept the velocity now he's just going to set his velocity to whatever it is um when i stop or when i hit the button to save which i think actually works well because now i can save it and keep my velocity without having to hold the button down the whole time although it's going gonna reset my velocity every frame isn't it yeah i guess it doesn't matter okay let's um where'd my player go stop playing let's clear player paths i just don't want my player falling off the edge anymore all right so we go grab our money and we load one and the money reappears so i load one and you see that it's not resetting my player's position it's only resetting the money go pick it up load one it reappears go pick it up load when it repairs i'm gonna go pick it up i'm going to hit save and then i'm hit load and it doesn't reappear so far so good it's saving the money state but it's not hooked up to the player's date so let's make the player implement that same interface so that it just kind of works with that game persistence setup that we have to do that we'll go over here to our money we'll look at our interface our i save state which file is this in let's hit f12 and go to it oops control z f12 to go to it it's right now in the bottom of our game persist i'm going to move it to its own file move to i save state then we'll go into player and we'll make it implement the i save state method so just do comma i save state alt enter implement those methods in fact right now i've got save and load i'm not going to implement them i'm going to hit escape i'm going to go down here and where we have on disable i'll make that save and where we have on enable i'll make that load i do need to make them public so that they actually account for the interface because an interface essentially describes your public facing methods or your public contract if it's not public you can't access it but changing on enable and on disable to save and load now should make it so that when i hit that button uh it saves my player too so to save and load my player state let's try it out all right oh we have a compiler error let's go back into here ctrl shift b i think it's saying that i have two i save states that what it was let's go into unity writer's not seeing it so maybe there's an error here okay it just hadn't caught up something some got mixed up in the files i'm just tab back and forth okay so that seems good i can move around let's stop playing let's reset player press one more time and then let's try loading and saving our state with everything all right so i'm moving around moving around moving around oh whoops i didn't save moving around moving around let's go over here save and then i load and i'm back there okay looking good and if i go pick up my money i've got one dollar but if i load i'm back at that spot with zero dollars and the money reappears if i go pick up the money though save and then maybe run around here load i'm back there and i have my cash all right so let's go through the process of adding i guess a little bit more money because i think picking up one dollar is kind of lame and then um yeah go on to whatever i forget what our next step was there's quite a few different things that we can do here so let's go into scene view go to 2d mode hit f and let's just duplicate this cache a little bit put out a couple more dollars make sure that everything's working across picking up multiple things and the saving and loading is right and then i think we'll do multiple save games and then combining data and uh maybe going to play fab and pushing stuff up into the cloud and all that stuff cause right now we've got one way we got a way to save like a single game but not more than that oh our money spins so slowly look at that tiny tiny slow spin what's going on in the players there's an error here saying that it couldn't get higher velocity interesting wait did not get the ah i'm gonna hit load oh let's just play i'm not sure what i messed up there i'll fix the we'll figure it out and get it debugged all right let's hit play though let's run around grab some cash real quick and grab just that half of the cache save and then load looking good go pick up the rest of this cache and then load and yep we're back to it now i want to figure out what this error was real quick so i'm going to hit f5 added break point right here in our load method remove that other one i'm going to stop playing and hit play one more time just so we can see what's going on there all right oops we're hitting the save method any second now it should let me start again and we can load but people are talking to them and chat about saving data and databases going through look and see what everybody's chatting about in there all right so going through our load states okay so here what was null ah the rigid body was null ah okay here's what happened let's talk about this this is actually kind of an important thing so if you're new to unity you may not have experienced this or if it's like your first year in you might run into this more often than not and just struggle and go what the hell is wrong why did this stop working everything was fine right so what's going on here is we're loading and in it in our load method we're accessing the rigid body right and the rigid body if you look here is cached in our awake method so our awake method gets our rigid body but for some reason when we call load the rigid body is null let's hit f5 real quick i'm going to hit play in it debug it show it real quick and then i'll show you how we can easily fix this but i want to show like how you can determine that this is the problem when this pops up because this happens all the time we hit play we'll go back into unity one more time or back into writer when it pops up any second now and you can just put our mouse right over here and you can see that the rigid body is null so i knew that the error was on this line because the error message said it's on line 29 but theoretically like actually realistically there wasn't much that could be null so i i guess like rigid body was kind of the only thing but if you're not sure you add a break point you can just mouse over things and start looking at stuff so i could look at like the results of this but no nothing else could really be the option so let's go see why that's happening because it's getting cached here in a wake but the problem is that this load method is getting called before awake now if you're new to unity you're thinking like how the hell is something getting called before awake it's because all of the awakes are called together if we go in here i well let's go into game persist right so here we've got a situation where if you look at the game execution order stuff right you see that awake gets called then on enable and then start which is kind of weird like you might think on enable gets called after start but it's awake on enable start and then all of the other methods and then the things that get called every frame but what happens when you call awake on on enable is that they're called on each object at once so the player will call it's awake and then it's on enable the game persist we'll call it's awake and then call it's on enable and everything else will do the same thing and then all of them will call their start methods now what happens here is because of just sheer luck and the order that the things were added into the scene and the system that i'm on the game persists awake and on enable are calling before the players awake and on enable so what happens is this calls in it calls the load before players cache that rigid body we get a no reference exception the game blows up and we don't know why and this again won't happen all the time right like i could run this again on a mac and it might work totally fine because the execution order has changed there are two ways to fix this really one is there is an ability to go in and kind of hard code the script execution order so you could change it so that that one that the player always runs before the the game persists that's an option not the one that i would usually recommend though there are a lot there are three options because another option is to set up the binding and control of all of this stuff in a single place so you have like a single script that kind of bootstraps your game and sets up all of these references and kind of handles that that's what like a dependency injection framework would do the third option is to just change our game persist to not do this in on enable and to do this and start and then maybe we could still leave this a non-disabled but we really we don't even need it in start we could probably just disable it and take over control of it but if we move it to start then it will at least fix the issue we won't get that no reference exception it will work i'm going to just disable them though because i want to now load in every time fresh with a new game and then just have the ability to save and load an existing saved game i want to be able to go through a bunch of different saves and i think that that functionality of auto loading the last one makes it a little bit harder for me to play with that let's try it out again one more time no more error that error is gone go pick up some money i go hit load one and i'm back at whatever load one was but i can hit play and go back and reset all right so now we've got a system that allows us to kind of save out at least a variety of different things so we're saving the player's position the player's velocity the player's money and then the money is also saving its own state and the money could save more than just the data that it's got there if we look right now let's hit play again and let's watch what the money does we hit play come on oh i think i might have hit a breakpoint nope no breakpoint so see like when i restart and i hit load the money doesn't reset to its original rotation right it just keeps spinning at the rotation that it was at so one option that i could have is like go into our money and if i wanted to make the money you know save its rotation i could just implement that right here in the save and in the load i could extend it out so that this money object saved whatever extra data that i want not just its active state it could save like how many times it's been hit what its current health is whatever other type of data that i want just like in the player i can save off this other data that i've got here in the money i can save off whatever i wanted as well all right let's go through saving multiple games now because i think that's where it gets a little bit more interesting so we'll go through the process of adding a couple buttons here and we're going to hook up the buttons so that they can save like game one game two and game three did money stop saving let me hit play i said money stop saving i want to make sure that's not actually actually true and i didn't break it possible that i made it look that way it's possible that i also broke it too so i loaded oh no my money is not interesting let's try this again so let's go through play i'm going to save it and see if my money is saved maybe i did break it and then we'll go through the process of debugging that and fix it so go grab some cash one two three dollars save them and load and when i load it seems okay let's stop playing and play again oh well when i removed auto load uh okay so i think what happened there when the money got set out to zero was that um i removed the loading but enabled the savings so i'd reset it to save it and clear it out but i'm not 100 sure i guess i'll find out soon oh hey thanks for the super chat cyber coder all right let's go through and add in our new buttons so we'll go we want to load game one load game two and then i wanna load game three and four so i'm gonna go into 2d mode hit f and we're just going to take these buttons here and duplicate them i'll take load game one and two collapse these down control d w and move them down a bit ctrl d move them down a bit and then let's start renaming them so this will be saved game two load game two save game three load game three are those in the right positions nope um let's rename those let's move these up here so these are two two and three and three and i want to get these in the same order so they're load save load save load save all right now i'm gonna change the text on them real quick i could of course automate this but i don't think it's worth automating because taking more time to write the code than it will to write the text here and we'll change these ones to say three as well then we just have to hook these buttons up so that they actually pass in what game we want to load and save there we go i've got my save and load buttons and remember these are hooked up to our let's go to the button itself they're hooked up to the game persists save method and the game persists load method so if i go to game persist here open it up what i can do is make it so that my load and save methods just take a game number or a game name i could say something like int game number and then do the same for my save let's save that off and go into unity and then i'll see these as parameters i can just pass this in and then save off a game by simply well you'll see how easy it is we just add some text to our keys and save that off and then you'll see it gets even easier once we stream everything or serialize everything sorry reading chat and everything at the same time as as typing code gets a little bit weird all right so we'll go in here we've got load game one i'm gonna go to my button here and i've got a load method so i'll go to game persist and choose load here which now takes an int it was missing before because that method um well it's changed to change to a new method that requires knit so the first one will load game one and then we'll do save game one so game persist save and save game one of course how you set up your buttons and your ui for this would totally depend on your actual game like do it how whatever way makes the most sense i'm going to choose game persist here oh see i want load and load i'm going to select it on both of them and then do the um numbers in them individually so two and three and then you do the same for the saves we're going to set up that reference go choose save and we'll choose i put in three here and then i click on this one and put in two and i've got them all set up all right so now i can save and load games one two and three or at least i have buttons that do it and they say it to the method but it doesn't actually do the thing so let's make it so that we can actually save the game number now now easiest thing to do or the easiest way to extend this is just to pass in the game number to these methods i can make my save and load methods take a game number do int game number in my interface and then if i do ctrl shift b it's oh i need to stop running and debugging but it should give me back a list of the errors that i've got and the errors are going to be because i've changed the the implementation or the method structure of my save and load so or oh i changed the implementation that i need in the interface and i haven't done it in the method yet it says that they no longer implement the method well it says they don't not no longer because it doesn't know the historical fact that it used to but it's easy for us to fix all we have to do is change the structure now i could hit alt enter and hit implement missing methods and then have it just add them in and it gives me a save and a load with those two parameters but i already know what i need i need this int game number just added as a parameter so i'm just going to cut it let's take it right there ctrl x get it on my clipboard i'm going to delete this stuff out and then we'll just go paste this in as parameters for load and save control shift b should see that those errors are gone why am i still debugging i thought i'd stop that those ones are gone but now this one in money has the same problem so just go add those two parameters and save that off and then now my errors are gone but it doesn't actually save anything specific to the number so if i try it out let's go try it real quick and see what it does i've added buttons i've hooked them up i passed in the parameter but if i go like load two you'll see it still looks like my load one my load one two and three if i go over here and pick up more money let's go pick up some cash and go pick up three more dollars somewhere and i hit save three and then i load one well you see i'm still at the same one and here i'm at the same one because when we save and load right now we're not actually saving them off to separate games we're just passing that in as a parameter so let's make the parameter actually do something in our money it's pretty easy to do we just need to change our key so we'll make our picked up key keep something like game number plus picked up key now how we set these keys up and link them totally depends on your game and your project obviously this is not the prettiest key format but eventually we'll switch to a javascript one so i don't want to give you some specific format for how you should set up all of your keys pick however you want to set them up but just having the game number in there or the game's key the game's name or something is enough to separate them out so that we can load up the one that we want and save the one that we want then i can go into my player and do the same so here i can just do game number plus i'm just going to paste this in front of all of these for now paste paste and paste and save and now i've got it saving off up three different game numbers let's try it out all right so run around grab one dollar i'll save that as game one i'm gonna go grab two more dollars save that as game two and then i'm gonna go grab a couple more and save that as game three now let's load game two load game one load game three one two three one two three so you can see how easy it is to to just make this work right it's actually it's working now we're loading things for different games um just literally by appending a key um oh somebody's talking about versioning saves uh let's let's uh talk let's take a brief pause for a second so one of the issues with this setup um and one of the things to mention in chat is that if we start to add in new versions of our game and we start to upgrade things and change things dramatically our save data could become out of sync right if we start to rename our game objects and we start to add new things and change stuff our our data could come out of sync pretty easily and getting it so that it matches up with an like our newer version of a game matches up with an older save is um well it's kind of a pain right like it it requires work and some forethought it would say his pain but i mean it's not something that's just automatic and that you're just going to get kind of for free what you need to do in those cases are well two different things it's the first is you do want to keep track of the actual version number of your save so i think back to when we'd save like a large character data for um an mmo it would save off all of this data and essentially you'd be surprised but it's essentially a very similar system we're serializing off the data take all of the important data of the character i'm kind of like what we have on the player not so much the money side that that part would go in a different spot we take all of the important data of the player the inventory the request status um all of their stuff that they've done every like achievement that they've ever done take that data serialize it down and then um kind of stamp that with a version number so whenever the game would rev to a point where what you generally do is when the game is changing enough to the point where a old save would cause an issue and needs an upgrade to work in the new loading system would write a simple little upgrade process that would upgrade that data so it would take the data from the previous save and if there was any transformation that needed to be done to it would do that transformation to the data in that in the process or in the game while loading it and then resave the data out in the latest format or the latest version of the game automatically all right so that's um just a real quick note on versioning because you do need to think about it um as your game updates you need to make sure that you're thinking about oh can can i do an upgrade to this okay if i do an update what breaks what changes and how can i make it adapt but it's not an issue and somebody's also asking if this would work well with the binary formatter and yeah that's one of the things i was uh briefly talking about earlier was that when you set the system up when you set it up to do the serialization which is where we're going next um excuse me we've already done a little bit of it but once we started up start doing full serialization of stuff with burping on the camera right um then what you can do is just swap out the serializer so you can swap to a json serializer or binary one use the binary formatter or whatever else you want to persist that data out all right so let's go on to um the next bit of stuff that i want to do which is saving this all off into just one big single javascript file so that we can then send it off to the cloud and maybe save it in a cloud save somewhere else as just a single bit of data that we could do whatever we want with so to do that we need to well start thinking about how we want to actually save our data and come up with a simple data saving or game saving data structure right now we're just kind of ad hoc saving a bunch of stuff so our money saves its own stuff our player saves his own stuff and the game persist method just or may the game persist class or mono behavior the object here is really just saying hey all of you things go do your own stuff now i want to make it so that instead of that they'll just well let the game persist do the serialization itself so get the data from the object and then have it serialize and deserialize back out so i can just kind of pass the data into the thing and then um oh and then get it back so that's that's the plan and that's that's where we're gonna go with it so we'll go through and i'm going to delete out these two unused things we're going to create a new class and i'm going to call this game data so say public class game data and in it i'm going to store off all of the stuff that i want to save so some of the things that i want to save uh money that's my my current amount of money i'm going to make these uh public just going to be some public integers for my money i'm going to make a public vector 3 for my player position i'll make a public vector 3 for my player velocity and again these are just the parameters that i came up with as simple ones to demonstrate you could use whatever things you need to save if you got to save all kinds of other crazy stuff just add them in as parameters as long as they're serializable which reminds me we need to add the serializable attribute here add that serializable attribute at the top of our game data and then um let's see what else do we want to add and we want to add in our money data so i want to save the state of all of my money objects so i'm going to create another class called money data and then this will just store off all of my money objects current states so i'll say public string name and publix bull pool not billboard asset bull um is picked up so those are the two parameters that i have on my money right now on my money let's go take a look at it again really all i save is whether or not it was picked up but let's rename this to was that is that it matches and then i also just need my name so that i've got some sort of a key to link it back to the specific money object i'm going to make this serializable as well and then we'll make that a list of money data's in our game data and we'll call this money datas i cannot spell today capitalize that and make it public and we'll even make it a new list of money datas all right there we go we've got two data classes that we can start to use um money rotation yeah that's something we maybe we'll add that to let's let's let's do it let's say float uh public float y this would just be our y value our y euler angles value so we can change that around and make it spin all right so let's move these into their own files move game data into its own file and move money data into actually i think i'm gonna oh i'm gonna move it to its own file thought about moving it into the game data file but i think i want to leave it in the in its own file all right we'll go back into game persist and then in our save what we're gonna do is set up a game data we'll create a game data object and we'll just persist that thing out all right so where are we at i lost my place i hate a reading chat always gets me mixed alright so in our save we're going to create our game data here so we'll say game data underscore game data equals new game data we'll just give it a new default value and then in our save we'll we say to serialize it so say var json equals jsonutility.2json and we'll serialize out our json and then here we'll do a player prefs and we'll just write that out so we'll say set playerpuffs.setstring let's call this game data and we'll call it game data for our game number so game data plus game number and we'll set the value to our json so the goal here now is to take it so that all of the stuff that we're saving out in all of those different player press keys and all of those different sections and we're going to get them all into this game data object and then we're going to save that object out because then what we can do is just take this we can take this little string here we can send it off to a web service or a cloud service or whatever other thing we can write it into whatever object we want just keep it in one spot it's it's basically our saved game we don't want to have a saved game that's necessarily a ton of different fields saved in a bunch of spots we're just getting a save game that's from well it's one big save game file right we save it as a savegame.dat or whatever you want to call it um and get it all in that one place so we've got it here we're setting it and we're saving it um not super useful yet though because we're not really filling that object out right we need to actually make this game data object have the actual data that we want to have so let's do that now what we can do is say in our save instead of going through and persisting all of these in fact i'm leaving that there so that we can see it but we're going to kind of skip past the saving what we're going to do is get that data but all right let me get my thoughts straight real quick and my words right take a drink and then we'll write the code ah getting all mixed up okay so i want to get my players position into our game data so say game data dot player position equals player dot transform dot position i don't have my player so i'm just going to get it i'll say var player equals find objective type player um in fact i think i should cache that and save that off somewhere but for now i'm just going to grab it and put it into this player and into here so that i can save off the player position and then we had a player velocity and then i could get the velocity data from it too what we're going to do so with the player we're going to do it a little bit different with all the other objects we're going to actually use the interface to get the data back from them but with the player i'm going to do kind of a weird mix of stuff so i don't think i want to go that route so we'll say git component we'll just get the rigid body and we'll get the velocity all right so we've got those two there was one other field right our money so the final field that we'll do is our money so player or let's do that first because the most important right our money is equal to our player dot money so this is going to let us save off our players data here and at least it should give us our player save data into our game data here let's um oh you know what i should have done let's change this up a little bit let's clean this more because the the way that um you know let's make it work and then we'll clean it more we're going to keep improving it right we're going to we need to get to a player data object because that's where this should be the other thing that we need to do once we've got we've got all this player data going into our game data so we can serialize it is get all of our other objects our money objects and they're persisting but i think i'm going to load the player data first no i'm going to save the i'm going to save the money data let's do it so in our saving the money data what we want to do is create a new money data object let's go to our money data script here and this is essentially just an object that's got the name with the state of it and the y position it's going to be saved off in a list on our game data so let's go back to our game persist and for each one of these objects that has data that can save we're going to i read in chat too i gotta stop reading chat while i'm in here so what we're going to do is take the data that we need here and get it get back a money data object and then we're just going to add it into our game data so say gamedata.moneydatas.add and we're going to get back the money data but i don't want to go through all of the um i save state objects here i think what i want to do is just go through the money objects here and persist those out instead so we're going to do that we're going to go through money objects because there's there's more that we can do here to abstract it out but i feel like if i abstract it without having another explanation there or example it feels it's gonna over complicate it and make it a little bit too confusing not make as much sense so i'm gonna just take the persist here which is let's rename this to money and then we'll go we'll take our money dot data and we're just going to add the data from our money object into our money data's object now we're going to generate a money data so we'll go in here create a get only property here and this is going to have a private setter and a public getter what we're going to do is move down the state of this into this money data object or we could just um return back out a new money data object based on the state of it so let's let's do that let's start with um let's start with just returning back oh i'm trying to think about one if i want to go through the process of setting the state of it yeah let's do that so in here let's see what we'll do is when we pick it up we'll say data dot was picked up equals true and then in our update method we're going to expand this out we're going to say data dot y equals transform.rotation euler angles dot y so we're going to cache the y every frame right now into that data object and we're going to cache in our state of it whenever we pick it up i think the y caching we could probably just do on a save but for now i just want to add it in the update because theoretically we put whatever type of stuff is going to change every frame we might want to put in there and pass that down into the data right now it's just the y position rotating but i think that um we could put any type of thing in there so we've got our positions going in our data is getting updated um we want to set this to a new money data and it should not be getting reset so add a semicolon there let's see we need anything else nope okay so in our save method what do we want to do oh right pretty much nothing right because no longer do i need to actually save stuff i just need to ask to get the data back or return the data back from our money data and have my game persist method save it instead so maybe the save method can go away in fact that's what we're going to do pretty soon we're going to remove this from our interface but what about our load method our load method needs to actually be able to load in some data maybe from a money data object instead of from a game number because i don't want this to pull data in from the um from the player press or read data or do any serialization i want to take that data object and then set its state based on that data object so instead of taking a game number in here let's make it load off of a money data and then in here what we'll do is say our money data equals money data oh i go our underscore money data or our our local get my words right comment this out our instance of money data on this class the one that had a private setter where is it wait do i have it on here oh i named it data that's why i got myself confused we're going to rename this money data all right that's what happens when i change my naming schemes up the money data money data so our money data is going to be set to the one that we pass in so what we're essentially doing is saying hey when we load this take this data object that was serialized out from before pass that in use that as your new object the last thing that we need to do is just set our active state based on that money data's active state and set our rotation based on it so i'll take this line move it up right here set it to active based on our money data the upper case one really they're both the same object so it doesn't matter but we want to do it based on the was picked up and we want the inverse of that so not was picked up so it'll be active if it wasn't picked up this the active if it wasn't and then the other thing we want to do is set our rotation so we say transform dot local rotation no transform dot rotation equals quaternion dot euler and we'll pass in zero comma zero oh zero comma money data dot y there we go get em right and then zero so that's going to restore our rotations now we're restoring our rotation and our save method doesn't really need to do anything in fact i can get rid of this interface completely here because our money is now kind of saving and it's on its own um in its own way again we could add an interface that saves off of something a little bit more generic when we have data that's going to save this persistent like we have pickable pickupable objects could be an interface instead of money data just be objects that are liftable or pickupable or grab-able or whatever you want to call the interface for it we don't necessarily have to reference the money data class but it does need to be a little bit more specific in the type of data that it's serializing or we can make it an eye serialized data or an isave data that takes in a type and use some generic types i don't want to get into that yet because i feel like i get into generics with interfaces i'm going to over complicate it for a lot of people who are already kind of struggling to follow along but if you're comfortable with interfaces you could definitely have an i save state of type money data and then implement that and then have that as your interface as well so let's go through fixing up our interface implementation or our calls to it do we need to do anything for that let's go take a look in our game persist right now we're just looping through all of the monies and saving those that seems good and then in our load we just need to do the same so we're going to change this from looping through mono behaviors to looping through money we're going to get including the active ones and then in all of them what do we want to do well we load them we just want to say oh let's rename this to money we want money dot load and we want it to load our game money data so we'll say money data now we need to get that money data out right so let's take a look at it real quick we save our money data by adding them all into this money data's object right and then we serialize that out so when i deserialize it i should expect to get back another list of money datas and then just go through that list of money data link them up to the objects and then reset the data so let's try it out when i do to do that i'm going to need to load my let's zoom out so i'm not scrolling up and down here i'm going to need to load my data from this game data or from this string right here into a game data object and then loop through them so we'll say bar game data or underscore game data equals json utility dot from json type game data and then we need the string and here let's put in the word json and we'll make a string for that create a local variable string json equals let's zoom in a bit so you can see it again it's going to be equal to player prefs dot get string and then we'll load our string right here game data plus game number and again we don't have to read this from player prefs we could read this from a file from a remote data store or whatever else we want it doesn't matter player press is just the easiest that works everywhere the downsides to player preps are pretty well known if you don't know about them you should look them up biggest ones are like size limitations and easy accessibility but right now we're just going to save them into there because it doesn't really matter the process is exactly the same so we've got our json text there we're going to deserialize it into a game data object and then we're going to loop through all of our money objects here see if we have a game data object that matches that or a money data object that matches for that game data so we'll say bar money data equals gamedata.moneydatas.first or default and we're just going to use a link statement here we had a ton of things this would be i would say less than efficient we might want to profile it but for this case it's not going to matter at all so if you're worried about link just remember you can profile it and fix it if you need to but in our case i don't think it's going to matter so we're going to do a link statement where we're going to find the first one whose name matches our money's name so here we're comparing the money data object's name to the game object money's name we're going to find the first one that matches so that we find the matching one they're just keyed off of the names and then we're going to tell that money object this is the actual game object to load the data from it let's go take a look at that real quick one more time that name field right here that's this one one thing you might have noticed though if you've been following along i didn't set the name on our money data when we save it so if we go down into our save here and we look at our money.money data so we go let's go look at it right here this money data object that gets created it never actually gets its data um saved so it never gets or it never gets its name saved off to match so what i need to do is make sure that in our awake or sometime in our process or in our lifetime we make the money data's name match our name now we could do that um in our start method we could do it in our load method we could do it even in a save method what i'm going to do is add it into our start so add a private start and i'll just say money data dot name equals gameobject.name and i'm going to turn that just in an expressionbody method and i'm going to copy that and i'm going to put that into our load method as well because well i don't need to do it in a load method because it's only going to load if they match so i don't need to okay i think we're good there we can go back let's see save everything off i think if i do a build and hit play we should be good to go and we should be saving and loading multiple games um all into this one file give it a go i'm probably gonna run into an error or two as my guess though coding things live that tends to happen all right so run over here go grab one money two monies hit the save button no errors occurred yet okay we'll go back over here hit load okay my money reappeared my money reloaded and it's reloading in its positions so that's good um my my player's not reloading but my money is reloading in its positions let's go grab some more money save game two and see if it keeps my other positions save game two so i load one they're in that position load two hey so my money and uh and that stuff is working great the only issue now is that my player is not persisting properly so let's make the player persist properly oh the reason he's not persisting is he just doesn't load properly so the game data right here is getting saved off and setting the player's position and velocity we don't actually reload them in the load method though let's go through that process real quick take these right here just these little couple lines actually let's cache the player here so i'm going to take this line right here the game persist one and i'm going to cache this player off in our away because i'm going to reference it again somewhere so add a underscore player generate a field for it and then turn this into an expression body method up go down here expression body get rid of the private keywords i'm going to get rid of all these private keywords too because i don't ah the wrong hotkey just because i don't need them and i like to shrink things up a little bit all right so now we've got our player saved off and then in here we'll save the players money the position and velocity into the game data and then we'll load those back in in our load method now that i've cached it so we'll go up here after we load all of the money data we'll say player dot transform dot position equals game data dot player position and then copy and do the same for our rigid body get component rigid body now i think in in again in an ideal situation you don't want to be grabbing the rigid body component you probably want to be setting something on the player and that's i think what we'll do next maybe we'll pass in a player data pass that into the player let that thing load and then we'll go into some remote saving and loading so we'll do player dot money equals game data dot money all right so save that off control shift b and oh yeah you can see we've already got an error here the error if i hit f12 is that money is privately settable it's not supposed to be set from outside the player class mostly to prevent accidental misuse of it and now this change that i've made kind of exposes or requires me to open up my player and make it ugly and make it bad i don't like it i'm going to do it anyway just for a second and then we're going to go back and change it so we'll change it we'll make it public by removing the private keyword around that money setter we'll go into unity make sure that it works and then we'll go back to setting it private and see how we can kind of clean that back up a little bit more all right so stop playing play again all right we'll run around grab one money two money save grab three money for money save and we'll grab five monies and save load one load two load three i think it's looking good it's saving off our data now into this one file let's go take a look at what that file looks like or what that json data looks like so i'm gonna hit f5 in here and then this save method actually isn't even getting called anymore so i could probably get rid of that let's go into our game persist though and let's take a look at what the data actually looks like when we save it off so right here is at the end of our save right after we've converted the data over to json and i'll hit save and if we look at it right here let's just click on it and get it up here in an editor move my mouse over very slowly i'm going to copy this onto the clipboard we're just going to take a quick peek at what this data looks like okay so there we go got the data on there let's zoom this out ah okay let's let's find a json formatter real quick two seconds i'm gonna paste this into like a json formatter online real quick so you can see what it looks what it looks like kind of in a neater format all right here we go a json formatter and validator oh that didn't work full screen is way too big um but essentially the way that it works or the way that this file is set up kind of see it here is that we've got our root level object and that's what this opening braces so when you're looking at your json data and you're trying to figure out what it is what i usually recommend is copy it into something that will format it well um writer can do it other editors can do it this tool has um this just like a little web page to let you paste it into there's tons of different ways to do it i just want to show that like you don't have to use writer to do it or anything else you can use whatever you find you whatever you can find to see your data and actually view it but what it actually looks like is you get this object and you can kind of collapse them down and underneath it it'll have a key and a value for everything on the object if we go look at our actual data object here let's go look at the game data object you see that it's got money player position player velocity and money data and that's what we see here we have money player position player velocity and money data all in that order so these are the fields that we have on that object player position expands out because it's an object and it has its own field so that has the x y and z same for the velocity and then money data's because it's an array has these little square braces around it so all of the data inside money data is going to be in the square braces meaning this is an array or a collection of things um and then these are the actual objects or the entries of the objects in there so this is a way to just view the data see what it looks like and see what your actual save stuff is showing and here you'll see that actually we've got an issue we look at this but we've got a lot of money objects here um and we've got multiple right so if i look here i've got money six i think i've got a money one i saw money six money one money one money six so what what's happening what's causing this well if you think about it for a moment money data is a list of things right it's a list of data objects and when we save let's go to the code where we save right here we add to this list now when we create money datas we're loading it right we're loading it from another game and then we're adding in these new money datas when we save and then uh well obviously we're ending up in a situation where we have a ton of money data objects out there because we're just adding new ones new ones new ones new ones so what we need to do is manage this so that we either clear out the money data and just re-add them or that we keep track of them and bind them up at the start now i don't want to go into the binding up at the start because i feel like it's going to get a little too advanced it's going to take a couple hours to go through that but we can at the very least just clear out this list go through here money data is not clear and save so this should fix that data so that we don't end up with multiple things in our javascript let's go take a look at it real quick and see if that fixed it so and the other way by the way just for anybody who's curious the thing that i i don't want to dive into right now just because i feel like it'll be a lot of overkills take a long time is that we could set up these money data objects and then in a bootstrapper essentially bind them up to the actual game objects that they link to instead of getting them from the objects so we essentially pass them in have them work with their data in that object and then we always have a reference to that object instead of having to get it back out when we save it so we essentially be keeping all of our game data in one spot in memory and just constantly keeping it there and referencing it there that would be um again the more advanced way that we're not going to get into today maybe we'll do that some other time though all right so go over here i've got my two objects i'm gonna save one go over here save two i'm gonna load one and then i'm gonna go over here and save three i'm gonna pick up these objects again and then do a save three and then i'm gonna look at that json data see if it looks clear and then we'll uh go on to the next thing and talk a little bit about newton's soft and json serialization too i'm gonna hit f5 real quick actually you know what i'm gonna do yeah oh i hit a five i was thinking i would just add a field to it and make it show up but i already i'm already in debug mode i've already hit f5 and attached so let's go through it all right so here we are we've got our json data here and if i go over to the right and hit view and copy this out and just paste this into that page again that i had go right here paste process bam now i've got money data so i've got money seven six five four three two one and a zero basically i don't have multiple copies of my money data's anymore because we cleared that out important to just take a look at your json data i think when you're saving stuff out too so when you're saving and serializing things and loading things test it make sure that it works and ideally set up a unit tested scenario for it so that you can actually make sure that everything works constantly as you change stuff but test it at the very least test that when you make any big changes to it test it look at the data make sure that it actually looks valid on top of working you don't end up with like a giant one gigabyte save file that you're not actually using because it's just copies and copies and copies of the data and i have seen stuff like that before where things get saved many times like that and it just grows exponentially every time you save it it doubles the size and yeah it gets big and bad quick right all right so let's stop playing and um there's a little bit of talk about the serialization stuff so right now we're just using the json utility serializer that's the built-in one and it lets you serialize a lot of things but it is by far not the most powerful serializer the newtonsoft one the one that's mentioned in chat and the one that a lot of people recommend all the time the one that i usually use is um a lot better at catching things and serializing things it'll automatically serialize a lot of things that the um the built-in one won't do things like dictionaries i believe newton's office dictionaries of all kinds of things but it does um it's been a while since i've had to serialize one though uh but sorry i think thinking in my head real quick anyway it'll serialize a lot of other things like properties and things that you wouldn't serialize with the built-in json utility so if you're interested in serialization stuff and you want to get into serializing other objects and finding that json utility is an issue you can always grab the newton soft one there's a free version of it and i think there's um some assets in the asset store to grab it too there may even be a package in the package manager to grab it in now i'm not completely sure um but you can definitely switch it out but one other option that you have let's let's go past player prefs for a second so right now we're saving this data off into json and i said that you should check this data and all that but i haven't actually shown you how to save it off into a file it's extremely easy to save this stuff into a file on your local file system and then reload that too so let me show you how to do that if we wanted to save our json data instead of into a player pref string into like a text file or a binary file we can use the stream writer so what i can do is say using and then open parentheses streamwriter streamwriter equals new streamwriter and it's going to want to add some using statement so i hit alt enter add my missing references which i think was a system.io reference yep okay and then we're going to go down and the streamwriter takes in some parameters the parameter that we're going to use or the optional parameter setup that we're going to use is just the path to the file name so if i just put in something like save game uh game number dot json that's going to give us a file named save game whatever one two or three dot json now i'll do the open parenthesis at the end of it i need two closing braces here by the way because we're using this using statement which if you're not familiar with it is part of the well it gives you a way to implement the eye disposable interface kind of automatically and cleanly there's a new way to do this in c sharp eight we're not going to jump into that or maybe with nine but we're not going to jump into that what we're going to do is use the using setup for it so that it automatically cleans up the setup or the uh the references or the handles to the file the reason that we write it like this is so that when it leaves the scope of this it will clear up the references to it by calling the dispose method on the stream writer it's essentially like a way of writing things that implement i disposable to minimize the likelihood of screwing them up if you get an exception or you bail out or something else essentially if you leave the context it will clear up the file and not leave it locked if you've ever had a file that's like sitting there locked that you can't access it's because somebody didn't dispose of their their lock on it properly and using statements like this will help prevent that so we've got our stream writer here and what we want to do is say streamwriter.write and pass in our json yep that was it all right that's going to write out our data to a file i'm going to save that off or i'm going to comment out my set string i'm going to take this little bit here copy it go into my load and right here where we do the um get string part i'll say using streamwriter blah blah blah or yeah streamwriter this i'm gonna change this to reader instead of writer and we'll change this one to reader stream reader and we'll change this side to reader and then here we'll say read and we'll say json equals that so this is going oh not read um read to end there we go that'll read the whole file the read was just gonna read uh i think one character for one byte so this is going to get us our json data and now i need to bring all of this part of my load method into the scope of my using statement so just take this brace here delete it and move it down here to the end and now it's auto formatted and then i need to comment out this little line right here on 20 because i already have my json data fix that comment there i already have my json data right here on line 17. so now i'm reading it from a file and saving it off to a file let's save it try it out see what it looks like see what the file looks like and see if it all works so stop playing and we'll play one more time all right and then we'll run around go grab some money got two dollars i'll hit save one and then let's go look at our file system so i'm going to right click here in my in my project view hit show and explorer go up to save and load and look at here in my folder i've got a savegame1.json file i'll right click and let's hit open with and let's just open it in uh i guess we'll just use notepad for now i don't know well let's open it in writer that didn't work out very well i need to get the formatter set up for json in here i already set it up and i'm not sure what the hotkeys are now all right anyway here's our json data saved off so we've got our json in this text file here and if i go hit save to go back into our file explorer see i now have a saved game too and then this would allow me to give players like literally a save file that they could save off share with friends whatever save off that you know whatever some cash or share it online i don't know what you want to do with the save file you can save it however you want or they could go in and modify it of course we can also binary serialize it so if we want to go away from um using the json we could switch away from json utility to using the binary formatter and then save that off as data or we could compress this or base64 encode it is another option that we have to hide what this json data looks like in that text file if we wanted to i generally prefer to just write it in text so that i can read it and then at the end start to format it into either something that's um a lot of time i'll just base64 encode it and then decode it because that's enough for 99.9 of the people who are going to try to hack my game but if it's something super important then i'll um put more work into it and actually encrypt the data it's something where it's going to impact other players in my experience though 99 of games if people hack their local data it doesn't impact anybody else nobody cares and it doesn't really matter so i don't worry too much about it just try to obfuscate it enough with some a64 encoding or something in fact um i don't know if we should go through that like doing some encoding in there let's find the uh would use let's see where are we at right here so here's our data our json data what we could do is something like um in our save let me show you real quick what it looks like when we base 64 encode data so we've got our json data let's say var e64 equals convert dot 2 base 64 string json and then we could save this out let's write this instead of our json data wait a minute what am i thinking i'm getting myself mixed up here no i need to use my converter my encoder um encoding sorry i get getting myself dot all right i'm getting myself what is it it's uh okay give me two seconds to remember this real quick and we can format for that again it's system. ah there it is sorry everybody i just getting myself mixed up um in my text i'm just going to yank some base64 encoding code code real quick um off of one of my other project or action mail see i want the sorry system.txt dot encoding dot utf8 dot i forget sorry i'm hot and yeah thank you somebody pasted the code in there that's what i'm looking for getting myself mixed up oh did i do encoder instead of encoding okay this is a downside to uh live streaming for too long and get mixed up and overheated and confused all right let's paste this in so plain text bytes gets us our json there we go and then this is going to far be 64 is going to give us our base 64 code so what essentially what happens here and thank you um kevin thank you for posting that in there i missed a step in here so essentially what happens is we take our json data that data that i was showing you a little while ago with the braces and all that stuff and we converted into a byte array using the text.encoding.utf8.getbytes this was the step i was just totally spacing on so this converts it into a byte array and then that byte array gets turned into a string so essentially turning it into binary data and then turning that binary data into a string again so that we can write it out as text again we could also take this binary data by the way just plain text bytes and just save that out as actual data i want to show you what a base 64 string looks like because i think people see them all the time and they don't recognize it don't know what it is they don't know that they can just decode it as well so let's go through i'm going to save it real quick we'll look at the file the text of it real quick and then we'll do the decoding part of it all right so we hit play and go run around we'll go grab a dollar or two we'll hit save to um let's hit save three and then let's go look at the file for save three so right click on it open i'm gonna just open this in uh oh what did it open in writer so here it is it's open in writer and you can see the file here so this is my save game three and it says e y j n blah blah blah blah and it ends in an equal sign you'll recognize that all of them will end in an equal sign if you have these base 64 encoded text things so let's go figure it out let's go figure out how we can load that back in if we want to load it we'll go back to our game persist and then take um it's going to be instead of get bytes it's going to be get text and we'll pass in the byte array and we're going to do from base64 string instead of 2b64 string let's zoom this out a little bit um let's go up here to the part where we're in fact i'm going to move this i'm going to take this method here take it and move it up here above load so just so that the text for our stuff is right above it get rid of that we'll collapse this down and collapse that so in our reading data we're reading it all in right here and this is no longer going to be json data this is going to be b64 data i'm going to rename this to b64 and then we're going to say string um or no we want to do a character array first so we want to do system dot convert dot from base 64 string we're taking our b64 this is going to give us back our bytes our plain text bytes as it's defined up there which is also just a byte or i might when am i hitting the wrong key again i kept hitting backspace instead of equals so this is going to give us our plain text bytes array which is a byte array or i could also type this as byte array like this or just var and then we want to convert this byte array into our json text and to do that we use our let's see add a new line here we'll say string json equals and we want to use system.txt.encoding there we go utf-8 dot get string and we'll pass in our bytes we pass in the bytes here or the byte array and then that will give us back our text so this is essentially just a real easy easy to use lightweight way to semi encrypt or encode the data it's definitely not hidden because if you know you can do this you can just take that text and base64 decode it let's go try it out and make sure that it works so all right so we're in and we load game three and yep there we go it worked but if i load game two it doesn't work anymore because the data no longer matches only game three works one and two are both broken but i can go in here and resave over them and now saves one and two and two and three work at least i haven't fixed one one's still invalid it's got bad data all right um i went through a lot of things so far i think the the last thing that i really wanted to get into was saving remotely so doing like playfab setup or like an an online remote save so you can save it to the cloud right i assume everybody's still interested in that so we'll go a little bit longer and do that part now you don't mind hitting the thumbs up button though while we do that i definitely appreciate it and then we'll get into um the playfab process it's been a little while though so i need to pull up my actual playfab object here or my playfab project you know maybe i'll just go grab let me open up that project that i had open and show it let's see where it was this one right here so the playfab setup if you haven't used playfab by the way and you're new to it or you haven't used any cloud saving setup let me show you what it looks like um i'm going to pull up the ui it's free it's pretty easy to use and i think microsoft bought them or partnered with them or something so it's gonna be free i think for quite a while or at least available as an option for a while so let's go through the process real quick of of how to use this thing so if you're on the the play fab webpage right you go to let's see go to playfab first so you can sign up here and essentially it gives you a way to do a lot of different things um i'm not necessarily like pushing that you should definitely use playfab over any of the alternatives um i don't use any of them for anything that i'm doing production-wise right now but if you're looking at them playfab is one that gets recommended a lot and the ui or the whole infrastructure and the interface was really easy to use and integrate so if you're interested in one and you're not sure what to use i would definitely give it a try so the main thing that i want to use from this one is just saving off um player data so essentially data management is one of the the many different things um that we want that we can do with it and it's the one thing that i actually care about in fact it's not even really that one it's really this one cross network identity and data or we're gonna have player specific data and um to set it up all i did was sign up a new account and then create an app so i went in and then hit new game or i think i hit new studio and then new game and then created a game in here um i want to go through my open project and show what that looks like real quick and then um maybe i'll go through the process of setting it up but i'm kind of running out of breath right now so let's just show how you use it and how you could integrate this existing stuff with what we've already done and see just how easy it is so we've got here this project let me load up my sample scene and make sure that it works so for this project all i've done is load in the um the player of the the playfab sdk so i grabbed the playfab sdk pulled it in and made a single script here a playfab login script let's make it open up a new window here that allows us to see what it does so my playfab login script doesn't do much this was me kind of experimenting with playfab seeing how it works how you deal with a login and how you save a little bit of data to it it's actually extremely freaking simple so the way that this thing works is um well let's see let's go into unity real quick and pull it up i think if i show the code without showing the ui and stuff and talking about it might be a little bit more confusing so hit play and then we'll look at the elements real quick and then talk about how it all works so let's see pause i don't want to be in maximize mode uncheck maximize there we go okay so by default i'm already logged in as jwyman1 so it logged me in as my last user but i also gave myself the ability to register by putting in the username a password and an email address i'm going to do that right now i'm going to say this is a live json ken uh my password will be i don't know it doesn't really matter and my email plus live 10 gmail.com so i can register my account and then i can save some data off so when i've done that when i register the account let's go see what it does so i'm going to go look at my button here i think this is my register button right yep it calls my playfab login.register method i'm going to go look at that real quick see how that works and how we register an account in playfab so assuming i've got my sdk set up setting up the sdk i don't want to run through it right now but it was essentially import the package put in your codes that it gave you so when you create your project it'll give you some codes for your project you put those in that's it sdk works you don't have to do anything else you do however need to make calls to do like registration and login and all that stuff if you want to do it not use their example scenes so to register we create a register request when i hit that button we create a register prefab or playfab user request which just takes the username the password and the email as the three parameters and i'm putting those in using the syntax right here is going to set the properties on them and then we call playfab client api register playfab user pass in that registration message or that request right there and then some callbacks for when we succeed or fail if we succeed which is the only case that i'm going to deal with right now oh in either case we save the password in the email that's how we're logging back in so if we succeed we say hey that we registered and we saved the username as well the last thing that we do is log in and that happens on start so that's why when i registered i wasn't actually logged in because my code wasn't quite smart enough it only does the register saves it off in a username and then in our start method i look to see if i have my username and password saved off if i have them both here so if they're not null it's a terribly written if statement then we call and generate a login request so create a new login request call playfab client api log in with playfab and pass in that request and then we get a login success message or event and a login failure method the final bit of things the part where we would hook all of this up so the part that makes it all work is we've got a um button down here let's go back into unity button down here to save our data and to load some data so if you look here we have this get user data method or this getuser data call that we're calling whenever we successfully log in if i hit f12 and go to it and see what it actually does it sends another request so the way that all of these apis work is you send a request and you're going to get a call back you're going to get some event back so you might have noticed that with the other ones we had events that we sent off and some success and failure events that we get back i'm doing the same thing here but here i'm just doing it without methods and we're doing a lambda statement instead so instead of passing in these as methods for parameters they're just passed in as lambdas that are kind of built kind of or there are there are parameters of this thing a little bit harder to read but essentially what we're doing is saying we'll get the user data and if we get a success so this one is the success we'll run this code right here and this code will say if the data contains a level key then set our text to whatever that level key is now this level could be whatever we want to call it we call it um json data because that's what it is we could call it game one data because it could be game one data or game two data or anything else and then we just load that in now the part where we save it the final piece of the puzzle is this little save button if i go to it and select it i'm pretty sure it's just calling a save method here in playfab yeah it's calling save user data which again just generates an update user request so we created a new request these are again the playfab objects these are playfab objects and you'll see this exact code in their example api if you go through their api you'll see it that they exactly how to do this as well you see all the code for it but what we do here is we send an update user data request and we pass in the data as a dictionary of key value pairs so what we would do here is say json or game data one or level one or whatever we want to call it and then pass in that json data instead of the text that's in my text box and that's pretty much it if we do that we can get the data to and from playfab and then load and save it um unfortunately i'm running out of breath and it's getting loud outside and i've got to take a little kid on a drive in just a minute so i think i'm going to wrap this up in just a second but then what i'm gonna do next is turn this into a full-fledged um tutorial so like step by step of how to do the persistent stuff kind of well edited cut down trimmed to the specific points um and then i think i'll add in the playfab step and the playfab setup as kind of the last step in there step by step on that too so if you're interested in that stuff make sure that you're subscribed and you hit the like button or thumbs up button or just leave a comment below because if this thing is really popular then it means i should definitely be doing um lots of persistent stuff but i sent out a poll on persistence things let me switch camera view and it was by far like the most popular thing that i asked about so i really wanted to at least get into it get something out today go through the process real quick and then give you guys all something that you can really use um again afterwards so we'll go step by step on it um this will also be available for you yeah so you'll be able to go through and watch it again as soon as it's done processing or kind of skip through stuff just make sure that you hit subscribe like share and all that stuff um i definitely appreciate it and i'm almost out of stuff to say i did put a link up for the hoodies on the game.courses site if you're interested in those you can check them out um and if you have questions about this persistent stuff just shoot me an email because if there's stuff that i missed or was confusing it would be helpful in the new video that i'm going to do for this so i'm going to go through the whole process and if you've got uh yeah if you have thoughts or just feedback or ideas or questions that you think would be useful in there let me know just send them to me an email and i'll um i'll read through them and try to get back to you on that too and get in there all right thanks again everybody for coming out um i'm exhausted but had a great time and uh had a blast with this i hope everybody enjoyed it and learned something useful figuring out some some cool game dev stuff and we'll do a lot more of these i do another one next week and i'll see you all soon
Info
Channel: Jason Weimann
Views: 21,837
Rating: undefined out of 5
Keywords:
Id: 4h2CvULKqic
Channel Id: undefined
Length: 144min 54sec (8694 seconds)
Published: Sun Jan 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.