Prefab pooling

The previous pooling solution is useful for typical C# objects, but it won't work for specialized Unity objects, such as GameObject and MonoBehaviour. These objects tend to consume a large chunk of our runtime memory, can cost us a great deal of CPU usage when they're created and destroyed, and tend to risk a large amount of garbage collection at runtime. For instance, during the lifecycle of a small RPG game, we might spawn a thousand Orc creatures, but at any given moment, we may only need a maximum of 10 of them. It would be nice if we could perform similar pooling as before but, for Unity Prefabs, to save on a lot of unnecessary overhead creating and destroying 990 Orcs we don't need.

Our goal is to push the overwhelming majority of object instantiation to scene initialization rather than letting them get created at runtime. This can provide some big runtime CPU savings and avoids a lot of spikes caused by object creation/destruction and garbage collection at the expense of scene loading times and runtime memory consumption. As a result, there are quite a few pooling solutions available on the Asset Store to handle this task, with varying degrees of simplicity, quality, and feature sets.

It is often recommended that pooling should be implemented in any game that intends to be deployed on mobile devices, due to the greater overhead costs involved in the allocation and deallocation of memory compared to desktop applications.

However, creating a pooling solution is an interesting topic, and building one from scratch is a great way of getting to grips with a lot of important internal Unity engine behavior. Also, knowing how such a system is built makes it easier to extend if we wish it to meet the needs of our particular game, rather than to rely on a prebuilt solution.

The general idea of Prefab pooling is to create a system that contains lists of active and inactive GameObjects that were all instantiated from the same Prefab reference. The following diagram shows how the system might look after several spawns, despawns, and respawns of various objects derived from four different Prefabs (Orc, Troll, Ogre, and Dragon):

Note that the Heap Memory area in the previous screenshot represents the objects as they exist in memory, while the Pooling System area represents the Pooling System's references to those objects.

In this example, several instances of each Prefab were instantiated (11 Orcs, 8 Trolls, 5 Ogres, and 1 Dragon). Currently, only 11 of these objects are active, while the other 14 have been previously despawned and are inactive. Note that the despawned objects still exist in memory, although they are not visible and cannot interact with the game world until they have been respawned. Naturally, this costs us a constant amount of heap memory at runtime to maintain the inactive objects, but when a new object is instantiated, we can reuse one of the existing inactive objects rather than allocating more memory to satisfy the request. This saves significant runtime CPU costs during object creation and destruction and avoids garbage collection.

The following diagram shows the chain of events that needs to occur when New Orc is spawned:

The first object in the Inactive Orc pool (Orc7) is reactivated and moved into the Active pool. We now have six active Orcs and five inactive Orcs.

The following diagram shows the order of events when an Ogre object is despawned:

This time, the object is deactivated and moved from the Active pool into the Inactive pool, leaving us with one active Ogre and four inactive Ogres.

Finally, the following diagram shows what happens when a new object is spawned, but there are no inactive objects to satisfy the request:

In this scenario, more memory must be allocated to instantiate the new Dragon object since there are no Dragon objects in its Inactive pool to reuse. Therefore, to avoid runtime memory allocations for our GameObjects, it is critical that we know beforehand how many we will need and that there is sufficient memory space available to contain them all at once. This will vary depending on the type of object in question and requires occasional testing and sanity checking to ensure that we have a sensible number of each Prefab instantiated at runtime.

With all of this in mind, let's create a pooling system for Prefabs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.53.209