Search code examples
c#unity-game-enginedelayyieldcoroutine

Why isn't my "yield" working?


i'm very new to programming and i have a feeling that there is a very stupid mistake here. But can anyone explain me, why instead of 4 messages with a delay of 2 seconds between, i instantaniously get the last message shown only.

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using UnityEngine.UI;

public class Wait : MonoBehaviour {

    private int i = 0;
    public string[] message;

    [SerializeField]
    private Text toText;

    public IEnumerator Message(float waitTime)
    {
        toText.text = message[i];
        i++;
        yield return new WaitForSeconds(waitTime = 2f);
    }

    void Start()
    {
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
    }
}

Solution

  • void Start()
    {
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
        StartCoroutine(Message(i));
    }
    

    I don't think that is doing what you think it should. This will not wait for each StartCoroutine to finish and will call the next StartCoroutine.

    This is what happens:

    The first StartCoroutine(Message(i)); call will start the Message function. Once it meets the yield return new WaitForSeconds(waitTime = 2f); line of code, it will then jump back into the Start() function.

    The next StartCoroutine(Message(i)); will be called then the-same thing will happen again.

    When calling a coroutine function from a non coroutine function, as long as you have yield return new WaitForSeconds, yield return null;, or yield return what-ever YieldInstruction is implemented, the execution will return to that non coroutine function in-which the StartCoroutine function was called from and continue to execute other code.

    To make coroutine wait for another one to finish, make the StartCoroutine(Message(i)); function call from another coroutine function. This will allow you to yield each coroutine function call. This is called chaining coroutine.

    To chain or yield a coroutine function call, simply put yield return in front of the StartCoroutine function. yield return StartCoroutine(Message(i));

    public class Wait : MonoBehaviour {
        private int i = 0;
        public string[] message;
    
        [SerializeField]
        private Text toText;
    
        public IEnumerator Message(float waitTime)
        {
            // toText.text = message[i];
            i++;
            yield return new WaitForSeconds(waitTime = 2f);
        }
    
        void Start()
        {
            StartCoroutine(startMessage());
        }
    
        IEnumerator startMessage()
        {
            yield return StartCoroutine(Message(i));//Wait until this coroutine function retuns
            yield return StartCoroutine(Message(i));//Wait until this coroutine function retuns
            yield return StartCoroutine(Message(i));//Wait until this coroutine function retuns
            yield return StartCoroutine(Message(i));//Wait until this coroutine function retuns
        }
    }
    

    Now, each StartCoroutine(Message(i)); call will wait until the first one finishes. You can always use a boolean variable to do this but it is much better to yield the StartCoroutine call.