Why is this coroutine only firing once?

I’m trying to make a script to make an enemy jump up and descend when the player approaches. The problem is that the coroutine controlling the enemy movement is only firing once. I did also try putting putting the contents of the coroutine into a while loop, but everything I tried with while either ended up with the same results or crashing Unity.

using UnityEngine;
using System.Collections;

public class Enemy_2 : MonoBehaviour {

	public float distance;
	public float lerp_value;

	public bool attack_triggered;

	public Vector3 bottom;
	public Vector3 top;

	public GameObject player;
	public GameObject enemy;


	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		distance = Vector2.Distance (player.transform.position, enemy.transform.position);
	

		if (distance < 15 && attack_triggered == false) {
			attack_triggered = true;
			StartCoroutine ("Jumping");
			}

	}

	IEnumerator Jumping () {

			if (transform.position != top) {
				lerp_value += 0.1f;
				Debug.Log ("Fire");
				transform.position = Vector3.Lerp (bottom, top, lerp_value);
				}
			else if (transform.position == top) {
				StartCoroutine ("Falling");
				StopCoroutine ("Jumping");
				}
		yield return null;
		}


	IEnumerator Falling () {
		if (transform.position != bottom) {
			lerp_value -= 0.1f;
			transform.position = Vector3.Lerp (top, bottom, lerp_value);
			}
		else if (transform.position == bottom) {
			attack_triggered = false;
			StopCoroutine ("Falling");
			}
		yield return null;
	}
}

Well, since you don’t have a while loop in your coroutine, it will of course only run once when you start it once. This condition:

if (transform.position == top)

is suboptimal since you compare floating point values and the position property might go through some transformations (local to world and world to local). It’s better to check the lerp value.

Next thing is you increase your lerp value from 0 to 1 and lerp from bottom to top. However in falling you start at 1 and lerp back to 0 but you have reversed top and bottom. So you again lerp from bottom to top.

Is it important to use two coroutines? It would be easier that way:

IEnumerator Jumping ()
{
    // start jumping
    for (float t = 0; t < 1; t += Time.deltaTime) 
    {
        transform.position = Vector3.Lerp (bottom, top, t);
        yield return null;
    }
    // start falling
    for (float t = 0; t < 1; t += Time.deltaTime) 
    {
        transform.position = Vector3.Lerp (top, bottom, t);
        yield return null;
    }
    // done
    attack_triggered = false;

}

ps: At the moment i increase t by Time.deltaTime which will make the jump-up take 1 second and the falling will also take 1 second. You can divide it by you desired time it should take.

    float jumpTime = 2.0f; // two seconds
    for (float t = 0; t < 1; t += Time.deltaTime / jumpTime )

Coroutines only continue their processing if you put in a loop of some sort. And they are like any other function…once you hit the bottom, the coroutine is done. A usual structure:

while('some condition') {
     // Some code here that does something repeatedly over time
     yield return null;
 }

In the particular case of your Jumping method, you could do:

IEnumerator Jumping () {

        while (transform.position != top) {
            lerp_value += 0.1f;
            transform.position = Vector3.Lerp (bottom, top, lerp_value);
            yield return null;
        }
       StartCoroutine ("Falling");
    }

Note you should really be using deltaTime when modifying your lerp_value.

Since this is the top result for this issue, I had this issue as well with Unity 2021 and the answer was completely different than any of the other suggestions.

It turns out I was using

SceneManager.MoveGameObjectToScene(gameObject, scene);

After my StartCoroutine. Internally Unity must do something during this move that cancels all coroutines, so my coroutine was only running once. After moving my StartCoroutine to after the Move, my coroutine ran as normal.