3
\$\begingroup\$

I have a coroutine, which I called from the Update() method on every click.

First, I call AddTrunk() to add to my trunkList, then I use my coroutine to move the animation for 0.3 seconds. After 0.3 seconds, it calls Destroy(), and then it changes transform.position. However, before completing the animation, it runs transform.position; it first my tree down first, and then does the animation.


This is where I call my coroutine:

void Update () 
{
    if (Input.GetMouseButtonDown (0)) 
    {
        AddTrunk ();

        if (!isRunning) 
        {
            StartCoroutine (BranchOutAnimation ());
        }
    }
}

Here is the coroutine BranchOutAnimation():

IEnumerator BranchOutAnimation()
{
    while (true) 
    {
        isRunning = true;
        iTween.MoveTo (trunkList[index], 
            new Vector3 (trunkList[index].transform.position.x 
            - 5f, trunkList[index].transform.position.y, 
            trunkList [index].transform.position.z), 0.3f);
        yield return new WaitForSeconds (0.3f);

        Destroy (trunkList [index]);
        trunkList.RemoveAt (index);
        transform.position = new Vector3 (transform.position.x, transform.position.y 
            - treeHeight, transform.position.z);
        isRunning = false;
        yield break;
    }
}

What am I doing wrong?

\$\endgroup\$
3
  • \$\begingroup\$ @Lasse, sounds like you should post that as an answer. \$\endgroup\$
    – Gnemlock
    Commented Apr 27, 2017 at 10:30
  • 2
    \$\begingroup\$ One tip based on your code, just because it's burned me in the past. I would set isRunning = true immediately in your if(!sRunning) statement, but set it false where you do. This will help prevent the very unlikely occurrence of the coroutine initiating twice if called very rapidly. \$\endgroup\$ Commented Apr 27, 2017 at 17:42
  • \$\begingroup\$ @JesseWilliams since Unity runs its Update methods single-threaded, the coroutine can't be initiated twice here. The Coroutine runs all the way up to its first yield statement immediately when it's started, before StatCoroutine returns, on the same thread as the update method that started it (ie. the main thread), so there's no opportunity for other main thread code to preempt the setting of this flag. You'll only run into trouble if you put the flag after the first yield, or if you have code you've manually initiated on another thread also mucking with that flag. \$\endgroup\$
    – DMGregory
    Commented Oct 9, 2017 at 14:51

1 Answer 1

4
\$\begingroup\$

Calling yield break breaks the coroutine and the while loop in it won't start over again. The while loop goes through only once after waiting for 0.3 seconds. Use the yield break only when you want to break out from the coroutine. If you want the while loop to go through multiple times, try yield return null; which will just make the coroutine to wait for one frame.

If you actually want to run the whole code block only once, just remove the while loop as it would behave exactly the same.

Based on your code I'm guessing/assuming you want to grow the tree until there are no more trunks in the list, and finally just remove the whole tree. Here's some untested code to help you out:

IEnumerator BranchOutAnimation()
{
    // Make sure we are running only one coroutine
    if(isRunning)
        yield break;

    isRunning = true;

    // Which index did we start from?
    int trunkIndex = index;

    // Just make the animation interval configurable for easier modification later
    const float animationInterval = 0.3f;

    // Loop until instructed otherwise
    while (true) 
    {
        // Do some nice animation
        iTween.MoveTo (trunkList[trunkIndex], new Vector3 (trunkList[trunkIndex].transform.position.x - 5f, trunkList[trunkIndex].transform.position.y, trunkList [trunkIndex].transform.position.z), animationInterval);

        // Make the coroutine wait for a moment
        yield return new WaitForSeconds (animationInterval);

        // Increase index of the animation
        trunkIndex++;

        // Check if we have reached the last index
        if(trunkIndex == trunkList.Count)
        {
            // Break the while loop, NOT the coroutine
            break;
        }
    }

    // Finally just remove the whole tree
    for(int i = trunkList.Count - 1; i >= 0 ; i--)
    {
        Destroy (trunkList [i]);
        trunkList.RemoveAt (i);
        transform.position = new Vector3 (transform.position.x, transform.position.y - treeHeight, transform.position.z);
    }

    isRunning = false;
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .