Instantiate/Destroy VS. Enable/Disable

Hello,

I’m testing hardware by creating these massive test scenes with many rigid body game objects. Obviously after a certain point performance degrades. And I know I can adjust the camera clipping planes to improve performance, but I’m wondering if I need something more sophisticated for loading part of a scene, that way I can create an open world game.

Are there any assets for this?

Also, I have ideas for loading game objects based on their proximity to the player, and unloading game objects which are far away and off screen.

Question is, for an open world game where lots of game objects will be in scene, and will be loaded /unloaded pretty often, would it be better to simply enable/disable game objects or to add/remove from memory?

I realize to answer this question experimentation is needed. But this seems like a common enough problem( partial scene loading) so what kind of strategies have the Unity vets come up with?

The technique you are describing is called ‘Object pooling’ and theres a lot of material on the subject out there.

There’s pros and cons to both.

In simple terms…

Instantiate/Destory:
pro - easy to implement, keeps memory usage to only that what is needed (great for low memory systems)
cons - expensive to perform, dogs down garbage collection

Enable/Disable:
pro - fast on the processor, does not incur expensive garbage collector calls
cons - complicated to implement, can fill up memory if objects are complex (bad for low memory systems), can result in bugs if the state from previous time enabled isn’t reset properly

Personally what I implemented both into one system in my ‘com.spacepuppy.Spawn’ namespace of my framework. In it the primary facade is the ‘SpawnPool’.

SpawnPool is a multiton factory (a multiton is like a singleton that can have more than one instance. There is a default global instance, as well as secondary instances that can be used if the default one is to be overriden).

The SpawnPool maintains prefabs that can be cached for reuse. The SpawnPool has a design time manager that you add prefabs to declaring them cacheable. When you do this you can select metrics for their caching:

quantity to cache on load
buffer quantity to load if the cache runs dry
max quantity allowed to be cached in total

A profile can even be made that allow varying quantities depending on user system specs. Low memory system, no caching. High memory system, more caching.

If a prefab is called to be spawned that is not part of the SpawnPool, then it just Instantiates it. This way all code just needs to call ‘SpawnPool.Spawn(…)’ and the SpawnPool takes care of the rest… making it a replacement for ‘Instantiate’.

There is also a function called ‘Kill’ that handles destroying gameobjects which replaces the ‘Object.Destroy’ function. It will determine if the GameObject is a cached object and replace it into the cache pool. Otherwise call Destroy like normal.

This way I can write code for any project, use the SpawnPool, and if I want to turn off caching… I just go into the SpawnPool manager and turn it off. But all the code still gets performed the same way.

3 Likes

Thanks for the great responses.

lordofduct,

Thank you for pointing me in the right direction!

duct, like duct tape:

circa 1997

Just wanted to add, Instantiating objects requires you to position them properly. Can be a pain if you have detailed scenes with many objects being created. Much easier to have the scene already layed out and just hit the “on/off” switch. :wink:

1 Like

In terms of garbage collection. For example I have torch that checks on a first frame of the game if it is raining and if it’s not I want to have a gameobject with fire particles on it.

For garbage collection, is it better to create object that I need (spawn on torch fire if its not raining), or destroy object I don’t need (destroy fire object on torch if it’s raining)?

From what I have tested and done myself, one of the best approach to that is actually a mix of 3 things:

  1. Use a proper LOD + Occlusion Culling to make sure unseen torches are disabled.
  2. For each torch, instead of disabling/enabling or destroying/instantiating the particle effect, just change its particle spawn rate to 0. This saves you from filling up the Garbage Collector with the particle effect caches and a particle system with 0 uses barely any resources and can still make use of GPU Instantiating if you properly set each effect to use the same GPU cached mesh + material + textures. It also allows you to have a better transition between the 2 states of the torches (so that the fire doesn’t just disappear, but instead have it current live particle dies properly.)
  3. Make sure each identical torches are Batched together. (So, the torches themselves are batched while the particle effects are GPU instantiated.)

Another possibility, if you want the most efficient results is to set a maximum of torches and, instead of instantiating them or enabling/disabling them, you use a spacial emplacement management script that will move torches around based on your location. This is actually extremely efficient on mobiles as you can just check the distance between the player and each torch position by simple maths and detect the closest torches position to said player and place each torches at those particular position. (To avoid having the torches’ fire spawn in-between their position when moved, you got to set the particles system to spawn the particles in local space or to forcefully reset the particle system once moved, which destroy its spawned particles that might by laying around and set it at time 0.)

1 Like