Ultimate Object Pooling | Unity Beginner Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
gretings game developers the time has come to build the ultimate pooling system in unity you guys like the ultimate event system it forever changed how some of you develop games expect no less from this video Let's dive right into it here's what we're going to build this is you you are a cannon and you can shoot cannon balls you have to hit those trolls hidden in barrels when you hit them they explode that's it so we are spawning enemies cannon balls and particles all those great candidates to be object pulled and disclaimer I misspelled Canon everywhere like a dumbass anyway first of all why is object pulling important in unity instantiate and Destroy expensive methods instantiate is simply expensive and Destroy is bad for the garbage collector garbage collection is necessary in C we can't avoid it but it can slow down your game and create random CPU spikes when you least want it if the player experiences frame drops during an intensive fight be ready for some emotional reviews for object pooling to make any sense you need to have an object that you need very often and usually for a short period of time think bullets bullet shells bullet impacts particle effects enemies and so on shooting can really become a performance nightmare instantiate the bullet instantiate the bullet shell instantiate the hit particles that's three instantiate and you shot once instead of instantiating bullets when you shoot and Destroy them when they hit something you create let's say 100 inactive bullets you keep them ready in a pool whenever you want to shoot you take a bullet from the pool you configure it and then you shoot it then instead of destroying the bullet you deactivate it and throw it back on the pool the configure step is really important and that's a secret to good object pulling once you fall in love with object pulling you will never spawn game objects the same way ever again but but there is one challenge that will hit your object pulling dreams really hard and will haunt you the problem is about the granularity of the objects to pull let me explain if you need something small and general many many times like a bullet this is Trivial get a bullet use it put it back on the pool but if you need something big and complex many many times like enemies loot crates or even powerups you might have 10 or 20 different types of enemies each with their own model models textures weapons and abilities how do your object pull this option one you create one pool per enemy so you get the enemy and use it directly this results in many pools and you will most likely end up with a dictionary mapping a key to a pool option two you create one pool of a generic enemy and configure the enemy object when you need it this means that the enemy prefab needs to have everything to be able to become any type of enemy all right that's for the explanation there are no no silver bullets here one way or another you will have to compromise now for an ultimate video I'll show you three ways to do object pulling in unity and at the end of this video you will know everything you need to reuse that system or build your own because remember no silver bullets let's now get to work here's a starting scene with some small environment and some models by the way you can download those models I made the link is below there's also some of the source code which I recommend you don't copy and paste if you are here to learn all right after some basic setup the is a cannon it is rigged and has the muzzle at the right place as well as some particle effects the animator is very simple it transitions from idle to loading and back using a Boolean called loading there's a spawn location where enemies will spawn the cannon ball has a sphere collider and rigid body the Collision detection is set to continuous dynamic because in my version the ball is pretty fast and this improves the accuracy of collisions I throw the rotation for E of use but you could also not do it finally the enemy it's also rigged and has some accessories like spikes and a pack of dynamites and it also has two animations idle and walking now nothing else is done we have to code all so let's create a scripts folder and inside I will create a c script called Cannonball we will first implement the game using instantiate and Destroy and later we will refractor it that way you will understand how to refractor your own project hopefully the two main fields are destroy after that we will use to destroy this ball after 5 Seconds hit VFX will be the explosion that we spawn when this ball touches an enemy we get the rigid body reference in a wake and in start we can directly schedule the destruction of this object after the delay then this ball is pretty dump it won't decide when to be thrown or explode another script will tell it that so we have two public methods hit will spawn an explosion schedules the destroy of that explosion game object and here I forgot to put dot game object sorry for that and since explosion spawned we can destroy the ball directly the throw method will just take a force Vector as input and apply it on the rigid body save put the script on the ball and either you create a new particle system or use an asset I have downloaded one casual VFX pack and I will use that one the cannon ball is ready like that we can make a prefab out of it and move on to the Canon the Canon has an animation for shooting and this animation has an event called shoot this will be our signal to spawn the cannon ball so the shooting is mainly animation DFT let's make the Canon script and put it on the Canon the base code is simple we need a reference to The Cannonball prefab a reference to the muzzle transform then we have the shooting force the delay after which we can start shooting when the game starts and the rate at which we can shoot finally we also have a reference to the muzzle flash and in awake we get the animator and for maximum performance we can convert the animation parameter name from string to an INT and use that field instead I prefer this than risking to type two times the same string can you imagine the horror in update and I assume you did this at least once before we check if we can shoot and we check if the player clicked on the mouse if yes we update the timer and call prepare to shoot this method could do more but for now it's just starts animation I simply like organizing things in methods early on and remember the animation event calls shoot so in that method we change the loading parameter back to false and instantiate a new canon ball we apply some force and play the muzzle flash safe and in unity we put the cannon ball prefab in place is the mule into the mule slot shooting fors at 25 delay at two rate at one and Link The Flash VF let's try it out no surprises here we spawn cannonballs and they destroy themselves after 5 Seconds let's work on the enemy I will make a new enemy script and put it on the enemy the enemy is super basic it will just go forward which is pretty realistic considering that the thing inside does not really see where it goes I challenge you try to act smart while walking a barrel or maybe just like And subscribe this video that's also fine super quick we get the references we move forward using the velocity and when we collide with the cannon ball we tell the ball that it got hit and we explode this means for now that we destroy the game object let's try it out okay that's way too fast maybe a speed like 0.5 is fine also remove the sphere trigger that I had for some reason I'll actually not need it and let's make a prefab out of it last CP before we move to object pulling everything I create an eny spawner and put it on the spawn location Unity 101 we take a prefab we track a timer and we spawn the prefab after every X seconds that's all very simple very inefficient in unity drag the enemy prefab in place set the delay at one and the raid at two for example and that's it we are ready for phase two finally all right here's a quick plan of what we are going to do we will apply object pulling on the enemies on the cannon ball and on the cannon balls explosion each time we will do a different implementation let's start simple with the enemy spawner make a a new script called pullable enemy spawner and put it on the spawn object I'll copy all the content from the enemy spawner in it and we will start from there at the top import unity engine. pool then add a private object pool of type enemy and call it enemy pool and in awake we have to create the pool the white text is simply the named arguments you can leave them out but I like that it's super explicit and easy to read at least for the first time we have to Define methods when the object is created when we take it from the pull when we release it and destroy it we can also give an initial pull capacity let's go over the object pull methods one by one to create new objects of course there is no avoiding it we are using instan shate we create a new enemy keep it inactive and return it this method is called whenever the pool is empty and we need a new enemy now once the pool has objects in it the take from pool method is called whenever we get an item from the pool here we simply activate the enemy object on enemy destroy will not be called here but let's define it as understand from the documentation this will only be called when you call clear or dispose on the object pool this is useful when you switch scenes and you know you don't need anything that you have pulled before finally on enemy release is called whenever an object is put back into the pool here you want to deactivate the object unsubscribe from any event and so on the methods are all ready now refactor the spawn code to use the object pool instantiate takes a position and rotation object pool get that does not so we have to get the object and do our changes afterwards since this video is about performance gains let's push the optimization further getting and setting transform. position and then transform. rotation is apparently not efficient as the C code has to switch four times to native code this is why there is a get position rotation as well as set position rotation method you then have two times less round trips to the native code whatever if you test this now it works but it's it's not done yet we have to refactor the enemy class uh as well right now the enemy destroys itself when it gets hit that's a no no now there is an object pull in play one solution is to add a delegate for example an Unity action on death and instead of destroy we invoked that event what this solution does it completely removes the creation and destruction of the enemy from the enemy club now in the spawner script we have to register method to the on death event in this method we don't destroy of course we release the object it goes back to the pool and on release this we unregister from the event the enemy has zero knowledge about the pool that's not bad all right let's try it out enemies are spawning and get inactive when hit the magic of object pulling is that any inactive object is then directly reused when the next one spawns perfect highly efficient oh and now they are confused I sure it is on purpose do you know why this happens we are reusing enemies those are rigid bodies with velocities and angular velocities in our code we are taking care of the Velocity but not the angular velocity this means that what seemed to be a new enemy still has the effects of whatever happened before so when you do object pulling you have to think about properly resetting the state of the object now let's talk about configuration we don't have one enemy we have enemies with and without spikes and with and without dynamite and we could have even more variations let's use some scriptable objects and enums to make a simple configurable enemy I'll create a new script called enemy configo then first we go into enemy and I will add two new blocks first an enam item category and second a standard C class with inside a public item category and public game object save and open the enemy prefab the enemy setup is simple we want to link an enam to a game object next the enemy config so will simply hold a list of item categories done next step is to add a configure method in the enemy script where we can for example reset the velocity and other things I convert the configuration received as parameter to a hash set of enams and this could have been done once in on enable of the scriptable object actually lastly we Loop over our configuration and enable only the one that matches all right someone needs to give the enemy the configuration and that someone is the spawner so the spawner will have all enemy configurations in spawn it will randomly choose one configuration and tell the enemy to configure itself using that data before we can test we need to create some scriptable objects I'll create uh four enemies one with nothing one with dynamite one with uh spikes and one with dynamite and spikes and we put them all in the list on the spawner now each enemy is randomized with a configuration awesome one object pool can create different types of enemies as you can imagine we can push the customization really far all right that was the first implementation pretty straightforward just use the object pool directly in your manager class for the next implementation we are going to put an object pool in a scriptable object create two new C scripts an object pool so and an eye pable the structure is like this the scriptable object has a pool and objects that we put in the pool can implement the ey pable interface this means that the pool can be used for any kind of objects and you have the option to customize how each object behaves during the different pooling life cycle method the interface is going to have five method register pool with the object pool SOS parameter and the create take release destroy methods the object pool so is a scriptable object we need to put some public field one for the prefab the default capacity and the rest is a little nice to have I use that to offset the default spawn position and rotation of the object like maybe you want to spawn your things very far from your main world or for whatever reason then we Define the object pool of game objects and we Define each method now this should not be special to you anymore in create we instantiate and return the object what's new is that we try to get the ey pullable component and if that works we register this as a pull and and call on pool create object maybe that object will run some extra Logic the same in on take from pool we check if you can use the iable interface on return pool we do that before and then we deactivate object same with destroy the last two methods are public one to get and one to release this how we use that object pool ASO what is missing is to force the full clearing of the object pool since now we have an S so multiple scenes in your game could use the same pool so when you are switching scenes you might want to either clear all the pulled objects and restart or you move those objects to the next scene keep this in mind in unity let's create a new object pull object and let's drag and drop the canon ball inside next we have to update our Canon and our canon ball script in Canon we need a reference to the object pool ASO and then in shoot instead of instantiate we have to get an object from the pool set its position and rotation and since we expect a cannon ball we can get the component and we will configure the object and call thr in in the canon ball script we should implement the I pullable interface and keep a private object pullo filled what's important is that we have to remove the destroy statement from the start method except register pool we don't really need the other interface methods the new configure method will reset the velocity and for the sake of this tutorial we will invoke release later this is not pretty but it works release is our new destroy method for the canon ball we cancel all invocation I will tell you why in a second and since we know the object pool we release our in hit instead of destroy we call our new release method and this is why we cancel invocation since objects are reused if we don't do that line we might pull a cannon ball that as soon as it becomes active the scheduled invoke kicks in and automatically releases the ball you don't want that so maybe you can Implement a time to Le timer for auto relasing the object it might be cleaner the setup is easy we drag and drop the scriptable object on the slot of the cannon all right it works cannon balls are now part of the pool party this implementation is awesome because you can give the same object pool to multiple objects everyone who needs a cannon ball here you go use this pool all right are you ready for the last implementation remember no Silver Bullet we're exploring multiple ways to do the same thing our last implementation is called super object poolo because I prefer this one over the previous one interfaces are nice but if you implement I pable a lot you will start having repeating code so we create a new super object pool so that is obviously a scriptable object and we create an abstract class pullable mono Behavior everything should be familiar it's just slightly different we have an action on release that can be used by other scripts to get notified when this object gets released we have the register pool method with the references to the pool the object has a public release method to release itself and invoke the event and finally we have some virtual methods that the concrete implementation can overwrite I don't use the on poost get in this video but this is just to show you some ideas maybe you want to perform some action after the object has been taken from the pool like really as a last step the super object poolo is very similar to the object poolo the difference is that it uses a pullable mono Behavior everywhere so we know what we have and we can call all methods directly without trying to get a component if you understood the previous implementation this one is working the same way all right we will use this pulling technique on our hit VFX object that is being used in the cannon board script this means that we need a super object pullo and we have to change our heat method now pullable mono behavior is abstract heat V effects will Implement its own class and if we want we can cast it to a pulled particle system for example that we will create right now that class looks like this it has a reference to the particle system and we hook into the stop action callback to get notified when the particle system has finished and we call release release comes from the pullable mono Behavior All right so cannon ball needs a super object pool let's create one your particle system prefab will need to have the pulled particle system mono behavior on it now we can put the prefab into the Super object pool and put the object pool on The Cannonball all right there you go three different ways to use unity's object pool directly in your class as a scriptable object with interfaces or as a scriptable object with an abstract mono Behavior I know I know you can push the abstraction pretty far but I've tested also other variations and came to the conclusion that unity's object pool is pretty abstract already right pushing the abstraction too far can be counterproductive and you might end up with an abstract object pool Factory Builder just saying be careful out there with all that being said thank you very much for watching I hope you like this video now go work on your game and I'll see you next time oh by the way we have a Discord Community you can join the game death Kingdom the link is below in the description we have fun and we discuss Unity stuff a lot as you can see this is a a new setup it's not a new setup normally the camera is behind me pointing in this direction now I just sit at the desk put the the green screen behind and uh it's faster to record I think it's so much faster now I understand why everyone is sitting at a computer and just talking straight to the camera straight in the mic everything is ready I think I'm going to use this for a while
Info
Channel: This is GameDev
Views: 2,067
Rating: undefined out of 5
Keywords: make my dream game, how to make a game, made with unity, game devlog, gamedev vlog gamedev, indiegamedev, game dev, indie gamedev, indie game, unity 3d, unity3d, game development, make a game, tutorial, guide, game engine, unity hub, blender 2.8, blender 3.0, blender 3, madewithunity, iOS, Android, mobile game, smartphone game brackeys, thomas brush, jason weimann, jonas tyroller, dani, danidev, blackthornprod gamedev, unity, install, how to, install unity
Id: zV8E59NoWZ8
Channel Id: undefined
Length: 19min 27sec (1167 seconds)
Published: Fri Dec 08 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.