Upgrade your variables! Unity Scriptable Objects Beginner Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
do you constantly get null reference errors because objects can't find each other and you're missing references do your objects depend on each other like some mad crazy spider web do you wish you could upgrade your variables and give them extra information and maybe even functionality oh and does this happen to your code when you make one small adjustment in this video i will provide you with a nice solution to those problems by introducing you to the power of scriptable objects they often sound a bit intimidating for beginners but please don't panic and run away like those guys down here i mean after all everyone here survived and was fine and the ones that ran away can embarrass themselves scriptable objects really aren't that complicated but they can make your life in unity so much easier and understanding how they work means you understand a lot about how things work in unity in general so let's do a bit of theory and then we're going to look at some practical examples to see how it works in code to understand scriptable objects it's important that you understand the big difference between your files on your hard drive and the scripts that you write and the instances the copies that get created at one time and that you use when the game is playing the project folder right here is literally files that are on my hard drive so when i create a new script i'm creating a new file the scripts on our hard drive are basically blueprints we defined some fields and some logic but during the game we use instances meaning copies based on those blueprints those instances are not created on your hard drive they are created in memory so when the game once they get created when the game stops they get wiped from memory every instance can use different values for the fields and of course we decide when we want to call those methods the logic and make them behave all differently in unity there are two main ways to create those instances at one time you can always create an instance of a script in another script simply by using instantiate and of course when we instantiate a prefab that has the scripts on it what we are doing is we are creating instances of all those scripts and the other main way is through the editor by building our scene we populate the scene with game objects and we can attach scripts to them as components this might seem like we're already creating instances but basically we're just telling unity when the scene starts i want you to create an instance of this and of this and of this and do this all in memory so here i have this vipgame object it has three scripts on it and when the scene starts i'm saying okay i want three instances of this script on this game object and the nice thing is i can also set different values for every game object here so here i might increase the walking speed and now when i click play unity is going to take all this information and create all the instances that i need at one time the switch is pretty much invisible but that's a feature of unity right now i'm looking at an instance of those scripts a good clue is that you probably came along is when you try to change some values and you think you found just the right amount the perfect values and then you click stop and the instance gets wiped from memory and that means all the values are gone too because once again you're just looking at the the plan for the scene i see the editor a bit like a shopping list you know you can say okay i want a creature like this one i want to place this one here and this one here and also give me a sun and then you got like those little post-it notes meaning you can change the value to say okay i want this creature to be really fast and this creature has different values but the important thing is all of this is still happening on your hard drive because there is a scene file every time you have a scene you save it on your hard drive and that scene file has all those informations in it with scriptable objects it starts the same way you just right click here in your projects folder and you create a new script and you see sharpscript and so you just created a new file on your hard drive and to turn it into a scripted object all you have to do is replace the mono behavior with scriptable object and don't forget to add the create asset menu attribute right above the name of the script because that is going to allow us to right click in the project folder and create an instance of this script now you might be wondering why do we create an instance in the project folder and that is exactly what the big difference is with a script object compared to money behavior and classes every instance is another file in your project folder on your hard drive you cannot put those instances into runtime you just create them one by one by just right clicking and every time you can get a new instance so in this project i have a scriptable object called float so and i have the grid as a menu attribute so i can right click and then choose here float so so now i created a new instance of this crypto object and i can give it different values based on the fields that i defined in the script and here before i have already created two instances called global light and global temperature you can give them any name you want when you click on the instance you can still see it right on the top what this instance is a copy of now you might be wondering what's the point of a script where i have to create every instance by hand that sounds incredibly tedious and the big advantage of scripted objects really is you know where they are they are right there on your hard drive they're always going to be there when you build a scene with mono behaviors it might be quite common that in a way you say find object of type find this one and then you say ah wait but this object also needs to know about another object and then of course every time a new object gets spawned like a new creature they have to know where the sun is so they have to find the sun and maybe actually the sun needs to know about every creature too and sometimes creatures die they get killed they get shot in the head i mean it's a game so things get instantiated and destroyed in memory all the time it's highly dynamic and so it gets pretty messy when you try to keep all those things connected and then of course when you try to call a method on a reference of an object that doesn't exist anymore you get an error and this could be a game working bug like all the time you put into your game it's just down the drain because of this one damn missing reference now there's one more thing we should talk about and that is prefabs because prefabs can really leverage this advantage that you know where the scriptable object is on your hard drive because prefabs they also sit on your hard drive right you create your game object give it some scripts and then you drag it into your projects folder to convert it to a prefab so i see prefab kind of like a collection of blueprints right you can have your game object with a bunch of scripts can have one script doesn't matter and then you have those little sticky notes because you can like preset all those values of the script and then when you instantiate one of those prefabs what you're doing is you're instantiating instance of every one of those scripts that's sitting on the prefab since the prefab is sitting on our hard drive and the instances of the scriptable object as well you can already make that connection so you can tell the prefab hey the script object instance that you probably want to know about is right there you just drag that in the inspector and i'm going to show you in a moment so every time now when you instantiate an instance of that prefab it already knows about that instance of the scriptable object and of course you can do that with different prefabs they can all reference the same instance of the scripted object and they can use it to communicate and now they don't have to find each other like the the normal instances of the scripts all your creatures the sun the mushrooms they just communicate through the scriptural object and they're always going to know where it is it's always going to be at the same place okay so let's take a look of a practical example i've built this little demo scene on how we can utilize this advantage of a scriptable object let's start with the thing itself the script that i created this scriptable object it's called float so and it's a scriptable object that is based around this float value so let's take a look at that script as i mentioned before i use this great asset menu attribute above the name of the class so i can easily create the instances with right clicking then i have a public sprite here for the icons file this could be really useful when you use this in a ui element a string for the name and the most important thing here is this float field it's just called value a private field so other scripts can just change the value but there's a public getter in case any script just wants to know what the value is and to change this i have these two methods so they are public anyone who has access to an instance of this can just change the amount the first method is called change amount by and the other one is set new amount uh just because sometimes i have some other scripts that want to say okay increase this value by 5 and other times i just want to say no set this value to 10 i don't i don't give a damn what the value was before and in both cases i make sure that the value doesn't go below minimum or the maximum above the maximum and i just use this mathf.clamp it says the first parameter is the value that you want to clamp between the second and the third parameter and of course those are just serialized fields that i can set in the inspector and they can be different of course then for every instance that i create of this script for the min and max value i also make public getters so other objects can at least request to know what the value is and they can work with it and we're gonna see some examples later on i should also give you a little preview with this set to initial amount because there's a bit of problem with scriptable objects since they don't live in one time they keep all their values so you have to reset them but we're going to do that in the end the more important thing right now is this action event here just make sure you use system because that's the namespace that that it lives in and it's just a handy way of winding a delegate in one line and i'm setting this event to an empty delegate just in case it gets called and no one is listening to it otherwise you would get an error message but if you just do it this way you're never gonna get the error and you can just call the event and we're doing this right here in the change new amount and set new amount and so the event it just gets sent out into the void the instance of this crypto object doesn't care who's listening to it but then other scripts can say okay every time this value changes i would like to get informed by listening to this event okay this is pretty much it for this this is all the scriptable objects we're going to use in this example so let's go into the scene and see how other objects and classes can use instances of that script to communicate with each other the script that's going to change those values is the sunswip so the sun is just a prefab it has light and it has this sunscreen and yes you can see it references both instances of my float so scriptable object like any good sun it basically just goes up and down it goes up the light increases and the temperature increases and here i set it so when the light increases by one i want to increase the temperature by five and when it's at its size it's gonna go down again so let's take a look at that script so here i have a bunch of serialized fields that you just saw and the reference to the actual light so you can set the min intensity and the max intensity and it's just going to go up and down between those two the important thing is of course the reference to the instances of the float so scriptal object and we're just doing this like we would do with any other script in unity you just say like a private and then you can say any kind of class you have could be a morning behavior or scriptural object could also be a class with automotive behavior then you give it a name and then you can assign an instance of this into this field so with the creature script you would get like any kind of creature that is living in the scene and this is what i was talking about before you can do that in the prefab so the sun is a prefab that has the instance of the script and i can already assign those references and they're never going to get lost i can instantiate all the sounds i want in the awake method i'm doing a bit of a dirty hack is what i also mentioned before the objects are not descriptive objects are not going to reset their values so i need some script that does that for me and i'm just doing it here in the sun and i'll explain more about that later so here in the start method i just add the current intensity and the heat and then i use this invoke repeating which i wouldn't recommend i just wanted to keep it really simple invoke repeating just says call this method after this seconds and then repeat that every x seconds that's the last parameter usually i would use a coating because invoke repeating is very error prone if you make a typo it's not gonna work but you're not gonna get an error message so that can be very frustrating but yeah i just want to keep it simple for this example so let's just go with invoke repeating it looks the easiest also on a side note if you want to have the sunrise smoothly you should play around with sine waves they are made perfect for that but for the sake of this tutorial we are really just making the sun go up and down go up and down in a very linear non-natural way but so you can see here when we are rising we set the intensity and we change it by second and when we reach the maximum then we're going to go down and the important thing is every time we do that we tell the instance of the scriptable object that we want to change the amount and as you might recall that means we're also now triggering the event in the instance of that scripted object and let's see who's listening to that event the most important one is this bybee prefab it has three scripts on it the first one is just so that it works around it just walks from point a to point b and when it drives at point b it chooses another point uh they're kinda stupid because their brains are light bulbs the next script is this skin color adjuster and that is going to change the color of them based on the global temperature so when it gets cold they're gonna start turning blue and so let's take a look at this one here on top we have reference to the renderer and then the material and that's just to changing it and of course the temperature at when we want to start turning blue and here we have a reference to an instance of this float so and it is of course the same instance that the sun is referencing so the sun is changing it and the this script is listening to it in start i just first save the color that it started with or so this orange and then i calculate the cold range i just use that range in the adjust color temperature method and the important thing is in on enable we are subscribing to the global temperature the instance of the float s0 the value changed event and what we are saying with this line is every time that event gets triggered we want to trigger the adjust color temperature method and therefore we are only calling this just color to temperature method when when the temperature actually changes and as you remember the sun is setting that value and it says the change amount by and that is triggering the event and i'm also going to show you how to do that with a slider so like any kind of script can change that the this script here the change skin color doesn't care about who actually changed it it only cares about that it changed and so when that happens we just check what the new temperature is and then we're going to calculate how far we are between the orange and the blue and then we set that to the skin material and down here very important in on disable which gets called when the game object gets destroyed or rather when this instance gets destroyed is that we unsubscribe from this event because if we don't um unity might actually keep this instance around in memory and still call that method even even though you don't see the game object in the scene anymore so when you subscribe to an event in unenabled always unsubscribing on disabled just use minus and that's really all there is to it okay this is it for this script so here's another example that is commonly used for this technique which is the ui that can just represent this value and again the ui doesn't care who's changing it it just says okay every time this value changes i'm gonna display that so it's just a text it has reference to this and as you can see here it's pretty much the same what in on enable we subscribe to this event so every time the changes we are going to change the text and then on disabled we're going to unsubscribe another example of thing that can react to this is on the bulky script is this lightbulb script and it does pretty much the same as the changed skin color it listens to the global light and if the value is below certain threshold that we can set here it's just going to turn on this light button and it's just going to do that by turning on a point light which i put inside this light bulb and to make it look a bit nicer also gonna change the material to this emissive material and yeah we're gonna hit play soon don't worry let's just take a real quick look at this script once again we are having a reference to one of those instances of the float so we're doing this right here and of course we're doing that in the prefab dragging in this reference and in on enable we're going to listen to the event and then we're going to toggle on the light bulb based on if it's already on i just change that in a bool so we don't have to change the material all the time and then we see okay if it wasn't on then we're going to turn it on and otherwise depending on the light we're going to turn it off and of course in on disabled we unsubscribe so let's hit play and see all of this in action the sun is going down now so it's changing the global temperature and the light the ui is picking up on that event and of course the the buy piece they're also listening to it so the light is now below one so they checked okay we need to turn on our lights because we need to see where we are walking and the sun rises again and i think i'm speeding up now so when it gets really hot oh there is another thing and that is also interesting because this smoke is a nested prefab it's a particle system that has a script on it and it listens to the temperature and then i define okay when it gets really hot i want to emit those particles this number of particles per second at maximum and again it's pretty simple we just have reference to the particle system and of course to our float so instance and here i don't know if you're familiar with particle systems i have a whole video on it if you want to change it through the script you have to get a reference to the subsystem and of that subsystem you can then set the values directly it's something to do with a custom interface for particle systems anyhow point being is it's all the same on enable you subscribe do it and then on disable unsubscribe so the cool thing is because this is a prefab we can attach this thing to anything and it's already like hooked up to the instance like the global temperature so for example i could say you know what i want the mushroom here to also smoke and i could even do this at one time like things don't need to know about each other everyone already knows what they have to know and yeah then the script just works i also have this little slider here once again another script also references these scripted objects no one knows about it only i do because i'm playing god here so i can just crank up the temperature uh the sun is going down it's trying to save those little creatures but i can keep cranking it up or i can just set it all the way down and now they're turning blue because it's cold and now the sun is rising the sun is kind of trying to be nice to them but yeah let's keep it cold or maybe let's go all the way hot and they're smoking again okay the last example i have here is this mushroom script and this one actually listens to both of those instances because it's checking when it should grow and it does that based on temperature and the light like both conditions have to be just right and i'm saving those in a vector 2. it's just a handy way to keep two values together has nothing to do with position it's just vector x the x value is the minimum and the y is the maximum so f1 for the temperature and one for the grow light range and here i just do one thing a little bit different i just call this method every second because they're kind of growing constantly you could of course also make a bool and only change that boo like other conditions right when the values of the script object instance change i just want to show you you can do it this way too right you don't have to listen to the event you can even use it in an update loop like an update loop could always check what's the value of the script or object instance and then do things accordingly i hope you can see how useful this technique is because all of those objects they communicate with each other but they don't know about each other's existence like the bile p doesn't have to find the sun and then in the sun script has to like dig through the script and find ah that's the light value and oh yeah i need the heat intensity do some calculations and or maybe there's another thing that's doing the temperature or light it only cares about the the smallest possible thing and that's the light and the temperature that's the only thing it has to reference have has referenced to so they're really communicating through the smallest possible link and that means things not gonna break when you remove things or add new things but you should also talk about the the downside of scripted objects and i think one of the most annoying ones is that values don't get reset because well they don't really care about one time or not so when you change them during one time and you stop the game they're still gonna have the the different values here this one i had this method set to initial value and you might be tempted to just add like awake or in on enable in the scripted object but to be honest it gets pretty messy i'm gonna show a link in the description there is a really nice unity thread where people are trying to figure out when exactly those things get called but it's not nearly as reliable as with the money behavior and there's some caveats to it so for example unenabled gets called when the scene is loaded and motor behavior is referencing an instance of that scriptable object so it means the first time gets called when you hit stop and play in the editor and the second arm then it's not gonna get caught and also awake keep in mind that is getting called when an instance of the script gets created so that means for the scripted object when you right click in the inspector then awake is getting called and that's not really that useful for game logic that might be nice utility my advice would be have some kind of level manager that has reference to all these scriptable objects and then in awake it sets them all to the initial value or maybe even depending on the level it might say no in this scene we're starting with a different values and what i also do is in a published game i have a menu scene and the menu scene can then look for a safe game can get that from the cloud or the hard drive and if it says okay we are loading a saved game i'm setting all the scriptable objects to the saved values otherwise we're starting a new game okay now i'm calling the uh set to initial initial amount on all these scriptal objects and to make sure that there are no confusions let's take a look at some examples when you would use the scriptal object and when you would like not use them so here's one of my favorite games two point hospital and my rule of thumb when to use a scriptable object is when every instance is going to be unique and used by more than one object so there's only one global light in the example i showed you right there's no two globalized three global lights and here a very good example is the player money like you don't have one wallet two wallets it's not like bitcoin or whatever where you make a new wallet the player always has like one wallet so you could just you know there's going to be one instance and also pretty much everything in the game is going to interact with this like the the drinks machine is gonna set that when someone buys a drink you get twenty dollars so the drinks machine prefab could have a reference to an instance of this float so and one float so instance is uh player money and the same like this reputation this level that's only going to exist once in the game so on the opposite side you would not use the scriptable objects when they are like endless maybe even an undefined amount of instances so in this game obviously the patients you you don't know how many patients they're going to be and they're definitely going to be a lot and every patient that's not a patient it's a pretty shitty hospital to be honest there's one and even quite happy so the patient is probably a class and then you have those values here for uh happiness uh health like those would just be values in a class because every patient has those and they're all different for every patient they're definitely not unique and of course you create new patients and i think one just died on the floor so the instances get destroyed and of course my own employees they also there is a class and everyone has those values they are absolutely not unique i'm gonna have a lot of those and maybe even the the drinks machine um like no it's a snack machine depending on how often it was used this this value goes up and it needs to be paired once again every snack machine has its own kind of value here they're definitely not sharing that so you would not use the scriptable object for that just keep that in the class okay this is it for this tutorial i hope you learned something as always if you have any kind of questions feedback comments yeah just just drop a comment below uh also if you're interested i can upload this project to github if you want to look at the scripts if anyone's going to request that i'm going to do that and yeah subscribing to this channel would be really nice but honestly watching all the way to the end that's actually worth a lot more yeah thanks for watching and goodbye
Info
Channel: Shack Man
Views: 2,581
Rating: undefined out of 5
Keywords: unity productivity, coding productivity, unity tips, c#, c# unity, c# unity tutorial, unity tutorial, unity game tutorial, programming tutorial, learn unity, game dev, unity gamedev, unity indiedev, scriptable objects, unity scriptable objects, scriptable objects beginner, agile code
Id: oovAPuckQjs
Channel Id: undefined
Length: 28min 54sec (1734 seconds)
Published: Mon Jan 03 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.