how to change from one coroutine to another when while condition is false

I have created two coroutines, one for moving my badGuy game objects right and another for moving them left (please see code below).

IEnumerator moveBadGuyLeft    (Transform fromPosition, Vector3 toPosition, float duration, int newIndex)    {

               
                while (emptyPos.Contains(badGuyPos[newIndex])) {

            emptyPos.Add(badGuyPos[newIndex + 1]);
            filledPos.Remove(badGuyPos[newIndex + 1]);
                    float counter = 0;
                   
                    Vector3 startPos = fromPosition.position;
                                       
                    while (counter < duration)
                    {                       
                        counter += Time.deltaTime;
                        fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
                        yield return null;
                       
                    }
                   

            emptyPos.Remove(badGuyPos[newIndex]);
            filledPos.Add(badGuyPos[newIndex]);


                    if (newIndex  > 0)    {

                        newIndex--;
                    }

            startPos = toPosition;
            toPosition = new Vector3 (badGuyPos[newIndex], startPos.y, startPos.z);

            int waitInterval = Random.Range(3, 5);
            yield return new WaitForSeconds(waitInterval);
                }
    }
IEnumerator moveBadGuyRight    (Transform fromPosition, Vector3 toPosition, float duration, int newIndex)    {

               
                while (emptyPos.Contains(badGuyPos[newIndex])) {

            emptyPos.Add(badGuyPos[newIndex - 1]);
            filledPos.Remove(badGuyPos[newIndex - 1]);
                    float counter = 0;
                   
                    Vector3 startPos = fromPosition.position;
                                       
                    while (counter < duration)
                    {                       
                        counter += Time.deltaTime;
                        fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
                        yield return null;
                       
                    }
                   

            emptyPos.Remove(badGuyPos[newIndex]);
            filledPos.Add(badGuyPos[newIndex]);


                    if (newIndex  > 0)    {

                        newIndex++;
                    }

            startPos = toPosition;
            toPosition = new Vector3 (badGuyPos[newIndex], startPos.y, startPos.z);

            int waitInterval = Random.Range(3, 5);
            yield return new WaitForSeconds(waitInterval);
                }
    }

I am trying to move my badGuy objects left till they meet a filled position then move them right till they meet a filled position and so on, toggling between left and right. I know that if my condition

while (emptyPos.Contains(badGuyPos[newIndex]))

is false then I should change from one coroutine to the other or vice versa. How can I implement this changing between coroutines. Please see how I am calling the coroutine in the Start method below:

void Start ()        {
for (int i = 0; i < badGuys.Count; i++) {
            if (badGuys [i].getBlockType () == BadGuySetup.BadGuyType.moving) {
                int indexInBadGuyPos = badGuyPos.IndexOf(blocks[i].getBadGuyGameObject().transform.position.x);
                Vector3 targetPos = new Vector3(badGuyPos[indexInBadGuyPos - 1], badGuys[i]. getBadGuyGameObject().transform.position.y, 0.0f);
                StartCoroutine(moveBadGuyLeft(badGuys [i]. getBadGuyGameObject().transform, targetPos, 1.0f, indexInBadGuyPos - 1));



            }
        }
}

When you call StartCoroutine, store the returned Coroutine object in a variable.

So maybe have one variable “Coroutine leftCoroutine” and one variable “Coroutine rightCoroutine”.

Then do: “leftCoroutine = StartCoroutine(…)”

Then when you start the right coroutine, first call “StopCoroutine(leftCoroutine)”, and vice versa.

Since I am looping through the badGuys, some might possibly end up moving right when others are moving left. Won’t the changing the coroutine is this way make all badGuys always move in the same direction?

That may be true, I’m not entirely certain what your code is doing, or rather the intention of it. I was just trying to demonstrate a concept that you might be able to use.

It seems to me that your loop is starting them all moving the same direction all at once, with the same duration? Let me know if that’s not accurate.

If each individual badGuy should oscillate back and forth on their own, independent of one another, then you should have each badGuy control its own movement, so that when the badGuy reaches the end, it will go back the other way.

