Skip to content

Latest commit

 

History

History
283 lines (204 loc) · 19.3 KB

DOCS.md

File metadata and controls

283 lines (204 loc) · 19.3 KB

Documentation

Overview

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.

Package Contents

  • 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 the ComponentObjectPoolBehaviour, but this requires the type to also implement the IPoolable 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.

Installation Instructions

This is based on the Unity documentation.

To load a package from a Git URL:

  1. Open the Package Manager window by navigating from your menu bar to; Window -> Package Manager. Menu item screenshot
  2. Click the add Add button button in the status bar.
  3. The options for adding packages appear. Add package screenshot
  4. Select Add package from git URL from the add menu. A text box and an Add button appear.
  5. Enter the Git URL; https://github.com/MuskettaMan/PoolManagement.git in the text box and click Add. Enter Git URL screenshot

If Unity was able to install the package successfully, the package now appears in the package list with the Git tag screenshot tag.

Limitations

  1. 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 from ObjectPoolBehaviourEditor, 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.

Workflows

Setup the GameObjectPoolBehaviour

  1. Add the GameObjectPoolBehaviour to your desired GameObject in the hierarchy. Add component screenshot
  2. Add the prefab you want to pool inside the Prefab field in the inspector. Select prefab screenshot
  3. (Optional) Change the Pooled Objects Parent Pooled Objects Parent field screenshot, more information about this field can be found by hovering over it.
  4. (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. Configuration section screenshot
  5. (Optional) Enable the field Use Send Messages Use Send Messages screenshot, 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 methods void Requested() {...} and void Returned() {...}. (This works in a similar manner as the Awake, Start and Update 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.

Setup the ComponentObjectPoolBehaviour

  1. Create a new script file inside your project. Create c# script screenshot
  2. Make your class inherit from the ComponentObjectPoolBehaviour; 📝Don't forget to add the using statement using Musketta.PoolManagement;
using Musketta.PoolManagement;

public class MyCustomPool : ComponentObjectPoolBehaviour<...>
{

}
  1. 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 the Transform component.
using Musketta.PoolManagement;
using UnityEngine;

public class MyCustomPool : ComponentObjectPoolBehaviour<Transform>
{

}
  1. 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. Reference prefab screenshot
  2. (Optional) I suggest reading the Setup the GameObjectPoolBehaviour section, for more information about the settings you can tweak in the inspector.
  3. (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 editor script screenshot

Setup the PoolableComponentObjectPoolBehaviour

  1. Create a new script file inside your project. Create c# script screenshot
  2. Make your class inherit from the PoolableComponentObjectPoolBehaviour.
using Musketta.PoolManagement;

public class MyCustomPool : PoolableComponentObjectPoolBehaviour<...>
{

}
  1. 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 the IPoolable 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>
{

}
  1. 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. Poolable component prefab inspection screenshot Reference prefab in object pool screenshot
  2. (Optional) I suggest reading the Setup the GameObjectPoolBehaviour section, for more information about the settings you can tweak in the inspector.
  3. (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 editor script screenshot

Setup the ObjectPool

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.

  1. Create an instance of the ObjectPool by using such a statement;
ObjectPool<StringBuilder> stringPool = new ObjectPool<StringBuilder>();
  1. 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.
  2. 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 method T Create();. So what we'll do is create a class that implements ICreationService with as generic type StringBuilder. Let's look at the result;
public class StringBuilderCreationService : ICreationService<StringBuilder>
{
    public StringBuilder Create()
    {
        return new StringBuilder();
    }
}
  1. 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);
  1. 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 and EmptyDestructionService 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);
  1. 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);

Create Editor

Automated

  1. Find your Object Pool script inside your project view.
  2. 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.
  3. 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.

Manual

If the automated feature didn't pan out for you, you can still manually define an editor script.

  1. Create a new script in your desired directory.
  2. 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;
  1. Inherit from the ObjectPoolBehaviourEditor with as generic the type of object that you will pool;
public class GameObjectPoolBehaviourEditor : ObjectPoolBehaviourEditor<GameObject> { }
  1. And finally add the CustomEditor attribute above your class with the Object Pool type;
[CustomEditor(typeof(GameObjectPoolBehaviour))]
public class GameObjectPoolBehaviourEditor : ObjectPoolBehaviourEditor<GameObject> { }

Advanced Topics

Object Pool Services

The ObjectPool makes use of different services, three in total; creation, management and destruction. The purpose of these are as follows;

  1. 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.
  2. 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.
  3. 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 implement IDisposable interface or require another type of clean up, like Unity GameObjects with the Destroy() 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.

Reference

ObjectPool API

ObjectPool Fields

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

ObjectPool Methods

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

ObjectPoolBehaviour API

ObjectPoolBehaviour Fields

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 Objects. Protected get, Private set
PoolManagementService IPoolManagementService<T> The service used for managing the Objects. Protected get, Private set
DestructionService IDestructionService<T> The service used for destroying the Objects. Protected get, Private set
ObjectPool ObjectPool<T> The inner ObjectPool<T> that's used for managing the object pooling. Public get, Private set

ObjectPoolBehaviour Methods

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

Samples

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.