Coroutine with multiple Loops

Hi,
I’ve checked the documentation, tutorials and read relating Q/A but it seems I can’t find a solution.
I use a coroutine to place a number in the center of the screen and then move a letter from the center to the one of the four corners of the screen.
The code iterates only once (blink of nr 1 and moves the first letter). But I can’t get the print “reached the target” on the console. It seems stuck in the while loop.
Can anybody help me?
Cheers
Nikola

public IEnumerator PlaceLetter() {

			foreach (GameObject nrTemp in numbers) {
				// Blink for 1sec in the center of the screen
				GameObject number = Instantiate (nrTemp) as GameObject;
				number.SetActive (true);
				yield return new WaitForSeconds (1);
				number.SetActive (false);
				Destroy (number); 
				yield return new WaitForSeconds (1);

					foreach (GameObject goTemp in letters) {
						// place letter in a corner of the screen
						GameObject letter = Instantiate (goTemp) as GameObject;
						letter.SetActive (true);
						Vector3 currentPosition = letter.transform.position;

							foreach (Vector3 tpTemp in targetPositions) {
								while (Vector3.Distance (currentPosition, tpTemp) > 0.1f) { 
								letter.transform.position = Vector3.Lerp (letter.transform.position, tpTemp, speed * Time.deltaTime);
								yield return null;

								}
								print ("reached the target");

							}
					}
			}
	}

Yes, of course. That’s because you check “currentPosition” in your while loop which isn’t updated inside the while loop at all. So you compare two constant values “currentPosition” and “tpTemp”. You either want to update currentPosition as well:

while (Vector3.Distance (currentPosition, tpTemp) > 0.1f)
{
    currentPosition = Vector3.Lerp (currentPosition, tpTemp, speed * Time.deltaTime);
    letter.transform.position = currentPosition;
    yield return null;
}

or check for letter.transform.position instead of “currentPosition”:

while (Vector3.Distance (letter.transform.position, tpTemp) > 0.1f)
{
    letter.transform.position = Vector3.Lerp (letter.transform.position, tpTemp, speed * Time.deltaTime);
    yield return null;
}

Note: using Lerp that way will result in a non linear motion. The movement will be framerate dependent as it’s a non linear function. You basically move towards the target and each step you reduce the distance by a certain percentage of the remaining distance. Since the distance is getting smaller and smaller, the amount you move each step also gets smaller and smaller. Such a progression can’t be linearly scaled with Time.deltaTime.

Extreme example: If you have only 1 FPS then Time.deltaTime will be “1”. That means after 1 frame (1 sec) you have reached your target. If you have 10 FPS that deltaTime is “0.1”. So you reduce the distance by 10% each step. After 1 second You haven’t reached your target. Since 0.9^10 is about “0.3487”. So the initial distance has been reduced by only 65%. Mathematically you will never reach the target since the amount you get closer gets smaller and smaller. If the initial distance was 1 unit it would take 22 frames (or 2.2 seconds) at a framerate of 10. The time gets longer the higher the framerate is as the percentage is getting smaller at higher rates.

edit

Instead you might want to actually lerp the position in a for loop:

Vector3 startPos = letter.transform.position;
for(float t = 0; t < 1f; t += Time.deltaTime/delay)
{
    letter.transform.position = Vector3.Lerp (startPos, tpTemp, t);
}

This will move the the letter linearly to the target position within “delay” seconds. If you don’t want it to move linearly you can use some hermite spline interpolation. Usually the “blue one” is the one you want:

public static float Hermite(float t)
{
    t = Mathf.Clamp01(t);
    return t*t*3f - t*t*t*2f;
}

Now just replace t in the Lerp with Hermite(t) and your movement will fade in at the start and fade out at the end.

If you don’t want a fade in but only a fade out you can use

public static float FadeOut(float t)
{
    t = Mathf.Clamp01(t);
    return t*2 - t*t;
}

This will start linearly and gets slower at the end.

Thank’s! This clarifies a lot. I indeed prefer to lerp the postion in a for loop. Cheers