- Home /
Activating GameObject(s) is slow
I need to regularly bring groups of up to 500 GameObject(s) into the scene at run time as larger objects in my game world are broken and split into pieces. Instantiating them as needed was too slow. I then tried instantiating them upon start up, setting their active property to false and then setting it to true when they are needed. This was a little better. I then got a further improvement by leaving the dormant pieces active but instead turning off their colliders, renderers, scripts, setting them to kinematic and then sending them to sleep. Then when they are needed I reverse the process. Note though that these optimisations do impose a pre-calculation delay of several seconds at level start.
That's about as far as I can take it. The bulk of the slow down now appears to be occurring in Unity's internal processing and outside of my activation loop. And it's still a significant slow down. Breaking apart 4 objects into 100 pieces each still results in a worst frame time of around 200 milliseconds before it returns to a more healthy rate.
Until I get the full version of Unity and access to proper profiling tools I can't be much more specific than that. I will speculate though that Unity uses an adaptive voxel subdivision method for determining which objects to test for collision. This method may be optimised in some way to take advantage of spatial and temporal cohesion in the game world. Perhaps by suddenly activating a whole lot of new colliders in a single frame I'm disrupting this cohesion. If I don't activate the colliders the slow down is significantly smaller but pieces with no collision are useless to me.
So I'm currently clueless on how to get a couple of hundred objects into the scene without dropping frames. Has anyone had any success in doing this?
Answer by SinisterRainbow · Oct 14, 2013 at 09:42 PM
This is an old question but I had a similar problem and this is how I solved it:
First, I make liberal use of coroutines to hide loading/path searching/pooling/everything.. as a result, my game never appears to be loading, there's always something hiding it.
I faced a very similar problem to yours when working in CryEngine, whether they used R-trees or whatever for collision, I don't know, but adding the physics collider of the object caused the greatest lag.
There I needed to create a world with 15000+ objects as quickly as possible. I use pools for it, but masked under a 'coroutine' (equiv. in C++ anyway) that spawns the initial board around the player first, after a small set area I spawn the player and the game starts - The board still loads though and spirals it's way outward. So you may see a second of loading in front, but far off stuff is virtually unnoticeable. This doesn't bother me at all, but could possible be masked further through effects like dissipating fog or something of the like.
But that wasn't good enough even, so I disabled physics, spawned them and bam - incredibly fast.
SO - I came up with a new strategy: For the physics part I use a small radius around the player that physicalizes all objects around him/her. PLUS a slightly larger radius for any essential physics (like enemies, shootable stuff). Every x meters moved it will physicalize new objects in the direction the player moved within the radius, and unphysicalize those that have now left the radius. This is hidden in a coroutine as well.
This works well for even very fast movement. Though this full system is not applicable to your game I'm sure, realizing it's the physics likely causing the majority of the lag and figuring out a solution that may work for your case.
As a final note, this is easier to do in C++ perhaps: Is make sure your data is memory aligned. You can do basic things to assure this like nested for-loops, make sure it accesses data in the array in memory aligned order. It can be 100x faster to access memory aligned data than randomly or ( gasp )accessing it reversed order.
Answer by nikescar · Oct 05, 2012 at 10:44 PM
They way this is usually done is by using object pools. You instantiate the object from the start and keep them off screen until needed. Checkout this thread for an example. Also do a search here on Answers for "object pool".
Thanks nikescar. I'm familiar with object pools as a method of avoiding instantiation costs and use them elsewhere in my project. Indeed I started out using them for this problem but the individual pool objects I'm bringing into the world are joined together in arbitrary ways and creating joints on the fly isn't fast either. Also I can't cap how many might be present at any one time. So, rather than using a reusable pool I store a 1 to 1 copy of everything I'm going to need. It does the same thing, avoids instantiation on the fly. And, as listed above, I added the further optimisation of disabling and reenabling components rather than activating/deactivating as used in the pool example.
Over 80% of the time I'm now losing sits in bringing colliders (they are already created, just disabled) into the world which happens whether you use an active/inactive GameObject pool or the method I'm using. If I leave the colliders disabled (a 1 line code change) I get the 80% back. After further tests with "teleporting" colliders (leaving them enabled but making large positional changes) the slowdown also appears here. It looks to me that Unity physics just runs much slower on the first frame after a reasonable number of colliders appear in a new place. This is probably a function of the increased complexity of the problem and also it not being optimised due to the relative infrequency of occurrence. I've written physics engines before and this operation doesn't need to be as slow as this.
I do love my Unity though so I might just have to get creative at a higher level to avoid bringing too many objects into the world at once.
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Multiple Cars not working 1 Answer
Is there a way to optimize Loading.PersistentManager? 2 Answers
Object Pooling, have some question marks 0 Answers