If your code in your update loop is slow, this means the frame rate will drop and it will do more FixedUpdates per frame. All this is fine.
If you code in your FixedUpdate is slow, (For example imagine it takes 1 second), so this also leads to a drop in frame rate. But now does it attempt to put in even more FixedUpdates because of the low frame rate leading to a feedback loop in which it gets slower and slower?
Yes, it does exactly this. This is why itās always recommended to move as much processing as you can outside of FixedUpdate, and to avoid relying on physics for too much stuff (especially stuff the player canāt see, like far away things). Slow code in Update slows your game down linearly, but slow code in FixedUpdate will slow your game down exponentially.
Unity doesnāt allow the game to slow down to infinite slowness this way (this would be theoretically possible, but Unity puts some kind of limitation on the number FUās running in one frame to prevent a slow FU from outright hard freezing games), but it most certainly can make a game unplayable.
Iāve run into situations in 2017.x where large amounts of physics work cause FixedUpdate and the physics update to be run over and over, with almost no actual frames processed. I donāt know if this has improved with later Unity versions.
Iām honestly curious what you think there is to āimproveā about this? This is a pretty fundamental, unavoidable result of the mere concept of processing anything at a specified interval, when processing that thing takes more time than that interval. Hoping for an improvement on this behavior seems to me like hoping theyāll fix the math operators to allow you to divide by zero.
I recommend that you just ⦠do not do that. Donāt do any heavy processing in FixedUpdate, period. Have them calculate their paths elsewhere (and ideally on a separate thread, even) and then just use the path in FixedUpdate.
You can use priorities for your tasks, and when you run out of execution time, you just stop executing, so some tasks will have to wait another frame.
They did that for the Apollo missions, it worked pretty well.
Of course, you may end up with some tasks never executedā¦
This is a generic way of solving such problem, but itās probably not well adapted to specific situations in gamedev.
Another approach is to split the execution over several frames.
For example, if you have 100k enemies, you can split them in 10 blocks of 10k enemies, and each frame you compute the path for 1 block (10k units).
That way it will take 10 times less CPU each frame to compute the path of the enemies.
Of course the downside is that you may have some problems if the walls move, a door is closed, or if your units can collide and they try to go over a narrow bridge.
A third idea I have is to move the enemies by batch.
Let say you have a RTS with a lot of units, you move all the units close to the player (use the mouse position to know where the player is looking).
For the units a bit farther away, chances are they are in groups (because there is a lot of units). So, you compute the path for the unit the closest to the ācenterā of the āgroupā, and you apply the result to all the units of the group.
The downside is that itās less precise.
Exactly this. The ideal game computes and draws nothing except what the player is looking at precisely at the frame needed. Practically there is always more being computed, but you should never need to compute all the things all the time to make a fun game.
Well I had encountered the issue in a pretty self manufactured manner specifically to test it. Basically I had a scene set up in a way where if I instantiated a specific gameobject which used physics it would add around 3% CPU usage to the main thread physics were run on, and I wanted to see what would happen if I instantiated 100 of them and overwhelmed the thread. Result was I donāt believe I saw any additional frames and had to kill the process eventually.
To your question though, I would like to see a fail safe where if X number of calls to FixedUpdate / physics have occurred with exactly 0 frames processed, that it forces FixedUpdate to wait until a single frame is processed. X could be 10, 60, 100, the exact number doesnāt matter to me.