PingPong() Jerks Object At Start

Simple script. Trying to get a cube to move up and down repeatedly. However when the object starts moving it jerks up and then I end up with a smooth transition. What’s going on?

public class Cube : MonoBehaviour
{
    public float max = 3f;
    public float speed = 3f;
    public float startTime;

    // Use this for initialization
    void Start()
    {
        max = transform.position.y + 3;
    }

    // Update is called once per frame
    void Update()
    {
        StartCoroutine(StartMovement(startTime));
    }

    IEnumerator StartMovement(float time)
    {
        yield return new WaitForSeconds(time);

        transform.position = new Vector3(transform.position.x, Mathf.PingPong(Time.time * speed, max), transform.position.z);
    }
}

In StartMovement you’re teleporting the Cube on the Y axis as soon as WaitForSeconds expires.

You’re also calling an additional instance of the coroutine every frame. Not sure why you’re doing that.

I changed it so the coroutine is only called once and instead use a bool to trigger the movement in update now. If I don’t use WaitForSeconds and just transform the position at start, there is no jerking motion. It seems this is causing the issue

public class Cube : MonoBehaviour
{
    public float max = 3f;
    public float speed = 3f;
    public float startTime;
    private bool start = false;

    // Use this for initialization
    void Start()
    {
        StartCoroutine(StartMovement(startTime));
    }

    // Update is called once per frame
    void Update()
    {
        if (start)
        {
            transform.position = new Vector3(transform.position.x, Mathf.PingPong(Time.time * speed, max), transform.position.z);
        }
       
    }

    IEnumerator StartMovement(float time)
    {
        yield return new WaitForSeconds(time);
        start = true;
    }
}

The jerking motion is because Time.time was starting at a different value. Mathf.PingPong will only start at 0 if the input (Time.time) starts at 0.

If you want to start the pingpong motion at a time other than the start of the game, you can do this:

private float startedAt = -1f;
private bool start = 0;

void Update() {
   if (start) {
      transform.position = new Vector3(transform.position.x, Mathf.PingPong( (Time.time - startedAt) * speed, max) , transform.position.z);
   }
}

IEnumerator StartMovement(float time)
{
    yield return new WaitForSeconds(time);
    start = true;
    startedAt = Time.time;
}

If you do this, then (Time.time - startedAt) will be 0 when the motion first begins.

Thank you this solved the problem. I started digging into the Time.time documentation afterwards. Might be a good idea to familiarize myself a little more with Time when working with it.

1 Like