Objects get out of sync when they all run WaitForSeconds

I have several objects (called magnets) moving in a pattern:

  1. Start at StartLocationX
  2. Move to EndLocationX
  3. Wait for StopLength
  4. Move back to StartPositionX
  5. Wait for StopLength

This process is repeated forever with a co-routine that I call from the Start function.

The problem is that they get out of sync. They all wait for the same amount of time (2 seconds) and they all move a length of 5 units. I’ve made sure this is all true several times. However, one of them always gets a bit out of sync, and it keeps getting worse and worse. At first it’s just a bit out of sync, then it gets more and more out of sync.

I’m cracking my head as to the reasons why this can happen. Here’s the code:

    /// <summary>
    /// Moves the magnet from start to end and back.
    /// </summary>
    private IEnumerator MagnetMovement()
        while (true)
            // If we've reached our destination
            if (transform.position.x == EndLocationX && EndLocationX == CurrentTargetX)
                yield return new WaitForSeconds(StopLength);
                CurrentTargetX = StartLocationX;
            if (transform.position.x == StartLocationX && StartLocationX == CurrentTargetX)
                yield return new WaitForSeconds(StopLength);
                CurrentTargetX = EndLocationX;

            // Move towards our destination
            transform.position = Vector2.MoveTowards(transform.position,
                new Vector2(CurrentTargetX, transform.position.y), MagnetMoveSpeed);

            yield return 0;

Co-routines are not very precise when using WaitForSeconds. You might be telling it to wait for 2 seconds, but in actuality, if you use System.Diagnostics.Stopwatch, you’ll see that it actually takes around 0.2 seconds longer than you’d expect. This varies with systems, since faster systems will be more precise, while slower ones would be even more out of sync.

In other words, you’re better off using the update function to keep things in sync.

I’d make some kind of “MagnetCoordinator” that has the coroutine and tells the magnets when to move.