Unity Tutorial: Preserving Data between Scene Loading/Switching

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this week's episodes were brought to you by the generous support of Andrew Henninger so welcome to this unity program tutorial where we are going to talk about sharing data between scenes because you can change scenes in unity right so let's say we go ahead and we make a couple of scenes so we're going to save this scene as um I don't know let's imagine we're making game like Super Mario World right or Super Mario Brothers 3 or whatever we have sort of an overworld and then you have individual levels so we'll have one scene this is like I don't know this is a this is our main menu right and then we have another scene called um overworld and then we have another scene save scene as um which is like level 1-1 okay something like that and then someone and so forth it's very easy to imagine that sort of situation school and IRC is open other people - oh uh the twitch chat is actually it's always been an IRC based chat um and some people that collect directly to it with an IRC client as opposed to the web that's all people are talking about over dares okay so imagine we've got this sort of scenario right and it's easy to imagine like okay in in a game like Super Mario or something like that we have lives we have score we have uh perhaps like a progression that we're trying to keep track of you know like what levels have you defeated what have you unlocked that sort of thing which bosses have you killed so on and so forth there's a lot of different things that you might want to track and normally when you switch from one scene to another all objects get destroyed right so let's say um over here in in the overworld I have some sort of object I'm going to create an empty on it and hey we got a tip from garden of sinners uh we're gonna Bowl on a paint garlotte sinners yay - booze inspired programming okay no booze yet not for me you guys have fun do what you want um but I will be focusing once we get to the multiplayer tf2 you then often there's a little bit of something to make that a little bit more silly um da da da yes okay so we're gonna create an object in here we're gonna call it something like game manager game status game status let's call it a game stat this object okay and we're going to add a component to it and I'm going to create a new script called game status obviously I could have created the script in I'm pointing at the screen because that helps so much right we could have added the script here in the project by going create c-sharp script or you can as a shortcut just sort of fill it in there but in any case we end up with a script called game status and it's attached to our object called game status over there Robert Jeb with the raised sub of course rogachev also really helpful at steering ships in Kerbal space program nepeta okay so we've got our script open bigan this for the stream looks pretty big right so standard sort of monobehaviour thing and let's let's imagine that we've got something like um you know uh we'll make it public for the sake of argument so that we can see it easier in the inspector I mean we could also use a serializable field let's forget let's say we've got something like um num Lodge which starts at no.3 and public and score which starts at 0 right we have some values on this is this is how we keep track of the status of our game overall stuff like that we have extra data structures so we have this and it's great so right now we are in what scene we are in our over old scene so let's actually to make it a little easier to remember let's just add a UI element here for text and um but edit a data I am going to yeah just Center the text and say write over world just so that we remember where we are we're going to Center it I'm gonna make the font nice and big maybe that's too big there we go like that um oh there you go got a stretch the thing I'm just feeling filling the screen with this that we can see what's going on and let's make that bright white and actually let's change our camera background to be black okay so we're on the overworld scene right now very clear so now and we've got this game status and we're keeping track of the stats but now we load level one and two old level one in the game I guess we could actually go and implement this that's probably good for example so let's add a button now normally how do you load level one well in something like Super Mario you make sure your characters walk to over to the level one and then you click you know whatever button it is on your this particular game so you hit X or a or whatever it is and it loads level 1-1 for us for simplicity we're just going to create a button so in our canvas here I'm going to create another UI element here it's going to be a boo tone and I'm just going to label this to say load level 1-1 okay and I'm going to grab this button and just dunno put it down the bottom left corner doesn't matter where it is but we have a button on screen and when we click this button it's going to load level 1-1 is the idea so to do that what are we going to do well let's go back to game status may as well add it there we could add the sort of function anywhere um there we are let's make a function who's that roller rocker with the resub 1/2 year thank you so very much void umm load let's make a function called load scene that takes a string with a scene name like that and to load a scene um it used to be you would go application at low level but now you have to um using Unity engine dot scene management which lets us do a scene manager dot load scene which takes either index or a string and we'll just pass it the scene name like that so now that we have this public function here to make our button work and we're not going to go into the details of how you know the the UI canvas II stuff basically your button has a little field here when the button gets clicked it can let something know that the button has been clicked so we're going to add an entry to that it needs an object so we're going to point game status to it and then from the game status object we're going to choose the game status script find the load scene script there the load scene function which takes one parameter over here and we can tell it that the string is going to load is level 1 - 1 so if we hit play now and if we hit the butoh I just say we're going to get an error the reason we're going to get an error is because you have to tell unity all the scenes that are loadable and we do that from going to file build settings I mean it tells us right there in the air and we're going to make sure that all of our scenes are in there so main menu overworld and level 1 the very first thing in this list is the thing that gets loaded automatically the program starts so that's a sort of order we can do things in so now if we hit play and we push the boot oh there we go and you seen has been loaded we can see at the top of the window here that we are in scene 1 - 1 we can make it a little bit more clear if we go and manually load level 1 - 1 here and again we'll create a piece of text we're going to make it fill the screen and be centered and centered and be larger font and be that way for this one we're going to make it white text I know that's what we did last time let's make this text black and we'll make the camera background white make it really really obvious we're going to change the text to say scene oops not here that we change it it's in here scene 1 - 1 - 1 okay so now again if I go back to the overworld I hit play now when we hit the button it should load scene 1 1 and it does and it's very obvious that's exactly what's going on cool and infinite egg thanks for the resub 19 months as a prime number of months mm-hmm did it do mcfine ever seen me here on twitch before I stream twice a week every week unless I'm you know out of the country or something like that every Saturday every Wednesday doo-doo-doo Thank You mace for putting up this river stream schedule okay so we got some ability to switch scenes now let's um most of these games have a little sort of UI pop up at the top that tell you what your current source core and lines are right so excuse me let's make um I'm gonna group this into into an empty we could make a panel but there's not a real need to do that I mean I guess that would be fine sure you know what just for visually speaking let's make a panel a panel is just a UI element that has a sprite on it and that by default is set to be semi-transparent so we're going to take that we're going to make sure it is glued to the top and stretched from left to right and we're going to give it a height of I don't know 50 pixels there so we have a panel top of the screen then inside of that I'm going to add a text over here that says something like score you know that ended up just some numbers is placeholder and lives and again added at it as a placeholder over here we're going to make the font white um I'll make the panel a little bit I'll make the panel make sure it's a darker color it will help the text pop no matter what um and I don't know will make the font a little bit bigger so that it's a book that's too big so it's a little easier to see and you out text has to be we have to tell it to fill the entire panel and will then tell it to be centered and in the middle there we go so that's our GUI very beautiful we're going to add so this panel is called I don't know the score panel or something like that and it's got text inside of it and I'm just going to make a new script okay I'll add it this way now we're going to create a c-sharp script and this is something like score panel updater and I'm going to attach this script to the text and the scripts only job is going to be to ask the game status to tell us what our current score is at that score and lies and it's going to update the text that's it so I mean there's a bunch of different ways to do it what we're going to do is on every update on every frame we're going to say let's find the game up status so we're going to do this naively first we're going to do something like a game object so we're going to get a game object hey sloppy thanks for the sub in fact I'm pretty sure that's a resub I think you've been sub before thank you very much sloppy so we're gonna grab a game object and again this is you know it this is a relatively slow bad way to grab the game status okay so we're going to start with this though we ran find an object called game status and then from that game object we want to grab specifically the game status we're going to call GS we can go geo getcomponent game status okay so it's the game status script that we actually care about and here we should check to make sure that these things get found in fact let's put in a check if geo is equal to null this means we failed to find something called game status so we're going to go debug log error fail to find an object named game status like that and then we'll just bail right away um and actually to stop it from spanning the the log over and over and over and over again what I'm going to do is enable there we go equals false I'm going to turn the script off this this score panel updater if it fails once it's just going to turn itself off so it doesn't just keep spamming the log and keep the same but other net what we're going to do is we're gonna grab that and we're gonna set we have a component we actually have to say using unity engine dot UI to say that we are using UI classes and objects and things like that we have a component on ourselves called text which has a property called text and if we set that that's going to be the words that show up up here so what we're going to do is we're going to set it to say something like score : + GS dot score + lives : and the space + GS lives num lives and there we go so every frame it's going to run an update itself let's hit play and see if that works it should set our score to zero and our lives to three and it does and if I were to click on game status because those uh those properties are are public and exposed to the serializer I can put type in new things over here there we go we gave ourselves a bunch of bullets good excellent wonderful so that works great now if we hit the button well obviously we don't have anything up there so we're like ah we want the user interface to also show up in this scene cool easiest way to do that I would say is take week let's say we take the score panel that we just we put all this work into designing this beautiful score panel at top of the screen shut up it's beautiful I'm gonna turn into a prefab down here so then when I go into level one one we already have a canvas let me just drop the score panel prefab inside of this canvas there we go it shows up there and all right it's not necessarily the most legible I think maybe I'll make my camera background let's let us give it a little bit of color after all and darken it a bit there we go so it still stands out those you see so now we have the score panel in the game cool so let's go back to the overworld let's hit play so our scores are updating here let's change our score to you know uh that much excellent that works right now let's hit the button to load scene one and see what disaster befalls us we hit the button the scores the UI panel isn't correct and we've got an error failed to find an object called game status so and that's indeed true there was an object called game status in our overall team but there's not one here in in scene one we're like oh yeah yeah okay so here's what we're going to do we're going to take this game status object again I'll turn into a prefab awesome we're so smart we're going to go to level one one and we're going to drop the game status prefab in our scene one one so of course things will work perfectly right and we can test that let's go back to the overworld yes we'll save the changes let's hit play it's a zero score three lives on our overall move hit button huh there it's saying zero scores three lives so everything is awesome right no so I'm gonna hit play again from the overworld and now I'm gonna change our game status to say oh yeah we have a nine thousand and one points but we've lost life we're down to two lives only okay so that's good and now we're going to enter into level one why is our score zero and lives three so of course the reason is that when we switch scenes we still trash all of our previous objects and create new objects for the new scene every scene every object in the previous scene gets destroyed we actually check this very explicitly our little game status script over here we can add a event handler for ondestroy and we can actually put in a little note that says game status was destroyed because this actually runs when we switch scenes let's try it if we hit play and we push the button see that game status was destroyed and then an entirely new game object gets created so here comes the question that I get asked quite frequently and in fact when I ask people for suggestions for this live stream this weekend I got more than one person asking about switching data back and forth and the answer is so there's more than one way to do that okay but ultimately we need to store data we need to make it so that when we change one scene to another the data that we need to keep somehow doesn't get destroyed and there are I'd say there's probably like three major ways of doing that let's look at a few of them probably the one that you would use in this situation might be something like a don't destroy download but I'm going to save that one for last because we'll have to talk about the singleton design pattern a few things like that so there are three major ways to cause data to persist I mean there might be more but three come to mind for me let's put in a note here there are three major ways to persist this data between scene changes way number one is to save the info into something persistent a user prefs are one a save file would be another oftentimes an actual save file might just get stuffed and user perhaps for example but the idea is something that persists and in fact this would persist even not just between seeing changes but in fact between stopping and starting the game okay actually put a note this preserves preserves data even between game executions not just seen changes okay so depending on what you're looking for that might be perfect it might be overkill it might you know not really matter one way or the other but that's one option option number two is static class data this is probably not the preference because uh it's easy to goof up as a beginner so class static class information is data the belongs to a class not to an instance of that class not to an object of that class um and it there's a certain persistence there that comes maybe a little bit unnaturally to the new programmer also every now and again this anything that's static like this gets a little bit wonky in unity because when you when you're in the unity editor and you play a game and then you hit the button to stop the game from being played right so we hit play we're playing the game things are happening and then we hit this button which stops the game from running the game was actually running within the unity editor memory and I don't think the statics get cleaned up at that point I think they do get cleaned up on the next play but it leads to some like really sort of oddball behavior in there so um there can be a little bit of gotchas which unfortunately might come up once we who just subbed FERPA for poke thank you very much for the sub the third way which tends to be the most the most unity way is using don't destroy on load I did get that spelled correct there right yes I did so um but Baba I need to bring up my window so we can see chat again and I just changed it this Flags a game object technically this is miss miss ret marest label well I mean ice doesn't really matter it's more like don't destroy on unload this Flags game object such that when we change from one scene to another it doesn't get destroyed I II it is still present in the newly loaded scene that's quite interesting but to use this to the best possible advantage you need to use the Unity singleton design pattern which is not a real singleton design pattern but it's close enough hey ain't a no thanks to the Risa so let's we're gonna start with the first one okay we're gonna implement the first one so um what we would do with this is whenever data gets changed we are going to want to save it inside the user prefs or instead of when it gets changed we can save it right before we destroy and that's what we'll do so there's a couple of different ways to do it one if you if you're changing you know points and lives and stuff if you had imagine we had some function called add score which took an integer you know in some amount of score and here we were saying score + equals s you know we could take this opportunity to save the score in a file slash user prefs if we wanted that would mean we were making the save every time the score changes which might be kind of slow because maybe the score changes quite frequently so instead what we're going to do but depending on implementation this could be slow / inefficient also if you happen to have multiple places in your program where the score could change and you're not always using like one central function to do it which you should be because it's usually really good to have one central function but imagine that we don't instead the better way might simply be when we destroy this game object before we get destroyed let's save our data to our save file this is implementation number one okay that's the version of implementation number one for saving the data so to do this we would simply say so there's a cannot just go dot user press they change things on me and I don't don't use user prefs very often so oh it's plays player press I'm calling user preps but it's player press hey that's what gives me player press because I don't use this very often so play your preps there it is so player perhaps is an interesting little class basically unity wouldn't an overarching class contain global data but well that's this what this is game status is our global data that's what this global data status is major so major cast said wouldn't an overarching class containing global data be better and of course then you do open up the the buck the can of worms of you know he's global that a good bad whatever but in this case game status is our global data and this is basically just meant to be a container to hold all those all the stats all the global data that needs to persist between loads this is exactly what this is intended to be if the game crash you lose on your score that well that's true so I mean there's two things if you save all the time jump on the other hand if we are constantly saving the data on the fly it means that we pretty much never lose anything to a crash depending on the kind of game you make you may want this but here we're going to say on destroy so whenever if you quit the game or if you change scenes will save the data so player press is a class that basically unity has sort of a built-in save file that is cross-platform you don't care where it gets stored you don't you don't care about like creating files destroying files worrying about anything like that it doesn't matter if you're on PC Mac Linux if you're playing through the web player if you're playing on a mobile device doesn't matter this player prefs is a file that exists and you can write stuff to it and read stuff from to from it just by reading and writing through various keys so in this case we're going to write an integer right our score is an integer you know we could have a float get out of string but we have an integer obviously so we're going to write an integer we're going to need the key so we're going to call this score and we need to give it a value which in this case is score and while we're at it we're also going to say player preps dot set in lives and we are going to give it num lives over there which maybe I should just called lives anyway that's fine so now when we change scenes this will happen whenever this object is destroyed which includes scene changes as well as simply exiting the program alright so right before this object actually gets destroyed it will save the score and the lines of the player press and then how do we get that back well we just read it in and when would we do that maybe in the start right so again implementation implementation number one um load data from player prefs this might be from the previous scene or maybe even from the previous execution ie saved between quitting and reloading the game so to do this very simple so get player prefs has a function called get int get in takes in a string which is our key so score and returns an integer so we say score is equal to that and that will load that in it actually has an optional second value which is the default value so what do we want if if there's no key called score what should this function return' well we want the scores to start off at zero so there you go so it'll have a default value of zero if score doesn't exist in our save file it will return zero otherwise it'll do that then we'll do the same thing for num lives and then lives over here because consistency is for suckers and we are going to set it to three there we go so start execute when we start this when the object runs technically start runs immediately before the first update gets called an object which is slightly different from on enable but this should work so now if we do this let's give this a try and see what happens we're going to go into unity and hit play so I'm on the overworld it ran for the first time the start function ran which caused us to check player press for the values technically these values didn't exist yet so they got set to the default of 0 and 3 let's go in and intentionally change it we're going to change our score to over 9000 so now we have a score of 9001 let me go I'm just going to switch scenes I'm gonna hit the button to switch scenes to level 1 level 1 so what happens is still when we switch scenes right before the scene went right before we leave the scene all the objects are destroyed and right before all the objects are destroyed the on destroy function gets called which tells our game status hey let's say it out all our data to play a press and then the objects all get destroyed a new scene comes in new objects get created and then the game status the new game status object gets its start function called and what it doesn't start is it reads from player press and so it loaded in our save data and this will persist between a game so if I hit I stop the program and I hit play we start a new program we get a new set of scores now you can if you want you can you could do a variety of tests to see there there's ways to check to see if this is a new execution or not if it's a scene load or not so maybe you will want to initiate the scores back to 0 at completely um if it's the first load you know which is fine there's lots of ways to do that basically if you have if you want to do that on the main menu if you click the new game button actually that might be a great idea if you click the new button main the new game button from the main menu what it should do is it should delete the player preface info or reset it to like zero and three right whereas if you hit load then it doesn't do that then it just lets this do its own thing but it's a little bit you know it's a little bit rough we got a few questions uh how how you how would you do that when saving inventory so that's that's a good question um the player preps are relatively simplistic they only save integers floats or strings doesn't mean that can't work you could do something like so let's say we had an inventory program right where um so you do something like player prefs dot set string in so this is slot zero of your inventory the name of that so you call it you know you're storing your data from some other variables but this is you know your longsword and then you're saving in player prefs dot set int in zero way and this has a weight of fifteen whatever etcetra etcetra etcetra this is a little bit cumbersome and usually if you have any sort of real complex data um you're not going to you don't tend to use player press like this for a couple of reasons one player prep only has quote unquote one save file right so how would you have more than one save file like because right now there's just one slot called inventory zero so you know that the first slot in your bag contains longsword that's it you just have one save again you can sort of brute force it where you could imagine that every single one of these player prep entries have something like save slot zero at the start of them and then you'd have another one called save slot one and that sort of thing and you could you know construct this with a string so string save slot is equal to save slot plus my save number and something like this and then you could use that as part of this code over here and whatever but it starts to get really really really messy so what you will generally do undo undo undo undo some more more more come on there you so what you'll generally do instead is you'll probably come up with some other saving system something like what we're doing a project porcupine where we're serializing our code to like an XML file right in in project porcupine we save our data as XML which is just string data and actually what we're doing right now in project porcupine is we're doing we're using player perhaps and we're saying set string save game zero to be my XML save info is basically what we're doing there we're taking all the XML we're taking all our game data convert it into an XML string and we could save that to a file but we just stuff it in player press which is fine and then you could have multiple saved games over here you could decide that you're going to implement a fixed number of slots or you could have an unlimited number of slots by just you know continuing to add +1 to the save game number and that is one way you can do it if you're at a certain point if you got a lot a lot of data that you can run into certain limits about player press storage size particularly just just only I think for the web player basically were the WebGL at which point you might want to look into some other situations solutions but it's well beyond the scope of this particular tutorial hope that that is good ginger cookie with the 2-year risa thank you so much ginger cookie oh oh there you go just posted earlier to year two years warning in t minus ten thank you so much and yeah custom save files man yeah so that's a thing like we can stuff the XML inside a player press or you can go through the process of actually opening a file on the file system of the computer that you're on and stuff in your XML or whatever your binary data or anything you want in there um so that's it but that's again beyond the scope of that hmm are there any reasons why using XML no JSON oh um do I love JSON JSON definitely one of my favorite text-based data types especially as someone who came from a web dev kind of thing JSON is just beautiful and wonderful I used XML in project porcupine simply because XML parser is built into the version of c-sharp that unity uses if you do have either Silverlight loaded or there's some great open-source libraries that you can throw into your c-sharp there are some excellent excellent JSON sort of reader writers that are available on there love them but we just used XML because that was what was available in our library without having to add any third party stuff so that's that hmm because if you want to use XML in unity you just go you know using XML system XML there the system that XML and there's there's more after that there's your schema serialization all that sort of sort of built in to the version of c-sharp that unity has okay so that is the implementation number one so we save the info into something that persists which has a side-effect of persistent between game executions which might be good might be bad we don't know all right second version here is the static class data implementation so I'm going to I'm going to delete what we've done so far and re-implement this using static data so we're going to delete where we bring this up and we're going to remove this from the on destroy as well actually I suppose I could just comp it out yeah maybe I'll do that Boop so it'll still be here this code will be uploaded later on okay so now we're back to the version of the code where nothing persists between between either loading or exiting the game nor changing scenes nothing persists because we don't sort of save it anywhere and we don't try to load that data anywhere so it will be lost between runs hey drunk geek tables thanks Hilary sub um uniquely does have built-in JSON support now does it really Oh last time I did it it didn't or maybe I didn't check it right what do you have to include for that I mean because I know like it's not part of the it's not part of the c-sharp library that's there do they just add their own as part of a as part of like web support that's probably something to happen anyway well we're just that later maybe maybe next tutorial we'll be looking at ways to save that out to JSON and XML and different stuff okay so we're going to implement this sort of static class data so static data as I said is data is a variable then instead of belonging to an instance of a class it belongs to the class itself and we can do that very simply by declaring it static so now these two variables belong to the class as a whole all objects of that class will use it and in fact if it is public we don't have to grab an instance so here in this is our score panel updater we are finding in the score panel updater we're finding a copy of game status then we are grabbing the game status component from there and then we are writing out the data from that if we have static data we can actually ignore all this and comment all that out and instead we can just say hey I want the game status class dot score and the game status class dot num lies because those two variables belong to the class as opposed to an object so I don't need a copy of the object that's quite cool yeah pros and cons but it's quite cool um these will get instantiated to 3 and 0 when the program loads when the program loads these two variables will get set at that point they will not get reset to 3 and 0 every time you instantiate a new copy of game status they only get set once when you first run the program but other than that we can use it like whatever you know we can add score we can change it um it will likely break yeah in unity will no longer be able to set those values in the editor we could do a custom editor window and whatever let me create a little button here I'm going to create an extra button duplicating this one and I'm going to shove it to the bottom right and I'm going to label this one to add points and label it up here as well and what this button is going to do when you click it it's going to call the game status classes add score function we put in there and we're going to have it add nine thousand one point so when we click that button it'll add points so let's hit play we should start with a score of zero and three lives excellent and if I hit add points add nine thousand one points to our score we can hit more than once there we go if I stop the program and if I run it again will once again be at zero and three so let's add some points here let's hit the button to go to scene - level 1 1 and level 1 1 our score is still there because we are reading the score from the variable that belongs to the entirety of the class because it's a static variable so that's another way to persist data it's really really really simple to do and this is sort of like a true classic global variable like in the olden days that were considered very bad these are the global variables here it is encapsulated sort of in a namespace by virtue of being part of a class but we still don't have a lot of like babysitting in this variable and it's possible to write bad code somewhere else that and you know does silly things to this score but it does work and actually we don't need this important point we don't need this these two variables to be public I was doing it mostly for community editor but we could set these to be protected so that way nothing outside of the game status class can read or write this which does mean we'll get an error right now if we go and flip back into unity we will get a compilation error because this code right here is trying to access those two variables and they are protected we want to protect it so that the only way to change your score is by calling say this add score function but if we're going to do that we're going to need some way to for our outside program to read it we could use of course like get set sort of stuff but let's just go and make a public function here called get score which return score and a public int called get lies I should just call it lives you know what I'm going to do that instead of number lives I'm going to call this lives there we go add to a lot of sanity get lives return lives now what we can do won't quite work here because we haven't made this static but presumably what we could do is go game status get score and game status get lives but this will give us an error and the reason is this type of function here normal function must be called an instance of an object but here we're just trying to call it from the class itself without grabbing an instance of the object so if we weren't we did have an instance if we were still grabbing this instance of game status and going GS get score this would work but because we aren't and we're just trying to call it in the class itself that will be fine as long as we say it's static and I typically write a public static it doesn't actually matter public static so now we're saying that these are static methods which means they can't use they can't interact with anything that normally would need an instance but in this case we don't need an instance we're just using score and lodge they're both static so now that we'll run that will compile and yeah add points hit the button to load to the next scene boom done so now we have a bit of a cleaner thing still because things are protected this is the implementation to static class data um it's not that easy to goof up and as a beginner really but there is one trick C bit in that and this won't come up with integers like this but technically when you stop running a program in unity I don't believe it goes and cleans up all the classes because it's still running the same memory so anything you have set would still exist in the background of unity and sort of a weird awkward way um that you might not expect and when a program exits and or when it starts sometimes depending on your code you can you can end up with really weird messages then imply that something is is off or broken because it's trying to read a static that doesn't exist anymore because it's left over from the previous execution 99% of time it'll be fine but that's one way to do it okay and it's it works great you know um you know what let me rename this um very simple um occasionally leads to weirdness from inside the unity editor but not actually breaking things you could do really bad well not bad you know really messy global style variables with this but you can also do really nice in cap capsulation as well so that's fine static class data now we're going to go with the most unity style implementation um so remember that with this this game object is still being destroyed so our game status whenever we leave a scene this game static instance still goes away and then later on still gets created now one interesting question is this do we still need a game status object in our game and the answer is actually no if we never instantiated game status right let's say we didn't have this object over here we never had this game status all our static dad it would still be there and our static functions would not run currently I couldn't show you this without game status because of we do need an instance of it just for this add score and load scene torque right but if game status wasn't in here if we had got rid of this function and this function and maybe got rid of you know the start and all all that we would never need to instantiate game object it could just be a pure static class purely to can't contain data and that would be great but we need something external to process we need another class that you might instantiate to actually do you know your scene loading I mean this could be static here the problem is a button by itself in unity a uibutton can't call add score on just a static class by itself your button needs to point to an object so for the convenience of this example we have to have a button there but this could be a pure static class and it would still work pretty damn good all right so let's go and do the third implementation which again is the most unity style of thing so what this does as if we set don't destroy load on a game object then when a scene becomes unloaded it doesn't destroy the object so it will persist in the next scene let's give that a quick go let me go I'm going to remove everything from our static implementation so I'm going to remove stem in are basically whoops remove all the word static everywhere so we will no longer have a static class well we don't have a static class right now but we're gonna remove all the static bits get rid of all that kind of nonsense we need instantiation it's not nonsense data classes are really good this will break this code over here because we no longer can just grab get score from the class itself so we're gonna have to go back to the version which grabs a copy of game object and then does stuff although we did make score private so we're still gonna have to use get score and get lives which i think is probably an upgrade so now we are back assuming things are okay I believe we are back in the version where things don't persist so if I hit play we get zero score three lives add points we get 36,000 points I've hit the button to load the next scene everything is just being reset so we're back at a non persistent version so what we're going to do is we're going to add game object dot no it's not like that it's game object dot don't destroy on load so this is a static function on the game object class that requires you pass it some sort of object and typically what you do is you pass it our current game object right this is our current game object the one that belongs to this game status I mean sync this stock game object exactly the same so our game object from this hey rock dog thanks for the resub one month shy of a year thanks rock so our game object we are going to tell the unity system as a whole please don't destroy this when you load so what's going to be interesting is every time we've changed scenes at this point we've gotten this message in log game status was destroyed if I hit play right now xote thanks for the Risa the one-year anniversary thank you so much if I then quit the program I'll still get the message of the game status was destroyed that's still working now we can hit play I'm gonna hit the button to change scenes notice I did not get a message to tell me that this game object was destroyed but there is something that's happened we now have two game statuses in here one of these game statuses is from the overworld the first team the second game status is the game status that is in scene 1 - 1 this is why I say so this don't destroy onload is the most unity style there is um but it leads to a lot of complication and honestly maybe I really should just be encouraging you guys to use the static class data thing which is actually what I tend to do a lot internally but anyway let's move on so because level 1 - 1 has its own game status we end up with 2 ok we know like obviously this is not a great thing so let's get rid of the game status object from level 1 - 1 so we've gotten rid of it 1 - 1 no longer has one main menu sorry not main menu overworld has 1 game status here and we know it's not going to be destroyed on load so let's hit play let's give ourselves some points hit the button so new scene loads our game status from the overworld is still in our scene it just got carried over because it can get destroyed and our canvas our UI over here can successfully read from this that's great now we have a data that persists between scenes but there's one more tricky thing to worry about like oh that's wonderful now we have a single game status game object that persists throughout the entire program it doesn't matter um you know how many levels we go to right if you go from level 1 - 1 and we go to 1 - 2 game status will still be there that's cool but what happens when we go from level 1 - 1 back to the overworld so let me make an actually I should have done this from the start instead of having game status change scenes let's make a new object here and we're going to call it the scene loader object and we're going to give it the function so we're gonna give it a script called scene loader I'm just trying to figure out how to get the button press to work the way that I want yeah it's fine scene loader and in here I'm just going to grab from game status and actually we're moving more and more towards which should be a purely static class of game status which should tell you something I'm going to grab this load scene function I would have game status and just move it over to scene loader which really has no other job put to load a scene Oh using Unity engine scene man chose there we go we're going to go and tell our button over here which button is it I really should label this up there you go so this button is load scene button so it can no longer call the load scene function on our game status script because that's not where it is instead it's going to point towards the scene loaders object and the scene loader script and load scene load level 1-1 and then what we can do with this is I can go to level 1-1 and let's assume we have a button here and this button is the win level go back to overworld okay this this is just representing what would happen you know when you finally get to the end of the level okay I guess we'll move the button down so we can still see or on scene 1-1 you can hit this button to win the level and go back to the overworld and to do that I'm going to just go back to actually the overworld make a prefab from a scene loader go back to level 1-1 draw our scene loader in here and just tell that button - when you get clicked tell the scene loader objects scene loader class the load scene function and just tell it to call - to send the scene back to overworld so let's try that again we're going to go to overworld we're in hit play we're gonna hit the button here to go to scene two level 1-1 we're in level 1-1 we correctly have a game status actually me run this again right so we have 18,000 points we hit this we go to scene 1-1 we have 18,000 points because that game status object was not deleted now we're going to win the level we're going back to the overworld and once again we find ourselves in a situation where we have two game statuses two game statuses the UI here is still giving us the scores successfully the reason it's doing that is because when our UI script is running over here it finds the first object of the name game status and it just so happens that still the original one so our UI still looks fine because it's still grabbing the first game status with the 18,000 points not the second game status which has zero points but every time we switch back to level 1 1 and then back to the overworld and the Mac and forth and back and forth and back and forth we end up with a new game status all of which don't delete themselves ever so this is the problem and this is the the gotchas with the classic unity way to have data persist is you have to think about this like right now we have all these extra game statuses so all right what you might think do is what if we go backwards yeah we're gonna be making a singleton don't worry about it but you might be thinking let's take it back a step let's not create this object on the overworld let's create it on the main menu ah if we created only on the main menu then at least every time we switch back and forth between the level in the overworld it's not going to create more although every time you go back to the main menu then it's gonna create another one anyway see where it's going hey lower thanks for the resub the final problem is this it's if you're trying to test level 1 right if you're trying to debug something level 1 you every time you want to test it you want to start from the main menu load the main menu click start game go to the overworld move yourself over to level 1 hit the button to load level 1 and then finally get see if level 1 is working or not now you don't want to do that in unity you want to be able to be working on level 1 and just hit play and have it work now it doesn't work because our our GUI is trying to find an object called game status so there's two problems here the first is we end up with extra copies and the second is testing is a huge pain in the butt we can fix this though and this is going to involve the Unity design problem or unity design pattern I should say our singleton unity singleton design pattern so a single thing the idea of a single thing programming is a class where you can only instantiate a single copy of that class and every language is slightly different ways to do it some are somewhat more built-in ish than others but a lot of them involve sort of just going out of your way to check things they all have issues and there's you know these this is Singleton's are a source of religious warfare among programmers as even in unity what I'm going to show you how to do it so you can decide how to do it so here's how it works we want to be a single thing right we want to be a singleton ie there should only ever be one gain status instance at any given time so how do we find out if there's more than one well we could ask unity to tell us about all game objects are all game statuses that out there we can do a game object on find game objects of type game status which would return an array of game statuses and then if there's more than one then something's gone wrong but how do you pick which one of them is the real one well I mean you could just you know the first one or whatever but every every single copy of this is running the same thing it gets very awkward the way to do it is we keep a pointer to ourselves we have a static game status call most people call it current um or instance is very popular so I'm going to make it really explicit this is the one and only game status is that word enough for you now because it's static all instances of game status will just share this one variable over here so what we say is I want to be the only one and I want to never die okay all right that's step one but what happens again so this is on the overworld that gets set and that's groovy then you go to level one and then you come back over here okay and then you get a new copy of game status you've got the one that doesn't die and then the brand new one that we got from loading in the scene so what we do is before we set ourselves as this is the one and only game status and before we set ourselves as being immortal right become immortal there can only be one oh we are a Highlander she's called the Highlander a design pattern we are Highlander become immortal there can only be one so if someone else if this is the own and only game status is not null what does this mean someone else is the one and only someone else is is the singleton already so let's just bail so let's just destroy ourselves before we cause trouble so we're gonna say hey uh just destroy this this game object because we are not the one there is already of the one so we are not the ones to destroy ourselves and also let's return right away out of the start so that you know it doesn't run more than so we don't run anything else but if we get here if we get here then we are the one let's act like it so what this does is we're in hit play we're in the overworld we have our game status our game status just set itself as the one we're in add some points I mean hit the button to go to level 1 1 because game status set to do not destroy obviously it's still fine now we're going to go back to the overworld when we odhh the overworld scene there's going to be another game status over there but when it runs its start it's going to know that it's not the one and it's instantly going to kill itself in fact we even get a note that it went and destroyed itself so the game status that was there when we loaded the scene knew it was not the one and killed itself off automatically so now we don't get both multiple copies of game status which is good the other nice thing about this is then we can go and put one of these game status objects and every single scene because right now if we load level 1 1 directly in the editor and then we hit play to run this scene directly in the editor there's no game status so our UI reports that there's an error right plus if our guys running around he goes and stomps on a Koopa we're not going to get 100 points added to our score because there's no game status to add score to but now I can drop this game status prefab back in here and in fact we can now have the game status prefab in every single one of our scenes so now if at play there's a game status prefab we get no errors everything is groovy if I go from this scene to the overworld when I load the overworld again the game status house waiting there immediately discovers oh I shouldn't be here there's already one of me and I can keep flipping back and forth between these scenes back and forth so if your game data only needs to maintain simple data ok if all you need to do is keep track of a little bit of score and lives right then really what we should do is this is the ideal implementation implementation if your persistent data is just that data it doesn't do anything it's purely or it can be implemented as a purely static class then option number one is good basically this just acting as a big global dictionary for your data option 2 or option 3 over here option 1 is has its own you know possibilities option three is this is the ideal implementation if this class means to do things not just store things in other words maybe you need get to have an update function that you know modifies the game data regularly and will need to do so on every scene so what do I mean by that like literally if there's something that always has to be changed in the data no matter what scene you're in and has to be doing that in a sort of persistent way imagine you're playing a game where you can switch back and forth between scenes but there's a timer counting down constantly okay now what you could do is you could have a purely static class that just keeps the current time and you have some other script somewhere that keeps updating the time but now you have to make sure that that other script that keeps updating the time is present in every single scene as well and so if you already have that concept where there's a certain script that needs to exist in every single scene to do things on my global data you could just have your global data be this sort of persistent don't destroy onload kind of structure that just exists you have one game object you know exists in every single scene and it's the same one and it doesn't matter what scene you start from it will be there correctly I often do tend to do this I tend to work a lot with pure static of pure classes in general so the idea of like a pure static class is very appealing and is a great way to store data and again this way this is very simple you know this is a very simple very minimalist implementation has the benefit of true persistence also you don't need a single central to store data in this way each object could save load its own info although you know again whether that's appropriate not depends entirely on your stuff so hopefully this is a good set of tools that you've got I really like this and this is the one if you go and look up anything on by unity and how to how to have that a persist between scenes they tell you to use just don't destroy on load and don't destroy on load is very powerful but man it is loaded with gotchas because you need this sort of singleton design pattern there's one little bonus here right with this is this is a static variable called this is the one and only game status let's rename it something sooner let's rename this to instance actually we're going to rename it to lower case instance here there that that's a lot a lot more sane and that tends to be what people use um so we've got this one and only static link pointing us to the one true instance of game status our store our score panel updater instead of finding the game object which is arguably a slow operation in unity especially if you're doing it every frame it's not that slow but it's not great it might be better to do it in start for example right so in your void start here you could grab a copy of your game status at this point but what we can do is hey while we're looking for is the instance of the game status right the actual game status object itself not the game object but the game status object the instance of this class that's what we're looking for why don't we skip the find and skip the get component and just read directly from instance we could do very easily fit public but that opens up a lot of problems let's just make a I don't know we'll just make a little property here I guess we could make this a property whatever a lot of you do it this way say public static it could be a function as well here we'll make it clear with a function tends to be a little bit more accessible to everyone so it's a public static function called yet you instance and all it does is return instance but it means that no one outside the program can actually change where this is pointing you'll get a copy of the instance but you won't be able to change this particular variable and mess up everything so now we can again comment out all of this and just say something like game status dot yet instance work I guess I still need most of this line here and we can say game object get instance dot get score game object again instant that get lives that should compile what did I goof up oh yeah this has to return a game status doesn't return void it returns a game status there we go I didn't realize the program was still running there we are so now this is updating let's go and give ourselves some points or not Oh add points breaks yeah that makes sense the add points button is trying to point to the game status that was in the scene in our editor but the button is now broken because it's not pointing to no object anymore which is fine you're not usually gonna be adding points this way instead you're going to have you could have a script attached to this and that's would be the way it would correctly work this add points button should install instead be doing basically the add points button just has to say hey game status give me your current instance dot gets instance dot add score and this and then we add 9001 that's all the button has to do to add score to our correct instance of game status and this is also very fast because you're just accessing I mean technically this is a function call but function calls like this get optimized like crazy so effectively this is exactly the same as if we were able to access this variable directly and it's insanely fast and then we can just get it directly and that's very handy now you don't have to do game object that fun you don't have to do game object at find object of type you don't have to do from your game object you don't have to do dot yet component or anything like that you just go game status get instance dot blah which is really good and really fast I think hopefully that's relatively clear um one way with like one thing when you show someone multiple ways they might get confused about the number of options and which way is the right way and get confused between the two or the three in this case there's not really a better option there is sort of an option that is more optimal for whatever you're trying to do you can whatever you're trying to do you can do it for sure using any of these three methods but one of them will usually be a little simpler or a little faster or slightly more convenient is what it comes down to like if you really want a game and a lot of games these days just have one save basically they have one set of persistent data that persists between game loads and that's that player press is the ideal way to do that it just has one basically save file we did show you how you could have multiple game slots with this it's a little trickier also if you have really complex data this gets a little bit more annoying unless you go and serialize all your data to XML or JSON or something well that's a whole nother topic class data very mostly when things don't change or you're okay with having an outside script being responsible for changing the gam game data and then finally this way here is the most unity way of doing it which does have a lot of caveats although it is kind of interesting that you keep an actual game object alive throughout the entire excuse in your program so we're gonna do is we're right in programming only better yeah there's arguably something that you know any particular algorithm there might be one way that is faster than every other way but is that better because maybe it's not as flexible maybe you can't understand it like I used to write a lot of Perl code right and I would be very used to writing a lot of Perl code that would look like you know something like this and we'll tea at the top where's my tilting anymore right over here you know and then an escape like this and then another slash here and then here would have a slash one doing some stuff it's like a perfectly Owen and of course we're gonna have like a bunch of we're gonna have some parentheses over here and a star and then a dot question mark and then another dot and a star as excellent Perl code maybe I don't know it's been ages since I've written it um I've tried since I've done anything like this but that is not necessarily the best way just depending on you know if legibility is something that counts and it does count then maybe there's that so anyway so there's a lot of things that all we'd be holy wars about different implementations but hopefully that gives you a few tools in your tool check chest se thank you very much for the resub 25 months in a row thank you SE a wild regex appears hmm I love reg X's they're a great way to parse tech stuff I haven't done worked with him in ages because it's been a while since I've done any sort of web dev which is mostly where I did a lot of my m-my text programming especially when I work in Perl although you can do reg X's and basically every single language I think C sharps got like a class called reg X doesn't you probably have to include something anyway we're gonna take a very short break when we come back we're going to do something a lot more sort of just fun and silly we're gonna make sort of a 2d top-down car racing kind of thing I think it's like 15 minutes to throw this thing together and it'll be kind of a blast so the thing sort of thing that's very well suited whether you're playing mobile or whether you're going to be playing on a console type thing we'll look at a few of those topics and it's a hoot and I hope someone uses to make a really fun little car racing game so give me a two minutes just to have a bio break and when we come back we'll have a new little project open up here and we'll do a little bit of car programming it's going to be real cool see you guys in a couple thank you to everyone who pledged to support this in February and is making these videos happening through March and early April and of course these mic-check supporters we've got Wes Alden buffing again Craig Martell nail Vic strim Neil Blakeley Milner speedy savant valent cake being Aaron Tyson Marius field of old Oh Peter Talgo probably Olli Julian oh sure the phone Stephen stager Michael McClintock kale the quickened raise you on by trash adjectives and Andrew Henninger and everyone who just watches and shares and favorites and comments and subscribes thank you so much for just continuing to make these videos a thing that we can do I think it's pretty awesome and I hope you do too see you next time folks
Info
Channel: quill18creates
Views: 83,566
Rating: undefined out of 5
Keywords: Unity (game Engine), Game Engine (Software Genre), programming, tutorial, first, person, shooter, first person shooter, fps, howto, how to, beginner, guide, unity, unity 3d, unity 4, physics, blender, 2d, 3d, quill18, quill, multiplayer
Id: WchH-JCwVI8
Channel Id: undefined
Length: 70min 49sec (4249 seconds)
Published: Mon Apr 04 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.