This package is an implementation of the Object Pool design pattern made for Unity. It contains the traditional implementation of the design pattern, but also a more specialized implementation dealing with how GameObjects are instantiated, maintained and destroyed.
- The
GameObjectPoolBehaviour
is an out-of-the-box component that you put on any GameObject. You can pass this a prefab as the object it should pool and it'll work. - The
ComponentObjectPoolBehaviour
is the class you want to inherit from when creating your own more specialized Object Pools. You want to derive from this for when you want to pool a specific type of component. - The
PoolableComponentObjectPoolBehaviour
shares the same functionality as theComponentObjectPoolBehaviour
, but this requires the type to also implement theIPoolable
interface so it can send out callbacks for whenever an object has been returned or requested to/from it's pool. - This package also contains a feature to deal with the issue that you can't write custom editors for generic classes. By right-clicking the script file that contains a class that derives from
ObjectPoolBehaviour
it will show a context menu item; Pool Management -> Create Editor Script. This can be used to create an editor implementation of your Object Pool.
This is based on the Unity documentation.
To load a package from a Git URL:
- Open the Package Manager window by navigating from your menu bar to; Window -> Package Manager.
- Click the add button in the status bar.
- The options for adding packages appear.
- Select Add package from git URL from the add menu. A text box and an Add button appear.
- Enter the Git URL;
https://github.com/MuskettaMan/PoolManagement.git
in the text box and click Add.
If Unity was able to install the package successfully, the package now appears in the package list with the tag.
- To support the custom editor for classes derived from
ObjectPoolBehaviour
, you need to define this in an explicit editor file. You can either do this manually by creating your own editor file and inheriting fromObjectPoolBehaviourEditor
, or by making use of the 'Create Editor Script' menu item. :memo: Note: it's not required to make use of the custom editor, but it does offer a better experience when using the component.
- Add the
GameObjectPoolBehaviour
to your desired GameObject in the hierarchy. - Add the prefab you want to pool inside the
Prefab
field in the inspector. - (Optional) Change the
Pooled Objects Parent
, more information about this field can be found by hovering over it. - (Optional) Tweak the configuration settings. The setting you most likely want to change is the
Initial Capacity
, this is the amount of objects that will be created whenever the ObjectPool becomes active. - (Optional) Enable the field
Use Send Messages
, this determines whether to make use of Unity's message system. With this enabled Components on the GameObjects that are being pooled will get callbacks for when they are requested and returned. To make use of this you add the methodsvoid Requested() {...}
andvoid Returned() {...}
. (This works in a similar manner as theAwake
,Start
andUpdate
methods.))] :memo: Note: it's suggested to not make use of this as this can decrease performance. For a more elegant solution look into the PoolableComponentObjectPoolBehaviour.
- Create a new script file inside your project.
- Make your class inherit from the
ComponentObjectPoolBehaviour
; 📝Don't forget to add the using statementusing Musketta.PoolManagement;
using Musketta.PoolManagement;
public class MyCustomPool : ComponentObjectPoolBehaviour<...>
{
}
- This will also require you to add the generic type of what object will be pooled. The type you define here has to derive from the
Component
class. For this example I will make use of theTransform
component.
using Musketta.PoolManagement;
using UnityEngine;
public class MyCustomPool : ComponentObjectPoolBehaviour<Transform>
{
}
- After doing so you have successfully created an Object Pool that will work for the type you've defined in your class. You can now add this script to any GameObject and give a reference to a prefab that contains a component of the type you defined previously.
- (Optional) I suggest reading the Setup the GameObjectPoolBehaviour section, for more information about the settings you can tweak in the inspector.
- (Optional) This package also contains a feature to deal with the issue that you can't write custom editors for generic classes. By right-clicking the script file that contains a class that derives from
ObjectPoolBehaviour
it will show a context menu item; Pool Management -> Create Editor Script. This can be used to create an editor implementation of your Object Pool.
- Create a new script file inside your project.
- Make your class inherit from the
PoolableComponentObjectPoolBehaviour
.
using Musketta.PoolManagement;
public class MyCustomPool : PoolableComponentObjectPoolBehaviour<...>
{
}
- This will also require you to add the generic type of what object will be pooled. The type you define here has to derive from the
Component
class and will have to implement theIPoolable
interface.
public class MyPoolableComponent : MonoBehaviour, IPoolable
{
public void Requested()
{
Debug.Log("I've been requested :)!");
}
public void Returned()
{
Debug.Log("I've been returned :(!");
}
}
using Musketta.PoolManagement;
public class MyCustomPool : PoolableComponentObjectPoolBehaviour<MyPoolableComponent>
{
}
- After doing so you have successfully created an Object Pool that will work for the type you've defined in your class. You can now add this script to any GameObject and give a reference to a prefab that contains a component of the type you defined previously.
- (Optional) I suggest reading the Setup the GameObjectPoolBehaviour section, for more information about the settings you can tweak in the inspector.
- (Optional) This package also contains a feature to deal with the issue that you can't write custom editors for generic classes. By right-clicking the script file that contains a class that derives from
ObjectPoolBehaviour
it will show a context menu item; Pool Management -> Create Editor Script. This can be used to create an editor implementation of your Object Pool.
The base implementation of the ObjectPool
works with any type. The main target of this package was to also be able to use this with Unity's components and editors, but it's still possible to use this with normal C# types.
Let's look at an example where we want to make a pool of StringBuilder
objects.
- Create an instance of the
ObjectPool
by using such a statement;
ObjectPool<StringBuilder> stringPool = new ObjectPool<StringBuilder>();
- This won't compile due to the lack of arguments, but it will setup for later. The 3 parameters this constructor expects are a creation service, pool management service and destruction service. More about the specifics of these can be read in Object Pool Services.
- The most challenging parameter here is the creation service, so let's tackle that right away. The only thing the creation service expects is a class that implements
ICreationService<T>
which has a methodT Create();
. So what we'll do is create a class that implementsICreationService
with as generic typeStringBuilder
. Let's look at the result;
public class StringBuilderCreationService : ICreationService<StringBuilder>
{
public StringBuilder Create()
{
return new StringBuilder();
}
}
- Now we can use that class for our first parameter;
ObjectPool<StringBuilder> stringPool = new ObjectPool<StringBuilder>(new StringBuilderCreationService());
or
StringBuilderCreationService creationService = new StringBuilderCreationService();
ObjectPool<string> stringPool = new ObjectPool<string>(creationService);
- And now we only have to add the remaining pool management service and destruction service. Luckily these services can be defaulted by doing nothing. The
EmptyPoolManagementService
andEmptyDestructionService
classes implement the interfaces, but don't do anything. So if you want some type of clean up to happen to your objects you should create custom implementations of these. But for this example we can just use the null objects;
StringBuilderCreationService creationService = new StringBuilderCreationService();
EmptyPoolManagementService poolManagementService = new EmptyPoolManagementService();
EmptyDestructionService destructionService = new EmptyDestructionService();
ObjectPool<string> stringPool = new ObjectPool<string>(creationService, poolManagementService, destructionService);
- The final non-required parameter is the config. The config is a class that defines some settings that can change the way the pool behaves, these are the same settings that appear in the Unity inspector for the
ObjectPoolBehaviour
. This is the place to also define with how many objects your Object Pool will initialize. Let's take a look at a final example where we pass a config that will tell the pool to initialize with 500 objects.
StringBuilderCreationService creationService = new StringBuilderCreationService();
EmptyPoolManagementService poolManagementService = new EmptyPoolManagementService();
EmptyDestructionService destructionService = new EmptyDestructionService();
ObjectPool<StringBuilder>.ObjectPoolConfig config = new ObjectPool<StringBuilder>.ObjectPoolConfig(500);
ObjectPool<string> stringPool = new ObjectPool<string>(creationService, poolManagementService, destructionService, config);
- Find your Object Pool script inside your project view.
- Right click on the script file and open the menu item; Pool Management -> Create Editor Script.
📓If this option is greyed out/disabled, make sure the script your inspecting derives from
ObjectPoolBehaviour
. - After pressing that option a new file will be added in the same directory as your Object Pool script. You can now move/edit/change/delete this script.
If the automated feature didn't pan out for you, you can still manually define an editor script.
- Create a new script in your desired directory.
- Import the
UnityEditor
and Object Pool editor namespace and the namespace of the object that will be pooled;
using UnityEditor;
using Musketta.PoolManagement.Editor;
using My.Custom.Namespace;
- Inherit from the
ObjectPoolBehaviourEditor
with as generic the type of object that you will pool;
public class GameObjectPoolBehaviourEditor : ObjectPoolBehaviourEditor<GameObject> { }
- And finally add the
CustomEditor
attribute above your class with the Object Pool type;
[CustomEditor(typeof(GameObjectPoolBehaviour))]
public class GameObjectPoolBehaviourEditor : ObjectPoolBehaviourEditor<GameObject> { }
The ObjectPool
makes use of different services, three in total; creation, management and destruction. The purpose of these are as follows;
- Creation of the object, for most class this can be achieved by making use of its constructor, but in Unity for example you have to make use of the
Initialize()
method. This is also a good place to make use of the Factory design pattern. - Management of the objects, this class will receive callbacks for when objects are created, requested, returned and destroyed, along with the object. This can be used for updating the state of the object from an outside perspective. For example in the
GameObjectPoolManagamentService
whenever a GameObject is returned to the pool it will be set to in active,SetActive(false)
. But when it's requested it will be set active again. - Destruction of the objects, for most standard classes you might not need this, and you can just let
GarbageCollection
do its job. But in cases for objects that implementIDisposable
interface or require another type of clean up, like Unity GameObjects with theDestroy()
method, this is the place to perform such destruction, clean up, disposing.
It's recommended to derive from the default service for the Object Pool type you are using; for example the PoolableComponentObjectPoolBehaviour
has as default for the management service the PoolableComponentPoolManagementService
. So to further specify your own management you want to derive from this class to still maintain the original behaviour of the management.
Name | Type | Description | Access |
---|---|---|---|
Pooled | ReadOnlyCollection<T> |
All the objects that currently are being pooled inside this class. | Public |
InUse | ReadOnlyCollection<T> |
All the objects that currently are in use, but originally belong to this pool. | Public |
Name | Description | Parameters | Return Type | Access |
---|---|---|---|---|
RequestObject | Returns an object from the pool that the user can use. | T |
Public | |
ReturnObject | Returns the given @object so it can be used later. |
T @object |
void |
Public |
Dispose | Disposes the object pool and based on the config also the pooled and/or in use objects. | void |
Public | |
IsObjectInPool | Whether the given @object is being pooled inside here. |
T @object |
bool |
Public |
IsObjectInUse | Whether the given object originally belonged to this pool. | T @object |
bool |
Public |
Name | Type | Description | Access |
---|---|---|---|
prefab | T |
The prefab to pool, this will be the original for all the objects that will be inside the pool. | Protected |
CreationService | ICreationService<T> |
The service used for creating the Object s. |
Protected get, Private set |
PoolManagementService | IPoolManagementService<T> |
The service used for managing the Object s. |
Protected get, Private set |
DestructionService | IDestructionService<T> |
The service used for destroying the Object s. |
Protected get, Private set |
ObjectPool | ObjectPool<T> |
The inner ObjectPool<T> that's used for managing the object pooling. |
Public get, Private set |
Name | Description | Parameters | Return Type | Access |
---|---|---|---|---|
ReturnObject | Returns the given @object so it can be reused. |
T @object |
void |
Virtual Public |
RequestObject | Returns an object from the pool so it can be used. | T |
Virtual Public | |
Awake | Initializes the services and creates an instance of the ObjectPool<T> . |
void |
Virtual Protected | |
OnDestroy | Disposes the ObjectPool to make sure all the objects that were pooled and in use also get properly clean up. |
void |
Virtual Protected | |
Reset | Resets the component to make sure it's in the right state. | void |
Virtual Protected | |
InitializeCreationService | Initializes the creation service. If not overridden this will default to UnityObjectCreationService<T> . |
ICreationService<T> |
Virtual Protected | |
InitializePoolManagementService | Initializes the pool management service. If not overridden this will default to EmptyPoolManagementService<T> . |
IPoolManagementService<T> |
Virtual Protected | |
InitializeDestructionService | Initializes the destruction service. If not overridden this will default to UnityObjectDestructionService<T> . |
IDestructionService<T> |
Virtual Protected |
The package contains two samples, one for the ComponentObjectPoolBehaviour
and one for the PoolableComponentObjectPoolBehaviour
. The process for how these were created can be found in Workflow - Setup the ComponentObjectPoolBehaviour and Workflow - Setup the PoolableComponentObjectPoolBehaviour.