Coroutines WaitForSeconds – uneven spacing

I’m learning Unity, and I wanted to fire evenly spaced bullets at a predetermined interval. Consider, for instance, a function that accepts these two inputs:

bulletCount: 5
interval: 0.2f

This would mean fire five bullets over the course of one second, spaced out every 0.2 seconds. So you’d get 5 bullets over the course of one second, evenly spaced.

My code looks like this:

IEnumerator _MakeChain(string type, float speed, float angle, int clipSize, float delay) {
  for (int shot = 1; shot <= clipSize; shot++) {
    ShootBullet(type, speed, angle);
    yield return new WaitForSeconds(delay);
  }

  yield return null;
}

The result of this code is, well, some unevenly spaced bullets:

99290-uneven.jpg

The first bullets are always bunched up, for instance, but if you look closely you can see the others are also not evenly spaced.

Is this just a limitation of Coroutines and WaitForSeconds, or am I doing something wrong? I reached for Coroutines because of these two facts:

  1. Enemies need to be able to start multiple of the same type of “chain” of bullets at once
  2. The chains of bullets end after a set number of shots

It seems like it would be a headache to try to manage this with InvokeRepeating, since those go indefinitely, and there’s no fine-grained control over canceling these on a per-invoke status (as I understand it, canceling the invoke will cancel all ongoing invocations of the same method).

I read that WaitForSeconds can be off by a few frames, so for really “tight” spacing it might be off. I wouldn’t expect that for time frames around 200ms though for a game running at 60fps, given that each frame is an order of magnitude smaller than the delay time that I’m passing. The first few bullets look to be about at least 100ms off. Is WaitForSeconds really that unreliable?

I’m sure this is some basic stuff, but I looked around and didn’t see anything in particular that stood out as a possible fix. Is there a common approach to get around this? Thanks!

I’m guessing that this is due to the fact that the game only runs in fixed timesteps. When you say yield return new WaitForSeconds(.2) you are not guaranteed to have the following code execute after exactly .2 seconds - it could be anywhere from .2 to .216 seconds (if your game is going at 60fps). If your game is moving slower than 60 fps, it could be worse.

If this is indeed the cause the only way I could think about fixing it is to check how late you are and to spawn the projectile slightly forward from it’s normal start point to compensate.

Now, if the given picture came from the settings you described (5 shots, 1 every .2 seconds) than this is unlikely. If however it is from a much faster firing rate that this is likely the cause.

Looks like I found the culprit: starting the coroutine on the first frame. I assumed the issue was with the delay of subsequent bullets, then realized it could just as easily be a delayed first bullet causing that early bunching.

I realized if the first frame was doing too much, and lagging, then that first bullet would be delayed and cause the bunching with the second bullet.

To test this theory, I updated the script to wait 1 second before firing, and the distance between the bullets is much more sane, even without the position correction suggested by @jdean300 . I still plan to add that, but it’s good to know the cause of this anomaly.

I guess one possible takeaway here is not to do too much on that first frame? I’m not too sure, but I’ll now be delaying the testing of things to a few frames later.