Cairn has grown. The game now includes over 20 types of units, a huge variety of attack types with fully working combat mechanics, almost 9 different Landmarks can be built, destroyed, and taken over, and dozens of doodads that have to be navigated around or destroyed for resources. All of these pieces coming together in the most recent builds has created some unique problems, mostly with the management of memory.
All of these different pieces create other objects within the game. Landmarks create projectiles that are thrown at enemies, Units create blood splatters as they take damage, and doodads break apart as they are destroyed. Everything in the game has it’s time to be removed from the game, a blood splatter is only there for a second, as it fades away after the initial hit. This spawning and destroying of game objects was really starting to hurt performance. Lets look at some figures & performance charts to better explain the problem.
Here are some very rough numbers of two armies fighting it out:
10 Scrappers – 1 attack every .4 seconds.
10 Blood Archers – 1 arrow shot every 1.0 seconds.
8 Legionnaires – 1 attack every 1.1 seconds, chance to cause Burning
8 Tinkers – 1 bullet shot every 1.3 seconds.
Assuming this fight lasts for about 2 minutes, which is common for forces of this size we will have Spawned & Destroyed the following game objects
- 700+ arrows
- 400+ bullets
- 2455+ Splatter Spawners
- 2455+ Blood particle effects
- 8 Burning Effects
This didn’t actually cause any problems early on, but as we’ve grown and our test cases have grown to include hundreds of units instead of a few dozen, then we started testing on lower performance machines and laptops that weren’t connected to power supplies and decided it was time to stop the useless spawning.
So I started writing a Game Object Pool Manager. A tool that would cache game objects so that they could be reused over and over saving us all that memory that Spawn/Destroy hogs up and limiting the number of spawns as whole by incredible amounts.
These are some rough numbers of the objects spawned & destroyed after we implemented our Pool Manager in the same battle that I described above.
- 22 arrows
- 18 bullets
- 12 Splatter Spawners
- 24 Blood particle effects
- 2 Burning Effects
In battles with over 100 units, the performance gain could be measured in hundreds of frames per second. One single script and a few changes to projectiles, blood splatters, and status effects brought our system requirements down to almost nothing.
Here are some performance metrics from the Unity Profiler.
This is the before shot of our performance, taken when we started to notice some occasional slow down. You can see that the CPU usages spikes off the chart, way off the chart. Destroying the objects is taking close to half of what my CPU had to offer and my spawn scripts were grabbing another 6%. Not leaving much room for the UnitActionController script which houses the behavior controllers for every unit.
This is our performance after the object pool was put into place. The destroy and spawn scripts are no where to be found, since they are recycled throughout the game, and destroyed only at the end. You might also notice that the chart is scaled completely different, in the first the top line is 66ms(15fps) in the after one the top line is 16ms(60fps).
The script and details about whats inside of it are here. Feel free to use it as you please.