• Advertisement
Sign in to follow this  

Synchronize objects' movements moved by coroutine function

This topic is 659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

I'm having problems to synchronize the movement of three different objects from point A to point B and vice versa. To move the objects I use the following code:

public float time;
public Vector3 endPos;
private Vector3 startPos;

 void Start()
 {
     startPos = transform.position;
 }

 void FixedUpdate()
 {
     if(transform.position == startPos)
     {
         StartCoroutine(Move(gameObject.transform, startPos, endPos, time));
     }
     if(transform.position == endPos)
     {
         StartCoroutine(Move(gameObject.transform, endPos, startPos, time));
     }
  }

 public IEnumerator Move(Transform thisTransform, Vector3 startPosition, Vector3 endPosition, float time)
 {
     float i = 0f;
     float rate = 1/(time);
     while(i < 1)
     {
         i += Time.deltaTime * rate;
         thisTransform.position = Vector3.Lerp(startPosition, endPosition, i);
         yield return null;
     }
 }

As long as all of the objects have the same "time" value, their movements is correctly synchronized regardless the distance that they have to cover. The problems arises when they all have different "time" value. For example, if they have to move backwards and forwards from startPos(0,0,0) and endPos(5,0,0) with the following "time" value:

  • Object A time = 1 second
  • Object B time = 2 second
  • Object C time = 4 second

After 4 second, they should all be again at the same start position. However, what happen is that the fastest object (Object A) has a delay over the other two and this delay increase over time.

How can i fix this problem?

Share this post


Link to post
Share on other sites
Advertisement

Checking for equality of a Vector3 (or any floating point number) is problematic. It's unlikely that the final parameter you pass to Vector3.Lerp will be exactly 1, and unlikely that even if it is, the result will be exactly endPosition. So I'm surprised this code even sends your objects back and forth.

 

The following code worked for me:

 

    public float time = 2f;
    public Vector3 endPos;
    private Vector3 startPos;
 
    private float currentTime;
 
    // Use this for initialization
    void Start () {
        startPos = transform.position;
    }
 
    void FixedUpdate()
    {
        currentTime += Time.deltaTime;
 
        // Sawtooth wave
        currentTime %= time;
        float progress = currentTime / time;
 
        // Let's turn it into a triangle wave, which is what defines our back and forth movement
        progress = Mathf.Abs((progress - Mathf.Floor(progress + 0.5f)) * 2.0f);
        transform.position = Vector3.Lerp(startPos, endPos, progress);
    }

 

I think even with this though, the objects will get out of sync eventually due to accumulating fp precision errors. While it may be sufficient for scenario (I don't know), if you want 3 objects to stay in sync over a long period of time, you'll need to base their positions off a single simulation (rather than 3 separate simulations) - or at least ensure that the math calculations that involve Time.deltaTime are identical in all three simulations (they are not in the code I posted, since I'm using "time" to take the modulo of currentTime (and "time" is different among the 3 objects)).

Share this post


Link to post
Share on other sites

Vector3.Lerp will cap to 1.0f for the T value, which is why the equality checks would work sometimes.  Though I agree with phil_t otherwise.  Best to move all the objects in either the same coroutine or the same fixed update.  (I can't tell quite tell from the code, but this looks like a case where you don't really gain that much from a coroutine.)

Share this post


Link to post
Share on other sites

Checking for equality of a Vector3 (or any floating point number) is problematic. It's unlikely that the final parameter you pass to Vector3.Lerp will be exactly 1, and unlikely that even if it is, the result will be exactly endPosition. So I'm surprised this code even sends your objects back and forth.
 
The following code worked for me:
 

    public float time = 2f;
    public Vector3 endPos;
    private Vector3 startPos;
 
    private float currentTime;
 
    // Use this for initialization
    void Start () {
        startPos = transform.position;
    }
 
    void FixedUpdate()
    {
        currentTime += Time.deltaTime;
 
        // Sawtooth wave
        currentTime %= time;
        float progress = currentTime / time;
 
        // Let's turn it into a triangle wave, which is what defines our back and forth movement
        progress = Mathf.Abs((progress - Mathf.Floor(progress + 0.5f)) * 2.0f);
        transform.position = Vector3.Lerp(startPos, endPos, progress);
    }
 
I think even with this though, the objects will get out of sync eventually due to accumulating fp precision errors. While it may be sufficient for scenario (I don't know), if you want 3 objects to stay in sync over a long period of time, you'll need to base their positions off a single simulation (rather than 3 separate simulations) - or at least ensure that the math calculations that involve Time.deltaTime are identical in all three simulations (they are not in the code I posted, since I'm using "time" to take the modulo of currentTime (and "time" is different among the 3 objects)).

I tested your code and it works perfectly with my scenario. Indeed, the objects have to move until a certain event occurs. It usually happens within 3 minutes and in my test after 10 minutes the objects were still synchronized.

Thank you! :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement