The Ultimate Introduction to Scriptable Objects in Unity

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today we're going to learn about something that can save you hours and hours upon work in the unity game engine and this is called scriptable objects i'm going to show you what they are how to make one how to use them when you'd want to use them and i'm going to compare them to other methods that don't use them so you can get a better idea of how they work and why you might want to switch over to using them scriptable objects can make it easier to prototype it can organize your code to make it easier to understand and change for both the coders and designers and this results in quicker iteration times on both sides especially for designers who might not have entirety of knowledge on the code base and may just want to change a couple of values around and speaking of game design this video is sponsored by machinations meganations is the game balancing platform which you can map your entire game and then run simulations to balance the parameters which is great for fast game design iteration how do you know if you need machinations well you're swamped with spreadsheets text documents diagramming tools and whiteboards so you know that balancing is more than a circus act it's the cornerstone of great player experiences and you want to make sure to get it right you believe that guesswork is for the fortune tellers game designers should rely on proven science you want a reliable way of predicting player actions even after thousands of iterations machinations will help you get laser focused clarity rapid prototyping without writing any code to help you balance your player's experience and this can save you up to 90 in balancing and iteration time which is huge you can start from hundreds of ready-built templates or you can quickly create your own by using the prefab library items you can easily bring your whole team in and work with them on the same diagram by using the live collaborative editing feature similar to google docs so you can make edits in real time they have extensive and awesome documentation youtube tutorials and they host regular webinars so picking it up will be a breeze there's a plan that's free forever that gets you really far you can try it out by using my link in the description and start designing your own machinations so scriptable objects everyone's talking about them what are they well a scriptable object is just a fancy way to say that it is a container of data so in its primary use they are meant to contain data that you might need to play your game for example let's say you have an enemy and your enemy has different stats such as health speed and a type of attack well instead of creating a mono behavior to store this data and attaching it to your enemy you can make a scriptable object instead to store the data now the main difference between these two approaches is that a scriptable object is an asset so this is an asset within your assets folder and you cannot initialize a scriptable object in your scene so this is a project level asset this also means that this does not depend on the scene in any way so it is scene independent any game object from any scene can access this data you do not need to get a reference to another object in the scene now with a mono behavior usually what you would do is that you would have this zombie you would make a prefab out of it and if you want to change the stats you would make another prefab variant out of it with the new stats but you can see that this can quickly add up to having a bunch of different kind of prefabs and what happens if you change something in one prefab that you need to now change in all the other prefabs and that's because the zombie has a direct dependency to those stats so when you have dependencies when you change something it can cause something else to break or you might need to change other objects or scripts to account for the new changes scriptable objects makes our life easier because we extract that stats information from the zombie and we put it in this data container within our project level that we can easily duplicate and have different scriptable objects for our different enemies with different stats so there's a lot more descriptible objects but right now i just want to show you how to make a scriptable object so it's easier to follow along so in your assets folder or wherever you have your scripts you can right click and create a new c-sharp script and you can call it whatever you want in this case i want to make an enemy scriptable object and usually you have the word scriptable object after what you want to make a scriptable object of so for example i can just call this enemyscriptableobject and i actually already have a script like this on the scene so i'm just going to add a two to it so it doesn't get confused so once you have this script you can delete everything for the most part even these two using statements from system namespace just make sure you have using unity engine and all we have to do is instead of extending from mono behavior we can now extend from scriptable object and ta-da you have your scriptable object but we actually have to add some data fields into it so let's say our enemy has different properties such as health and speed so you can just declare as you would any other script public int health and you can set it to a value and you can also put speeds so you can do public float speed maybe set that to 5. you can also make these private with a serialized field as so but i'm going to want to access these from other methods so i'll just leave them public for now or you can make a getter and setter as well so this is like our blueprint our recipe and then what we can do is in the assets folder we can create an asset out of this script that contains our data unfortunately out of the box this is not supported directly we have to make this accessible from the assets folder so to do that we can add these two brackets here and type create asset menu parentheses then we can add a file name which is the default file name that will be given to our created asset in this case i'll just call it enemy scriptable object and you can also add in a menu name so you know when you right click in the assets folder a bunch of stuff pops out and it's sometimes hard to see what you want to select so this will make it easy for us so we can put it under a folder called scriptable objects dash and then we can call it something specific so in this case i'm just going to call it enemy2. you can just call it enemy one in your case alright so if we go back to the editor now and we right click create you see that now there's a new option here called scriptable objects and this will have all of our scriptable objects that we made if we put it under this menu item so now we can create an enemy2 scriptable object and we can name it anything we want in this case if we have an enemy of a goblin type we can just name it goblin enemy and you can see now that this is an asset in our project with health and speed and we can change it in the inspector so it is important to note since this is an asset and is not bound to our scene that means that when we change the values either through here or through code while the game is running or even while the game isn't running then those values will be saved unlike normally when you press play mode and you change a value in a component for example if you change this slope limit of the character controller while in play mode and you exit play mode it will not save that value with scriptable objects it does save that value so it makes it really nice for prototyping and if for some reason you didn't want it to save the values you can easily write a helper function to instantiate a new scriptable object through code and change those values at runtime and that wouldn't affect the original scriptable object which i'll show you how to instantiate them through code as well alrighty so now i want to show you a more concrete example using this space here i'm going to open up the script that i already have created so the only difference here is that we are also taking in another parameter called enemy attack scriptable object so let's say you have an enemy and let's say your enemy attacks the player now what if your different types of enemies have different kind of attacks well what you can do is input scriptable objects within other scriptable objects so in this case we're inputting this enemyattack scriptable object which if we go to it's just another scriptable object with other parameters such as attack damage attack range and attack sound which is a reference to an audio clip that we can play in our script whenever the zombie attacks so this makes it super easy to swap in different attack types when we want to test on either different enemies or we want to test the same enemy test different attacks and i just want to highlight that another benefit of using the scriptable object is that it can save you memory and performance for example in this scriptable object we are referencing an attack sound so let's say we have a bunch of enemies on the scene and if we were using mono behaviors we'd need to create an instance of an audio clip every time we instantiate a new prefab and so now you have a bunch of instances of something for each prefab when in reality if you can just reference the existing instance within the project then you wouldn't need all these created instances just like in this case we have a reference to an attack sound even the attack damage and attack range we only have one instance of these variables instead of having an instance per prefab of each enemy so you can see if we have a thousand enemies we need a thousand instances of the enemy prefab to be instantiated and each of those instances would need to put these variables in memory however since the scriptable object lives in the assets folder there's only one instance of it which you cannot instantiate now this is only in memory once instead of a thousand times alright so back to the editor i just want to show you a more concrete example using these enemy scripts that i've made so in this case i have a zombie within enemy controller which the enemy controller basically all we're doing is getting a reference to the animator and i'm just storing the different animations that it has so i can access it easily like the ids of each animations then what i'm doing here on start is that i have an audio source attached to the zombie so what we're doing here is we're referencing this enemy scriptable object which if we scroll up all we have to do is type private or public enemy scriptable object which is the name of the script that we made and our variable name just like any other variable so you can do enemy scriptable object dot and then i'm going to reference the enemy attack type which is the other scriptable object that i made that has the type of attack dot and then we have these public parameters that we can access and in this case it's called attack sound so basically what this script is doing it's saying that while the enemy is not in range of the player for its attack then follow the player and once it is in range then attack and wait a couple seconds until starting to follow the player again until it gets in range again and for the range we use the property from the scriptable object enemyscriptableobject.enemyattacktype.attack range and this is just a simple example to show you how to reference a scriptable object within the scene and so if you add the enemy controller to your zombie you can now drag and drop your created asset directly into the inspector so in this case i can drag the enemy scriptable object that we made with right-click create scriptable objects enemy right into here so we can use it and now you can see that when we run around the zombie will chase the player until it's at the certain range of the player which we can go to the project and click the scriptable object zombie attack and you see that the attack range is five now if we change it to one you'll see that now the zombie gets closer to the player before attacking and you see that when we stop pressing play here the value is kept in the scriptable object which is awesome so you can easily use this to do any kind of other system such as player stats health power up stats keeping a list of audio references a list of objects making an inventory system or creating a save system and it's great because this is persistent so the data will remain the same regardless of whatever scene you're in so it's scene independent it allows you greater flexibility because you can easily drag and drop different scriptable objects in to test different parameters or values so you can isolate testing different features more easily because you'll have reduced dependencies on different scripts which i'll actually explain a little bit more of in a minute and it's not bound to play mode so i do want to mention that there are some functions that you can call within scriptable objects the functions are awake unenable on disable on destroy and on validate now the execution of these is a little different than mono behaviors since this does not exist within the scene space and the documentation on this isn't super easy to understand fortunately i found this great forum on unity by get brinks explaining the different callbacks and when they are executed so the awake function is mostly called when a scriptable object is created in this case it could be either in the editor or at runtime which you can create scriptable objects at runtime and i'll actually show you how to do that it's also called when the scriptable object is selected when you click on it in the editor although i'm not sure why and get brings also seems to be confused on this on enable is called when the scriptable object is loaded so this is called after awake it's called if the current scene reloads and a scriptable object is being used and it's called if we enter play mode and the scene that loads also references a scriptable object on disable is called when the scriptable object goes out of scope or is unloaded so if a scene is loaded and there are no mono behaviors referencing the scriptable object then on disable is called if the current scene reloads and is currently referencing a scriptable object on disable is called it's also called in play mode when you enter a scene that has a scriptable object so on disable is actually called first before on enable is called which is interesting and on destroy is called when the script is destroyed so since this is a project level asset this could either be that you destroy it through your script in code if you delete it from the assets folder manually or if you created a new scriptable object at runtime and you either destroyed it quit the application or exited play mode and you can read through the rest of this forum if you're interested on more of the intricacies of the execution orders it's quite complicated and it seems like the documentation doesn't clearly explain the functions well and when they're executed so just to show you an example i've put the debug.logs in these functions and this scene has our zombie which this script references our enemy scriptable object that has these debug.logs so if we click play you'll see that ondisable is called first on validate is called and on enable is later called and i forgot to mention that on validate is basically just called when a script is loaded or the value of the script changes in the inspector which this can be good for debugging be careful if you use these functions because the execution orders can get a little messy make sure to print out the execution orders because if you're trying to reset something you see awake was not called here it's called when a scriptable object is created but you see if we create a new scriptable object right click create scriptable object enemy press enter you can see that in the console awake and on enable is called so just keep that in mind and now i'm going to show you how to instantiate a scriptable object through script so i've already written a script just to show you how it works this script is called instantiate scriptable object and this is just a normal monobehaviour so all you need is to get a reference to your scriptable object and this is the instance we're going to create and then you can call this method scriptableobject.createinstance and then you pass in the type of the instance that you want to create in this case we want to make an instance of type enemy scriptable object and you have to cast it using type of so we can get the type and pass it into this function and then all i'm doing here is equaling it to test which you actually have to cast it this is a cast meaning we're converting whatever type this is returning so this is returning a scriptable object and we're casting it to an enemy scriptable object so that we can easily reference it in our script and its values and then we can use it as normal we can do debug.log test enemy attack type attack damage you can access your properties as so and then if you want to destroy the scriptable object there's a function you can call called scriptableobject.destroy you pass in the scriptable object that you made and then this is just how many seconds you want to wait until it is destroyed which is a float so just to show you how this works i'm going to create an empty game object and attach this script here and then if we press play you'll see that first on disable is called twice then on validate then on enable then on validity again then on enable again then awake then on enable and this no reference exception is just because i actually didn't pass in an enemy attack type to the scriptable object but besides the point after that on disable is called and then on destroy and undisable is actually called again after that so you see there's lots of stuff going on here so just be careful on the script execution order additionally i'm not going to cover it in this video i'm going to cover it in another video there's another use for scriptable objects called event based messaging and it's where the scriptable object kind of acts as a middleman between two different scripts or components so we can decouple the code which basically means to separate or to remove dependency onto components and when you remove dependency it makes your life easier makes it easier to test more flexible and easier to debug so that's not going to be this video because that's a separate topic but it is a great way to architect your game to be flexible and easy to change for both the coders and designers and another thing i want to mention is to make sure you don't accidentally destroy your original scriptable object through code because you only have one instance of it in your project so if you destroy the original one then you'd lose that scriptable object with your values and finally another usage is replacing enums so if you're not familiar an enum is just a collection of different names and each name corresponds to its own so for example this has an id of 0 1 2 3 and usually we use this when we want to have a list of ids that we want to give something or a list of actions or states that a game object performs so this is actually used pretty commonly in state machines for example the player can be in a walking state running state idle state and each of those would be a separate entry within an enum just as here we have an attack type and we have different kinds of attacks that we can reference easily now the issue with this is that since each of these corresponds to an id what if you want to delete one but your code references an id of one well now since you deleted the original one which was a jab now the new entry will be test which has an id of one and so what ends up happening is that to sidestep this problem developers will just put none instead of actually deleting the attack type to avoid having to change ids everywhere and also for designers this isn't really extendable because designers have to go into the code they have to add an extra enum if they want another attack type because the designers will probably want to be adding attack types or variables in so they want to add dodge and in doing so they might mess up some code somewhere because the ids don't match so to avoid this you can just use scriptable objects similar to this enemy attack type here you have your attack damage range and sound and let's say you wanted to add another kind of attack you can just make a new scriptable object of type enemy attack and you can just name it anything you want goblin attack swing you can easily plop in your values here and then you can just drag and drop it into whatever game object needs the attack instead of using enums so that's just a side mention on another usage so yeah i hope you enjoyed this video and you found a lot of this useful and thank you once again to magnations for sponsoring this video if interested the link is in the description so if you did enjoy this video make sure to like and subscribe and hit that bell notification icon as it helps me out a lot and you can get notified on all the new releases so with that i'd like to thank my patrons who helped make these videos possible so thank you so much for all of your support if you're interested the link is in the description i offer source code early access to videos exclusive tutorials exclusive discord channel and insights onto what i'm working on so with that i'd like to thank my new patrons in the supporter tier we have thank you so much in the enthusiastics here we have jinsang gim asm rafael follow tomorrow ltd m games jack chong wang wu fili stargate media marco horodev brett kolja fane matthew mike aj max and luam thank you so much for all of your support it is really really appreciated it helps me make these videos possible once again link is in the description and if you haven't joined our discord channel be sure to do so you can chat post memes or ask for help so thank you again for watching everyone and i'll see you next time [Music] [Music] [Music] you
Info
Channel: samyam
Views: 68,133
Rating: undefined out of 5
Keywords: scriptable objects, unity so, so unity, scriptable objects unity, unity scriptable objects, enum, instance, scriptable object instance, scriptable object enum, scriptable, better data in unity, how to scriptable objects, how to use scriptable objects, ScriptableObjects, scriptable object, game architecture, How To Use Scriptable Objects in Unity, unity scriptableobject tutorial, scriptable objects tutorial, scriptable object tutorial, so tutorial, ScriptableObject Tutorial, better
Id: cy49zMBZvhg
Channel Id: undefined
Length: 20min 45sec (1245 seconds)
Published: Mon Jan 24 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.