Lerp in Coroutine (Crazy Behavior)

Hey my friends i have a problem that i strugle on it for days now , i make an obstacle that goes up and stay some time and return down and stay for some times also, i make it move with the Vector3.lerp function, and to make it stop i use the coroutine yield thing , all work great, but when the time goes and with some duplicante, the obstacles began to move in unsynchronized movements and move with crazy behavior , please help me, it blocks me from advancing in my project
this is the code :

IEnumerator Move()
{
//float timeToStart = Time.deltaTime;
while (isAlive) {

		if (tail.transform.position == currentPoint.position)
		{

			pointSelection++;
			yield return new WaitForSeconds (waitTime);

			if (pointSelection == points.Length) {
				pointSelection = 0;
				waitTime = waitTimeDown;
				yield return null;
			} else {

				waitTime = waitTimeUp;
				yield return null;

			}

			currentPoint = points[pointSelection];
			PlaySound (pointSelection);
		}

		tail.transform.position=Vector3.Lerp(tail.transform.position,currentPoint.position,speed );
	
		yield return null;
	}

}

Your problem is probably in speed

tail.transform.position=Vector3.Lerp(tail.transform.position,currentPoint.position,speed );

Lerp as a function goes from point A to point B, by a value from 0 to 1.

In addition to speed, try at least to give it a smoothed DeltaTime conversion

tail.transform.position=Vector3.Lerp(tail.transform.position,currentPoint.position, speed * Time.DeltaTime );

That will make the speed factor seem more natural. However the progress will not be linear.

If you wish for the movement to be linear, I would suggest remembering the starting Vector3 position at the beggining of the movement

var startPos = tail.transform.position;
float progress = 0f;

while(whatever){
   tail.transform.position=Vector3.Lerp(startPos ,currentPoint.position, progress);
   progress = Mathf.clamp(progress + speed * Time.DeltaTime, 0f, 1f);
   yield return null;
}

Lastly your condition

if (tail.transform.position == currentPoint.position)

might never be sated, because a Lerp never reaches destination unless the coeffecient (third parameter) is 1 or greater. I would suggest testing destination reached based on distance delta.

if( (tail.transform.position -currentPoint.position).magnitude < 0.05f )

Hello there,

If you know how long you want the object to be travelling for, you could use something like this:

    //SerializeField means you can assign them in the inspector
    [SerializeField] private float f_moveDuration = 4.0f;
    [SerializeField] private float f_timeToStayUp = 2.0f;
    [SerializeField] private float f_timeToStayDown = 3.0f;
    [SerializeField] private Transform tr_upTarget = null;
    [SerializeField] private Transform tr_downTarget = null;

    private Coroutine moveCoroutine = null;

    private void Start()
    {
        StartMovingObject();
    }

    // Call to start perpetual movement
    public void StartMovingObject()
    {
        moveCoroutine = StartCoroutine(MoveObjectCoroutine());
    }

    // Call to stop movement
    public void StopMovingObject()
    {
        if (moveCoroutine != null)
            StopCoroutine(moveCoroutine);
    }

    private IEnumerator MoveObjectCoroutine()
    {
        //Assuming your object starts DOWN
        bool isDown = true;
        yield return new WaitForSeconds(f_timeToStayDown);
        while(true)
        {
            float timer = 0.0f;
            Vector3 startPosition = gameObject.transform.position;
            Vector3 targetPosition = isDown ? tr_upTarget.position : tr_downTarget.position;

            // Object Starts Moving here
            while (timer < f_moveDuration)
            {
                timer += Time.deltaTime;
                float t = timer / f_moveDuration;

                //Smoothing
                t = t * t * t * (t * (6f * t - 15f) + 10f);
                gameObject.transform.position = Vector3.Lerp(startPosition, targetPosition, t);
                yield return null;
            }

            //Object has reached destination here
            isDown = !isDown;
            yield return new WaitForSeconds(isDown ? f_timeToStayDown : f_timeToStayUp);
        }

        yield return null;
    }

Throw that script onto your object, assign its variables, and you’re good to go. It’ll go up, stay a while, go down, stay a while, and start again. You can control exactly how long the objects spend moving, waiting up, and waiting down with f_moveDuration, f_timeToStayUp, and f_timeToStayDown (in seconds).

I threw a smoothing algorithm in there, but if you don’t like it you can pick any other from this page


I hope that helps!

Cheers,

~LegendBacon