Have you ever nested coroutines?

What situation did you need to nest coroutines in before?

I can’t make the transition step by step, even if I put a value of 30f for FadeOut (), it makes the transition from transparent to white instantly and shows the console messages well.

using System.Collections;
using UnityEngine;

namespace RPG.SceneManagement
{
    public class FadeInOut : MonoBehaviour
    {
        CanvasGroup canvasGroup;

        private void Start()
        {
            canvasGroup = GetComponent<CanvasGroup>();
            canvasGroup.alpha = 0;
            StartCoroutine(FadeOutIn());            
        }

        public IEnumerator FadeOutIn()
        {
            yield return FadeOut(30f);
            //yield return FadeIn(50f);
        }

        public IEnumerator FadeOut(float time)
        {
            while (canvasGroup.alpha < 1)
            {
                canvasGroup.alpha += time / Time.deltaTime;
            }
            print("FadeOut terminado.");
            yield return null;
        }

        public IEnumerator FadeIn(float time)
        {
            while (canvasGroup.alpha > 0)
            {
                canvasGroup.alpha -= Time.deltaTime / time;
            }
            print("FadeIn terminado.");
            yield return null;
        }
    }
}

Try swapping your time / Time.deltaTime to Time.deltaTime / time;

One nice use of nesting coroutines is having a “skippable wait”.

Since you could conceivably reuse it for multiple coroutines or multiple phases in one coroutine, it could be separated out into its own IEnumerator.

	IEnumerator MyRoutine ()
	{
		FirstThing();

		Func<bool> skipButtonWasPressed = () => Input.GetKeyDown(KeyCode.Space);
		yield return WaitForSecondsSkippable(5f, skipButtonWasPressed);

		//Ensure the state here is correct even if time/wait was skipped.
		SecondThing();
	}


	static public IEnumerator WaitForSecondsSkippable (float seconds, System.Func<bool> SkipCondition)
	{
		for (float timeElapsed = 0; timeElapsed < seconds; timeElapsed += Time.deltaTime)
		{
			if (SkipCondition != null && SkipCondition()) yield break;
			yield return null;
		}
	}

Things like this could also be achieved by writing your own custom IEnumerator type or CustomYieldInstruction subclass.

But as always, you weigh that option with how you want to manage your dependencies (your code becomes reliant on another type that you need to have the next time you want to reuse code for another project).

Nicely done!

Higher Order functions are a great way to create powerful methods without depending on the underlying code that calls the function.

For example, in this case, WaitForSecondsSkippable() does not need to know anything about what the condition is. You could pass any method that returns a bool as an argument.

Func<bool> characterAlive ()=> health.IsAlive();
yield return new WaitForSecondsSkippable(10f,  characterAlive);

Privacy & Terms