A quick note. You got to put 2 breaking space to have create paragraph here. Reading your question was quite painful. Not counting the amount of typing errors that made it even more a troublesome task to accomplish.
Lag Spikes could be a result from many many many many things.
If you could share some screenshot of the scene when the spikes occur and when they are not, it could help at seeing what’s different between each and what might be the cause of your problem.
Gfx.WaitForPresent is the process where the device is “ahead” and got nothing to do in the engine. It’s kinda like “keeping some memory available”. It’s usually related to either VSync or when the display and calculation of the engine aren’t synchronized.
Turning off VSync in the engine option might not work if the device force it on. Smart phone have an inner-limiter which limit the framerate regardless of the application (usually at 60). Your Gfx.WaitForPresent could be related to that.
At the same time, the issues with smartphone is that they have limited shared memory. They don’t have actual GPU that has their own dedicated memory, but instead takes from the RAM pool. It’s a slower process and more easy to clogged up.
Still, what seems to be (with lack of details) the cause of your problem is 2 things:
- When you activate “everything”, you’re clogging up the available memory and it lags.
- When you deactivate many things, you’re clogging up the batching/cache and it lags.
The first one is the usual lag due to having too much managed by the phone and the second one is that you request too many changes quickly that requires the batching/cache to be updated and the phone has a problem recovering. (Kinda like how you can’t move up from ignition to 300Km/h with a car in a sec.) The phone processing power might have relatively high capacity, but it’s nothing instantaneous.
The way you got to plan your game on a phone is by making sure the phone has all it needs before it needs it and that it’s already within the memory. SetActive() is the complete opposite of that as it’s like a switch instantly calling and turning off calls. The best example I could come up with is if you had a game with enemies prefabs. On PC, you could instantiate those enemies on the fly and it wouldn’t clog up the memory that much. On a phone, it would be suggested to, instead, keep a first instance of each enemy outside of the “game field” so that the phone can store and keep its related data active at all time.
Why are phone unable to have their processor as fast as PC when the numbers supposedly shows the contrary? Simple answer : Energy consumption. If you ran your phone with a 250-300 watts like a PC does, it could manage things a lot faster… but with the current batteries, it would drain all its juice in 30-45 min max (not counting the heat of the device.) You might find a phone that has a big whooping 8GB of RAM, but it processing power will still be that of a PC that might have 1GB-2GB max. The remaining 6GB-7GB is only useful for storing temporary voluminous data… not constantly changing it. My guess is that your project currently exceed the processing power of your phones or/and doesn’t have a constant fixed amount of information being used.
Think of your game like a washing machine. When you launch a scene, you have to make sure as many thing in the scene are set “in the tub” (memory), then you start the spinning (Updates). You got to remove or add as less as possible during the spinning because, each time, you stop the machine to add or remove the pieces. This is what Occlusion Culling (in Unity) does. It’s not just “turning” stuff off, it also keep their relevant data in memory. It’s like a “unspinning” zone in the washing machine’s tub. SetActive(), on the otherside, is like if you were removing the part from the tub. If you try to put it back inside, the tub entry might be too small so you do it piece by piece and it takes longer that’s when Gfx.WaitForPresent seems to be the cause (while it’s not).
One thing I noticed is your “Physic.Processing” is relatively high. This is mostly due to your usage of Triggers. Whenever possible, instead of using triggers zone, you should use a custom distance checker that does its check 2-4 times per secs. This will reduce the load on your physic.processing by around 40%-60% while raising the behavior.update by less than 0.01% per checker. (with 30-60 trigger, that’s a trade of 15%-18% off from your physic.processing for 0.3%-0.6%… maybe 1% max onto the Behaviour.Update)
Trigger Collision box aren’t something you use in numbers left and right permanently. Those are useful for short and precise collision effects such as bullets, explosions or other “quick temporary” things. Otherwise, they are like constant-per-frame calls of Coroutines that get “every” gameobject in the scene that has a collision component each frame and check up if there’s a change from the last frame with each of them.