- Home /
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; } }
Answer by Legend_Bacon · Mar 02, 2018 at 07:26 PM
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
Thank you very much for your time and i appreciate your help , it works like a charm but why code didn't work can you explain please (if you have time of course ) .
From what I can tell, there are a few things wrong with the piece of code above:
You're comparing two position using "==" in your first if statement. While it may seem to work for now, there is no guarantee that it always will due to the slight imprecision of floating points. Usually you want to use Vector3.Distance() ins$$anonymous$$d, with a small threshold to make sure the code catches it.
Lerps are a bit complicated, but usually you don't want to use them with speed. Ins$$anonymous$$d, I recommend you read the intro of THIS PAGE. It exactly explains how Lerps are "supposed" to work.
I hope that helps!
Cheers,
~LegendBacon
Answer by Helical · Mar 02, 2018 at 02:28 PM
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 )
Thank you for your answer, your awsome solution gives me a synchronized movement but not smooth :