Automatic object pool (Unity tutorial)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video i'm going to show you a system that will automate object pooling in unity you can easily reuse the code for just about any game object in any project it is written in a way that makes it easy to implement or remove stuff without breaking it and so right now this little sample scene it's creating enemies and heroes without an object pool they're just getting destroyed and here i have the prefab and now if i say you know what i want this thing here to be pulled all i have to do is attach this pulled object script and as you can see now a hero pool was created and yeah it's an object pool and it's working on the hero prefab now of course i can do the same with the enemy take the anime prefab give it the object script and now we have an enemy pool and if i move it at some point let's do it like this nothing breaks it just doesn't use the pool anymore of course this system is not perfect because making things more generic and automatic is going to cost you a bit of performance here and there if you want maximum performance you just got to go in there and tailor everything exactly to your game but on the other hand with this system you're going to save a lot of development time and so i think that's that's often the case like the pros and cons of where you find that balance between how much time you want to spend on performance and how much time you want to spend on getting things done more importantly this is a tutorial for you to learn new things and think differently maybe so when you come up with your own solutions you have more tools in your tool belt that said you can of course just download the project from the link in the description and use it in your own games also if you like this kind of content and want to support me to make more of it please consider subscribing and liking this video if you're new to object boost i just made a video for total beginners so you should probably check that out first this one here is more for advanced users because we will be using static methods method overloading generic parameters and action events but don't be scared i will do my best to explain everything for people who are new to any of those concepts also feel free to ask any question in the comments and now let's finally start the entire system consists of three scripts and i'm gonna go through them from top to bottom just a brief overview and then we're going in reverse order in good detail so let's start with the creator that's basically the one that's going to replace the instantiate the unity instantiate with create and the unity destroy with kill you can see those are static methods so we can call them from anywhere we don't need a reference to any creator instance and then it just checks if an object that wants to be created is supposed to be pulled and if yes it checks if there is a pull and if no it creates a pull if yes it gets the right pool and then it turns the pool which is good alt object pool just like tell me you got anything inactive there give me that first if not create a new one and when something gets destroyed it tells the object pool here you can have that back just put it on your list for the next time i need something and lastly we have the pooled object script which you've already seen that's the one we attach to a prefab and it's actually pretty simple first of all it has a reference to the pool it belongs to because once it gets created or taken out of the pool it it's not really connected anymore so i have this for putting it back in there then we have two methods called activate and deactivate now of course we set the game object active or inactive we are also calling those events and that's really just a handy way to like create a delegate or other define a delegate and create one in two lines we just do it in one line and make sure to include the system name space and then it's activated and it and we're just doing that in case um other components want to listen to it it's it's not really needed in the system right now but i wanted to include it because i use it quite a bit and i think it's it's a handy way to make sure that other scripts or things can can know that this just got activated and you can of course make static say public static event action and now you know okay for example when an enemy got created you can keep track of how many anyhow that's just optional oh and the equals delegate and then this like empty that's just to make sure that if we call it and no one is listening we don't get an error message so we don't have to do like invoke do a null check and then do it we can just activate it don't really care that no one is listening actually in this project no one is listening to it right now uh yeah but maybe it's useful and yeah that's pretty much it for the pool uh sorry for the pulled object so it sits on the prefab there we want to create instances of and that way the creator is going to know oh you want that thing to be pulled and the put objects are going to be handled by the pool and it's pretty much what you expect from an object pool first you have the prefab that is the source that you want to create a lots of instances of and we are going to refer to everything here by the pooled object script because we already know if the pool is handling it it must have this pulled object script otherwise it never gets in here and then of course we have a list with all the pooled objects so those are the ones that are taken out of the scene again in wake we make this a new list then we have the public method that returns an instance of a pooled object we pass in a transform as parent and then i just made a field just bit for readability set it to null and that's the one we're going to return in the end and also called activate on and like any other pool first we check if we have some inactive ones on our list so if the account is bigger than 0 we get the first item also remove it and then that's our object that we're going to return otherwise we are going to use the good old instant shade and i'm going to talk about this parent thing in a moment because it makes more sense when you see it from the crater and of course when we create it from scratch we also tell it oh by the way this pool right here that's the one you belong to so the object pull this one in the pulled object we're setting that when we create it the very first time inside the pool and that is important because when we return an object or rather when an object gets destroyed it needs to know which pool it's going to go in and that's what the crater handles so the crater is then going to find oh this is the pool you're supposed to go in if this field is set and then the equator is going to call return object on it and that's pretty much exactly what you expect we add it to the list and then we call it deactivate which is going to set the game object to inactive okay and now on to the most important thing the creator it's class with lots of static things and the reason is static is that way we can call for example create from anywhere without even needing an instance of creator so for example the stage manager where we make the new hero we say gameobject new hero and then we say creator.create and that's very similar to when you call instantiate so now we just say creator.create and see this is this the name of the class and not an instance and then we pass in a game object which is a hero prefab so this one's a game object we can also use a class and pass that in but we get to that in a moment first let's go through this one here so we have a dictionary where we have a pulled object and a pool so pool is the key put object the key and pull the value called pulse and then we just right away make this a new one and so this one is basically just to make sure that for every prefab that we're going to put we want to have a pool and we need somewhere here to to connect those two so in the static method create that's going to return us a game object first let's just make a new field call it new instance set it to null and now what we do is we take the prefab that was passed in as the source and we see if it has this pulled object script on it simply by saying pull object pull prefab so this is a new field and german then we just say prefab the parameter dot get component pulled object and the nice thing is this is not going to return an error if it doesn't have it then it's simply going to set it to null and then we can work with that so if the pool prefab is not equal to null meaning okay so our prefab has this pulled object script on it now what we do first of all we're gonna get a pull so once again make a new field and then we say get object pool and we pass in the pulled prefabs so and i i call it pulled prefab to make sure this one right now the field the script is the one on the prefab later we're going to use the one of the new instance right now we're still working with the prefab one so when we say get object pool and we pass in this component of the prefab let's see oh sorry f12 so this one returns a pool the get object will pass in make a new field again set it to null and first of all we check if our puts our static dictionary already has like this instance no sorry this component of a prefab in there and yes then it's easy we know okay which pool to return it's the one that's already connected to it so the key of that otherwise we're gonna have to make a new one so we know oh okay now we we just try to create a game object that out of a prefab that has this pulled object script but our pool dictionary doesn't have any of that in its key so make a container so we just do like a a new game object and this one here is simply the name so prefab.gameobject i just used that one so in this case if the prefab is called hero then we would say hero plus pool that's the name of the new game object then we have our pool that we're going to return and in this case we're just going to add it as a component to the game object we just created then we're also going to tell this pool which prefab it's supposed to create remember that was the very first one here and lastly now that we created it of course next time we want to have it in our dictionary so boots is our dictionary and we add the put prefab as the key and the pool we just created as the value so of course next time we pass that in we'd say oh yeah i got the key here and so the pool you want is the one that's connected to this key and then we return the pool so it's always going to return us a pool and if there wasn't any it just makes a new one so now that we have that the get object pool we have a pool and now we're actually going to create a pooled instance so make a new field call this one pool instance and then we say pool dot get instance the pool was either created or we fetched it and then we pass in a parent and i'm gonna get to that in a moment and then we just take whatever the pool they just created that's the one we're going to return it and otherwise if it's not supposed to be pulled it doesn't have that script on it we just use instantiate the good old unity instantiate and we just don't really care about any of that and then we return the new instance and before we get to that a little preview we have of course kill and that's the one that's going to replace unity's destroy and so we pass in a game object the killed object and then we do something similar we first check if the [Music] now the instance that got returned has the pulled object script on it and so if yes if that is not equal to null it has one and also and that's important the pulled object has its pool field sorry this one here signed so both must be not equal to null in that case we can say pull object dot pool return object so i will call this method here in the pool return object and of course we just passed it in gets added to the list and deactivated and of course if it doesn't have a pull object script we just destroyed the good old way and the reason i'm checking pulled object dot pull and make sure that field is not equal to null that's really just for the cases that you placed an object that's supposed to be pulled in the scene yourself like when you build the scene you might put some enemies in there and thing is in that case they weren't created by the creator and they weren't created by the pool either so they never went through this function which assigns the correct proof actually since the creator is all automatic when you build the scene the pool doesn't even exist like the game object doesn't exist the instance doesn't exist yet that's all automatically and of course you would get an error there because then you say sorry was it because then you would call this pulled object dot pool and you want to return it and it says i have no idea which pool i'm supposed to go to and of course you can write your own way around that i just figured you know this doesn't happen that often and it's not that important when you picture like a whole game like okay you have maybe a few enemies in there then okay just destroy those but all the other like thousands and thousands they are going to be pulled and of course totally up to you and now this is pretty much the system now let's go over some details i left out and so the first one is the transform dot parent and here in the parameter it says equal nut and that way it's an optional parameter i give it a default value of neither and that means i can call creator.create and only pass in a game object in that case it's just going to take now whenever i use a parent here it's going to take the default value but if i call it passing the game object and also transform then it's going to overwrite this null default value and use whatever i passed in when i call this method and the reason is that first of all i want by default all objects to be parented to the pool just to you know tidy up the scene a bit and so if we call this without passing in anything it's going to be null and that means it's going to call the pool dot gets get instance and it's going to pass in null and that's where the pool actually checks it now so we have 9 here because nothing was passed in and when it instantiates the prefab or the instance sorry of the prefab for the first time then what we're going to do is we make a transform new field new parent and in case you've never seen this this is an if else statement all in one line so what we're doing here is we're saying new parents equals to and then we check for condition is parent equal to null if yes we're going to take this value and assign it to a new parent if this condition is false we're going to take the second one the parent and assign that as a new parent and of course transform here that's referring to the transform of the pool like whatever the game object this pool is attached to so if it's not we say okay the pool is just going to act as the parent and otherwise we might be overwriting that and the reason for doing that is pretty much that i want to use it for ui elements as well so for game objects you could just say like creator.create and then in the next line whoever creates it sets the parent itself so maybe the stage manager i would say i want to be the parent and it could just say crater.create give me this and then in the next line like new enemy dot transform dot set parent pass in this one would be a problem but when you create ui elements and you instantiate them and then in the next line you set the parent you might end up with quite a mess because they might be parented to something that is that doesn't have a canvas and that can really mess up the layout and then in the next line you parent them to something that has a canvas and the layout is still messed up and so for this i want to be able to call instantiate and pass in a pattern that has a canvas right here because if i pass it in right there in this method it's not going to get messed up and that's really just the reason and now the bonus of course is you can uh call this in one line if the stage manager says i want to be the parent you could say in here creator dot create instead of just passing in the game object you could override the parameter of transform and say transform which is the transform of this script and now there is one last thing which is a static method that takes in a generic parameter and it's also called great and the reason i did that was because for example when you have the stage manager you might have a prefab that you referring to by a script that's attached to it that's quite common so if you already know okay enemy is the most important script i want to refer to the prefab right away by enemy don't have to use get component but other times you might not even have a script you want to refer to and you just say game object like hero prefab and i want the creator.great method to work with both and it's actually pretty similar to the original instantiate so if you double click it hit f12 you can see uh here public static t instantiate t t original apparent and condition for t is it has to inherit from object or so it has to be an object um apart you can't really go into the original code here from what i've heard it's quite expensive to get a look at that and i was trying to do it all in one method and it was getting pretty messy so i decided what i'll just use two methods and by using overloading meaning i can have method with the same name or multiple ones as long as the parameters are different this script is just going to figure out when i call creator.create which one i want to use if i pass in a game object oh it's it's this one if i pass in a component then it's going to use this one and so t is just like a it's a generic so it can be anything and here i made the condition it has to be a component so anything that gets attached to a game object can be passed in here as t and when i pass in a prefab that's basically when i define what t is so it could be a class like the enemy so when i call creator.create and i pass in enemy prefab it's an enemy class you know oh t is an enemy so that's what we're going to return to an enemy instance and so we can say t new instance equal to nine and here we're doing the same we're saying put prefab check if it has the component and we can just say prefab.getcomponent pulled object it's just the same it says okay i assume you want like other components on the same game object that t is attached to and so yeah that works quite nicely everything here is the same the get object pool get one or create one and the slight difference here is where we say return pooled instance we don't return a game object we return put instance get component t once again t is defined when we call it so it's going to return that and otherwise we just use instantiate and as i just showed you instantiate2 can take in anything it can be game object or a component and then we're going to return the new instance and then of course we want that for kill 2 which i don't have so i figured maybe you want to do that as a little exercise on your own so make sure that there's another kill method that takes in a generic parameter and then it's kind of similar to this one it's actually even a tiny bit easier to write so yeah maybe do that as an exercise if you think like i really want to know how that works and i can't figure it out let me know in the comments and of course if you have any kind of question feedback criticism just let me know also i'm always open to new ideas on what to make tutorials for i just got a quest so probably going to do some vr content and i think the next video is going to be me announcing that i'm going to do unity 101 coaching which is going to be free so if you're interested in that make sure to subscribe look out for that and otherwise thanks for watching and goodbye
Info
Channel: Shackman creates art and games
Views: 466
Rating: undefined out of 5
Keywords: unity object pool, unity automatic object pool, unity advanced object pool, object pool, c#, c# unity, c# unity tutorial, unity tutorial, unity game tutorial, unity 2d, programming tutorial, learn unity, game dev, unity gamedev, unity indiedev
Id: dZOCQpFolUA
Channel Id: undefined
Length: 25min 52sec (1552 seconds)
Published: Fri Jan 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.