(Better) Object Pooling - I Didn't Like My Old Solution

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right yes i've already made videos on object boolean and does the internet really need another object pooling video no not really but while working on a prototype project i wanted something a bit slicker and easier to use than what i've had in the past i wanted a system with no object pool manager objects that can return themselves without needing to find the object pool a system that can store a reference to a component not just the game object which saves on get component calls and can help keep my code cleaner i also wanted an interface to make the initialization of objects easy and consistent this lack of consistency was a big source of error in my last game now if you're just here for the code you can get it on github there's a link down below but you should definitely stick around just a bit longer to see how the system is implemented because it might be a bit different than what you're used to so if you're new to object pulling you might be asking well what does this do and why do i really need it the short and simple answer is that object pulling recycles objects this helps reduce lag spikes from creating and destroying objects which in turn can give your project a significant performance boost and you can see object pooling in action as i click a button to spawn an object and the object falls into a trigger which disables the object allowing the object to be reused clever simple and definitely useful so how do we go about implementing this new solution first there needs to be an object that is responsible for the spawning of the objects this object owns the pool and needs a reference to the object being pulled the spawner object then creates an instance of the object pool and sends a reference to the prefab to the pool so it knows what object it is storing and what to create then to get an object from the pool all we need to do is call the pull function additionally the objects being stored need some logic to work with the pool the easiest way to attach that logic is just to slap on the pool object component to the object prefab this default component will automatically return the object to the object pool when the object is disabled for me this is pretty slick and pretty easy to use and a big improvement on past systems that i've created but now on to the hard part or maybe it's the fun part depends on how you view it let's look at how it all works and full warning here we're using generics interfaces and actions so this isn't the easiest to understand solution and i'll link a couple videos if you're unfamiliar with those tools to get things started i created two interfaces the first one could be useful if i ever needed to pool non-model behavior objects but admittedly isn't 100 necessary at the moment the second interface however is definitely useful and is a big part of the system working smoothly but let's start with the first interface which helps define the object pool it has just two functions a push and a pull it is a generic interface where the generic parameter is the type of object that will be stored this works nicely as then our push and pull functions know what types they will be handling and again is this strictly necessary probably not but i did it anyways the second interface is used to define objects that can be in the object pool when used as intended the object pool can only contain types that implement the ipoolable interface this interface has an initialization function that takes in an action this action will get set in the object pool and is intended to be the function that returns the object to the pool this action is then intended to be invoked inside the return to pool function that doesn't all make sense well i think that's actually kind of reasonable it can feel a bit circular let's take a look at the object pool definition or at least the definition i'm using for monobehaviors the object pool itself has a generic parameter t and implements the ipoolable interface t is then constrained to be a monobehaviour that must also implement the ipoolable interface next comes the variables and the properties for the object pool first are two optional actions these actions can be assigned in one of the constructors this allows you to call a function every time an object is pulled out of the pool or pushed back to the pool this could be used for sound effects increment a score counter or just about anything it seemed useful so i put it in there next is the stack which is a first in first out collection that holds all of the pooled objects since we know the object being stored is a monobehaviour we also know it's attached to a game object it's this game object that will be instantiated if and when the pool runs out of objects in the stack lastly i added a property to count the number of objects in the pool and i stole this directly from the unity object pool solution when we create a pool we need to tell it what object it will store and i think the easiest and best way to do that is to inject the object or the prefab using a constructor in some cases it's also nice to pre-fill the pool so the constructor takes in an optional integer value of objects to pre-spawn using the spawn function the second constructor takes in a prefab as well as references for the pole object action the push object action and a number of objects to pre-spawn moving on the pull function is called whenever an object from the pool is needed inside there we first check if there's objects in the pool if there are we pop one out if there isn't we instantiate a new copy the game object is then set to active and the initialize function on the i pullable object is called and this is where the ipoolable interface is allowing easy and consistent initialization of the object notice also that we are providing a reference to the push function this is the secret sauce the push function is the function used to return an object to the pool this means the spawned object has a reference to this function and can return itself to the pool and we'll take a closer look at how this happens in just a bit then we check if the pull object action was assigned and if it was we invoke the action and pass in the object being spawned and finally we return the object so that whatever object asked for this new object can have a reference to it then moving on to the push function which is called to return an object to the object pool it's pretty straightforward it takes in the object and pushes it into the stack it then checks if the push object action was assigned and invokes the action if there are any subscribers and lastly the game object is turned off as a side note the turning on and off of the object in the pull and push functions is not 100 needed but it is there to ensure the object is toggled on and off correctly and to help keep the initialization functions clean every object that goes into this pool needs to implement the ipoolable interface now in some cases you may want to implement the interface specifically in a given class but both as an example of how to implement the interface and also to provide an easy to use and reusable solution i created the pool object class this component can simply be added to any prefab to allow that prefab to work with the object pool when implementing the ipoolable interface we should set the generic parameter to the class that is implementing the interface pool object in this particular example the class will also need an action to store a reference to the push function the value of this action is set in the initialize function which in turn gets called in the pull function of the object pool moving on the return to pool function in this particular example is called when the object is disabled this means all we need to do to return the object to the pool is turn the object off or disable the component inside the return pool function we check if the return to pool action has a value and if so we invoke the action and pass any reference to the object being sent to the object pool now the null check shouldn't be necessary but it avoids an error being thrown which depending on your perspective may or may not be a good thing to make the object pool a bit more useful and user-friendly i've added several overloads to the pull function these allow the position and rotation of the object to be set when pulling it thus mimicking the functionality of the instantiate function i've also created functions that return a game object as in some cases that is what is really needed and not the poolable object component itself all right if you're still with me i wanted to look at one more example and that's because actions and delegates can be a bit confusing and so i thought one more example might be useful and that is using the second constructor and assigning functions that will be called every time an object is pushed or pulled from the instance of the object pool in this example i've added the call on pull and call on push functions notice that they must have the input type that is being stored in the object pool and again the idea here is that these functions could trigger an animation a sound effect a ui counter just about anything that might need to react when an object is pulled out of that object pool or pushed back into it and that's it it's an abstract solution but actually pretty easy to use so as always i hope that was interesting and better yet useful for you and your project and until next time happy game designing
Info
Channel: One Wheel Studio
Views: 14,189
Rating: undefined out of 5
Keywords: Unity3d, Indie Game, Game Development
Id: x6jFZvvOGgk
Channel Id: undefined
Length: 8min 49sec (529 seconds)
Published: Wed Mar 02 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.