How to pass "ref parameter" in iterator method?

Hi all,

I need to pass a “ref” parameter to a IEnumerator method, but I sadly found out that it’s not possible to use “ref” as a parameter in a iterator…here’s my code below, which of course throws an error:

public class CountDownTimer : MonoBehaviour {

    public static IEnumerator CountDown (string objName, string displayEndText, float timer, ref bool boolToPass) {

        // Create a new GameObject for the countdown timer and child it to "HUD"
        GameObject countDownGO = new GameObject(objName);
        countDownGO.transform.parent = GameObject.Find("HUD").transform;

        // Create the GUIText component which displays the countdown and attach it to the countDownGO gameObject created above
        GUIText countText = countDownGO.AddComponent<GUIText>();
        countText.text = timer.ToString();
        countText.font = (Font)Resources.Load("Fonts/Arial Black", typeof(Font));
        countText.material = countText.font.material;
        countText.anchor = TextAnchor.MiddleCenter;
        countText.alignment = TextAlignment.Center;
        countText.transform.position = new Vector3 (0.5f,0.5f,0.0f);
        countText.lineSpacing = 1;
        countText.tabSize = 0;

        yield return new WaitForSeconds (1.0f); // Wait 1 second before starting the timer

        // While the timer is bigger then 1, decrease it every seconds and round the number to an int
        while (timer > 1) {

            timer -= Time.deltaTime;
            countText.text = Mathf.Round(timer).ToString();

            // When timer reaches 1, wait 0.5 seconds, then display end text and call callback function, wait 1 second then destroy the gameObject
            if (timer <= 1) {

                yield return new WaitForSeconds (0.5f);
                countText.text = displayEndText;
                boolToPass = true;

                yield return new WaitForSeconds (1.0f);
                Destroy(countDownGO);
                break;

            }

            yield return null;

        }

    } // End of CountDown IEnumerator function

I have looked around and found a few solutions, but I'm having a hard time understanding them and I haven't been able to successfully apply them to my own code. Could anyone show me how to do this with my code above?

Thanks a lot!

Stephane

How about using a delegate? I don't know in for what special case you need this bool but with a delegate you can pass a callback routine.

public delegate void OnTimerExpired();

public static IEnumerator CountDown (string objName, string displayEndText, float timer, OnTimerExpired callback)
{

[...]

    if (timer <= 1)
    {
        yield return new WaitForSeconds (0.5f);
        countText.text = displayEndText;
        if (callback != null)
            callback();
[...]
}

void MyCallback()
{
    // Timer expired
}

// To start the coroutine use:
StartCoroutine(CountDown("...", "...", 5, MyCallback));


edit

You can also pass an object to your coroutine. Classes are always reference types. Just create a class that holds the data you want to return.

public class CCoroutineResult
{
    public bool MyBool = false;
}

Define your coroutine like:

public static IEnumerator CountDown (string objName, string displayEndText, float timer, CCoroutineResult result)

You can easily change the bool inside your coroutine with: `result.MyBool = true;`


second edit

Well, just realised what you are doing inside your coroutine. You could go for another approach. StartCoroutine is a method of MonoBehaviour and the coroutine that is started is bound to the MonoBehaviour object. Since your function creates a temp GO you could run the coroutine on that gameobject. Just use a static method as a kind of constructor and remove the static from your coroutine. Create the GameObject within your static method and return the script instance.

public class CountDownTimer : MonoBehaviour
{
    public string displayEndText;
    public float timer;
    bool Done = false;
    private IEnumerator CountDown ()
    {
        // Here you can do all your stuff on the actual GameObject.
        // Just refer to `gameObject`
        [...]
    }
    public static CountDownTimer CreateTimer(float aDuration, string aEndText)
    {
        // Create a new GameObject for the countdown timer and child it to "HUD"
        GameObject countDownGO = new GameObject(objName);
        CountDownTimer CDScript = countDownGO.AddComponent< CountDownTimer >();
        CDScript.timer = aDuration;
        CDScript.displayEndText = aEndText;
        CDScript.StartCoroutine(CountDown());
        return CDScript;
    }
}