When my player character is hit by an enemy two coroutines start. One coroutine disables his collider so he cant take damage, then after 4 seconds his collider is re-enabled and a sound plays to signify he is back in action, while the second coroutine makes the player model flicker in and out until 4 seconds has passed. The problem i’m having is these two coroutines dont always sync up depending on the games framerate. I think I know why this is (one uses “yield return new WaitForSeconds” and the other uses “Time.deltaTime”) but i’m not sure how I can solve the issue. Ideally I want the coroutines to be time dependant not framerate dependant. Is this possible?
It’s a weird combination in the second snippet and it’ll never sync reliably with the first one.
First of all, I’d also suggest to either combine them or use a simple “yield return null” and a custom timer. Or if one solely depends on the other to finish, you can also work with a boolean flag or some other state-indicating object. One thing to note would be the execution order, as it might happen the one waiting for the other (which finally sets the flag) could run first and won’t be able to see the new state during the same frame anymore.
Now some thoughts about the issues with your snippets:
One reason for that is the manual timer which does not make a lot of sense to me.
It basically says, yield twice per iteration and each time for roughly 0.1f seconds.
And do that as long as the delta-times of the frames which happen to start a new iteration (roughly every 0.2f seconds) have used up my “duration” of 0.4 seconds.
Now just one of the flaws in this logic:
Imagine that each frame that happens to start a new iteration might be super-short (e.g. 5ms) or super long (100 ms - for whatever reason).
In the first case of my example, the routine could potentially run 80 iterations, while each iteration actually takes at least 0.2 seconds. It’ll last for something around 800.2 seconds + frame times in between.
Second version would run only 4 times, lasting for 40.2 seconds + frame times in between.
Now these are unrealistic cases, but the theory (and sometimes practice as well) allows this.
In order to hit roughly 4 seconds and get closer to some “synchronization”, you could run that loop with fixed 20 iterations (a counter, not a timer).
That’d efftecively run 20* ~ 0.2 = ~4 seconds.
Now here comes the next problem. While WaitForSeconds(4.0f) waits (for example) 4.01 seconds, WaitForSeconds(0.1f) may (each time) finish after 0.11 seconds.
This adds up during all iterations, so you would significantly overrun 4 seconds again…
As mentioned above, combination or some other way to “tell” the coroutine to sync would be much easier and way more reliable.