Used to easily create and manage instances of prefabs as pools of a given size, that saves having to utilize destroy and instantiate when wanting to use an instance of that prefab.
A lot of games need to instantiate and destroy prefabs at runtime and this small and easily integrated Pool Manager can help you create pools of isntances from prefabs of a given size to make sure that there are never more instances of that object then you actually need in the scene.
Unity Pool Manager implements the following methods consisting of a way to:
- Create a pool with a given size (see Create Pool method)
- Parent a pool to a given gameObject (see Parent Pool method)
- Increase the pool size at runtime (see Increase Pool Size method)
- En -or disable dynamic pooling, to create new slots in the pool once there are only visible instances to reuse (see Enable Dynamic Pooling method)
- Reuse an Pool Object from the given pool (see Reuse Object method)
For each method there is a description on how to call it and how to use it correctly for your game in the given section.
Required Software:
- Unity Ver. 2020.3.17f1
The Pool Manager itself is version independent, as long as .NET5 already exists. Additionally the example project can be opened with Unity itself or the newest release can be downloaded and exectued to test the functionality.
If you prefer the first method, you can simply install the shown Unity version and after installing it you can download the project and open it in Unity (see Opening a Project in Unity). Then you can start the game with the play button to test the Pool Managers functionality.
To simply use the Pool Manager in your own project without downloading the Unity project get the PoolManager.CS
and PoolObject.CS
files in the Example Project/Assets/Scritps/ called or alternatively get them from the newest release (may not include the newest changes) and save them in your own project. Then create a new empty gameObject
and attach the PoolManager.CS
script to it. Now you can easily add pools like shown in Create Pool method.
This documentation strives to explain how to start using the Pool Manager in your project and explains how to call and how to use its publicly accesible methods correctly.
To use the Pool Manager to start creating pools outside of itself you need to reference it. As the Pool Manager is a Singelton this can be done easily when we get the instance and save it as a private variable in the script that uses the Pool Manager.
private PoolManager pm;
void Start() {
pm = PoolManager.instance;
// Calling method in PoolManager
pm.CreatePool(this.gameObject, 10);
}
Alternatively you can directly call the methods this is not advised tough, if it is executed multiple times or you're going to need the instance multiple times in the same file.
void Start() {
PoolManager.CreatePool(this.gameObject, 10);
}
Additionaly the WeightedObject.CS
file can be included to make a lootTable, where certain poolObjects
have a higher change of being spawned then others.
To add a new weightedObject
to the lootTable simply create a new element in the Weighted Objects array with the properties:
Game Object
(The GamepoolObject
that should be instantiated or destroyed when utilizing the pool)Weight
(How likely it is that the weight is choosen divide the total weight of all elements by the weight of this element * 100 to get a procentual amount)Spawn Amount
(How manypoolObjects
we want to have in our pool --> Pool Size)
For this the random poolObject
we want to choose from need to be saved into a list of weightedObjects
and ordered by their value in a descending order.
[Header("Spawn Object Settings:")]
[SerializeField]
private List<WeightedObject> weightedObjects;
private int weightTotal = 1;
private void Start() {
// Create a pool and its parent for each weightedObject.
foreach (var spawnPrefab in weightedObjects) {
pm.CreatePool(spawnPrefab.gameObject, spawnPrefab.spawnAmount);
pm.ParentPool(spawnPrefab.gameObject, this.transform);
weightTotal += spawnPrefab.weight;
}
// Order weightedObjects by their assigned weight.
weightedObjects = weightedObjects.OrderByDescending(x => x.weight).ToList();
}
If we create a pool for each weightedObjects
, we can now choose a random one of them while still utilizing the weight we've assigned earlier.
private GameObject GetRandomSpawnPrefab() {
int randomNumber = Random.Range(0, weightTotal);
int weightSum = 0;
foreach (var spawnPrefab in weightedObjects) {
weightSum += spawnPrefab.weight;
if (randomNumber < weightSum) {
return spawnPrefab.gameObject;
}
}
return null;
}
Now that we have a gameObject
, we can simply reuse one of these gameObjects
from the pool with the Reuse Object method.
If needed the PoolObject
can implement the derived class to use certain calls like:
- On Object Reuse (called when the object gets reused from the Reuse Object method)
- Set Velocity (called when the object gets reused from the Reuse Object method with an additional
Vector2
that includes the velocity given to the method) - On Became Invisble (called when the object isn't rendered anymore by the camera see OnBecameInvisible Docs for more information)
- On Became Visible (called when the object gets rendered again by the camera see OnBecameVisible Docs for more information)
For this you simply need to create a new class that implements the PoolObject
class and then override
the virtual
methods (see Overriding virtual methods).
This section explains all public accesible methods, especially what they do, how to call them and when using them might be advantageous instead of other methods. We always assume PoolManager instance has been already referenced in the script. If you haven't done that already see Reference to Pool Manager Script.
What it does: Instantiates and disables the given amount of prefabs and adds them into the poolDictionary.
How to call it:
Prefab
is the prefab we want to save into our poolPoolSize
is the amount of instances of the prefabs we want to create for our poolDynamicPooling
defines if the poolSize should increase dynamically, if there are only visible instances of the given prefab to use
GameObject prefab = this.gameObject;
int poolSize = 25;
bool dynamicPooling = false;
pm.CreatePool(prefab, poolSize, dynamicPooling);
Alternatively you can call the methods with less paramters as some of them have default arguments.
GameObject prefab = this.gameObject;
int poolSize = 25;
pm.CreatePool(prefab, poolSize);
When to use it: When you want to create a pool with a given size for a given gameObject.
What it does: Changes the parent of the pool with the instances of the given prefab.
How to call it:
Prefab
is the prefab we want to change the pool parent atParent
is the new parent we want to set our pool under
GameObject prefab = this.gameObject;
Tranform parent = this.transform;
pm.ParentPool(prefab, parent);
When to use it: When you want to change the parent of a pool to show all of the pools under the Pool Manager for example.
What it does: Instantiates and disables the given amount of prefabs and adds them into the poolDictionary into the already existing pool.
How to call it:
Prefab
is the prefab we want to save into our poolDifference
is the additional amount of instances of the prefab we want to save into our pool
GameObject prefab = this.gameObject;
int difference = 1;
pm.IncreasePoolSize(prefab, difference);
When to use it: When you want to increase the size of an already existing pool at runtime, because the space is running out and causing popping.
What it does: En -or disables dynamic pooling on the pool with the instances of the given prefab.
How to call it:
Prefab
is the prefab we want to en -or disable dynamic pooling on the pool off.DynamicPooling
defines if the poolSize should increase dynamically, if there are only visible instances of the given prefab to use
GameObject prefab = this.gameObject;
bool dynamicPooling = true;
pm.EnableDynamicPooling(prefab, dynamicPooling);
Alternatively you can call the methods with less paramters as some of them have default arguments.
GameObject prefab = this.gameObject;
pm.EnableDynamicPooling(prefab);
When to use it: When you want to en -or disable dynamic pooling on a given pool, because it is not needed anymore or becomes needed after a certain switch in gameplay.
What it does: Reuses or uses one of the instances in the pool of the given prefab.
How to call it:
Prefab
is the prefab we want to reuse one of the instances from the pool fromPosition
is the new position the instance should have after enabling it againRotation
is the new rotation the instance should have after enabling it againVelocity
is the new velocity the instance should have after enabling it again
GameObject prefab = this.gameObject;
Vector3 position = Vector3.zero;
Quaternion rotation = Quaternion.identity;
Vector2 velocity = Vector2.zero;
pm.ReuseObject(prefab, position, rotation, velocity);
Alternatively you can call the methods with less paramters as some of them have default arguments.
GameObject prefab = this.gameObject;
pm.ReuseObject(prefab);
When to use it: When you want to use one of the instances in the pool of the given prefabs to spawn them in a new location with a given velocity and rotation.