Perhaps start a coroutine like this to control the movement?

IEnumerator patrol(...){
    while(enabled){
        yield return moveRight(); // another coroutine
        yield return moveLeft(); // another coroutine
    }
}

or perhaps

IEnumerator patrol(...){
    if(condition1){
        yield return moveRight(); // another coroutine
    }else if(condition2){
        yield return moveLeft(); // another coroutine
    }
}

Yes, initially all of them are moving in the same direction for the same duration but at different time intervals. Per your explanation I guess your initial suggestion should work, but where exactly am I suppose to start the rightCoroutine and stop the leftCoroutine?

I followed your suggestion. I added the following to the if (newIndex) > 0 condition in moveBadGuyLeft and moveBadGuyRight:

in moveBadGuyLeft:

if (newIndex  > 0)    {

                        newIndex--;

                if (!emptyPos.Contains(badGuyPos[newIndex])) {
                    isMovingLeft = false;
                    badGuyDestPos = new Vector3(badGuyPos[newIndex + 2], startPos.y, startPos.z );
                    badGuyNewIndex = newIndex + 2;
                    break;
                }
            }

in moveBadGuyRight:

 if (newIndex  > 0)    {

                        newIndex++;

                if (!emptyPos.Contains(badGuyPos[newIndex])) {
                    isMovingLeft = false;
                    badGuyDestPos = new Vector3(badGuyPos[newIndex - 2], startPos.y, startPos.z );
                    badGuyNewIndex = newIndex - 2;
                    break;
                }
            }

Then I created another coroutine which is suppose to change between the two coroutines:

IEnumerator movingBadGuys(Transform fromPosition, Vector3 toPosition, float duration, int newIndex)    {
        if(isMovingLeft){
            yield return StartCoroutine (moveBadGuyLeft(fromPosition, toPosition, duration, newIndex));
        }
        else if(!isMovingLeft){
            yield return StartCoroutine (moveBadGuyRight(fromPosition, toPosition, duration, newIndex));
        }
    }

Finally I updated looping through the badguys and moving them:

for (int i = 0; i < badGuys.Count; i++) {
        if (badGuys [i].getBlockType () == BadGuySetup.BadGuyType.moving) {
            int indexInBadGuyPos = badGuyPos.IndexOf(badGuys[i].getBadGuyGameObject().transform.position.x);
            Vector3 targetPos = new Vector3(badGuyPos[indexInBadGuyPos - 1], badGuys[i]. getBadGuyGameObject().transform.position.y, 0.0f);

            badGuyDestPos = targetPos;
            badGuyMoveDuration = 1.0f;
            badGuyNewIndex = indexInBadGuyPos - 1;
            StartCoroutine(movingBadGuys(badGuys [i]. getBadGuyGameObject().transform, badGuyDestPos, badGuyMoveDuration, badGuyNewIndex));

But this is changes are not working. I am testing it with only two badGuys which always start moving left and they only move left once and stop though there are other empty positions for them to continue moving left.

IEnumerator movingBadGuys(Transform fromPosition, Vector3 toPosition, float duration, int newIndex)    {
        if(isMovingLeft){
            yield return StartCoroutine (moveBadGuyLeft(fromPosition, toPosition, duration, newIndex));
        }
        else if(!isMovingLeft){
            yield return StartCoroutine (moveBadGuyRight(fromPosition, toPosition, duration, newIndex));
        }
    }

This code will only run through once. Try something like this:

IEnumerator movingBadGuys(Transform fromPosition, Vector3 toPosition, float duration, int newIndex) {
    while(conditionToKeepMoving) {
        if(isMovingLeft) {
            yield return StartCoroutine(moveBadGuyLeft(fromPosition, toPosition, duration, newIndex));
        } else if(!isMovingLeft) {
            yield return StartCoroutine(moveBadGuyRight(fromPosition, toPosition, duration, newIndex));
        }
    }
}

or put the while loop inside “moveBadGuyRight” or “moveBadGuyLeft”. Somewhere you need to loop to keep the bad guy moving until they’ve reached the end condition.