Getting values out of Coroutines

Hello,

I’m currently working on spells in my game and I’m facing something that I’ve never used that much : Callbacks in coroutines.
Here is the thing, in my method CastSpell() I need to Start two coroutines ManageCastTime in first place, then GoesOnCooldown.
The problem is that I have to call ManageCastTime first then GoesOnCooldown and I’m not sure how to do that …

I could make a callback to a method to Start GoesOnCooldown or starting it in ManageCastTime, but I think it’ll be better to get a boolean out of ManageCastTime.

So here is my question :
How do you get a value out of a coroutine ?

If I remember well, Coroutines consistently return values, so I’ve no clue how to do that.
I’ve checked many posts on many websites, but it seems like a lot of people are doing it in different ways.

Here is my code :

ManageCastTime

IEnumerator ManageCastTime()
    {        
        if (CastTime != 0f)
        {
            float castTimeElapsed = 0f;
            while (castTimeElapsed < CastTime)
            {
                castTimeElapsed += Time.deltaTime;
                yield return new WaitForEndOfFrame();
            }
        }
        yield return true;
    }

GoesOnCooldown

IEnumerator GoesOnCooldown()
    {
        if(Cooldown == 0f)
        {
            onCooldown = false;
            yield break; 
        }
        Debug.Log("The spell " + SpellName + " casted by " + Caster.name.ToString() + " goes on cooldown");
        onCooldown = true;
        cooldownElapsed = 0f;
        while(cooldownElapsed < Cooldown)
        {
            cooldownElapsed += Time.deltaTime;
            yield return new WaitForEndOfFrame();
        }
        onCooldown = false;
        Debug.Log("The spell " + SpellName + " casted by " + Caster.name.ToString() + " isn't in cooldown anymore");
        yield break;
    }

Thanks a lot for your help !

I personally wouldn’t use Coroutines here. Mainly because spells could be interrupted and all that jazz, but in the spirit of what you wrote - I made this as an example.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class Spell : MonoBehaviour
{
    [SerializeField] float castTime = 2.0f;
    [SerializeField] float coolDown = 5.0f;

    bool onCooldown;
    float cooldownElapsed;

    public float CastTime { get { return castTime; } }
    public float Cooldown { get { return coolDown; } }


    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space) && onCooldown == false)
        {
            StartCoroutine(CastSpell());
        }
    }


    private IEnumerator CastSpell()
    {
        yield return StartCoroutine(ManageCastTime());
        StartCoroutine(GoesOnCooldown());
    }


    private IEnumerator ManageCastTime()
    {
        Debug.Log("Start Cast");

        if (CastTime != 0f)
        {
            float castTimeElapsed = 0f;
            while (castTimeElapsed < CastTime)
            {
                castTimeElapsed += Time.deltaTime;
                yield return new WaitForEndOfFrame();
            }
        }

        Debug.Log("Cast Complete");
    }


    private IEnumerator GoesOnCooldown()
    {
        if (Cooldown == 0f)
        {
            onCooldown = false;
            yield break;
        }

        Debug.Log("Start Cooldown");

        onCooldown = true;
        cooldownElapsed = 0f;

        while (cooldownElapsed < Cooldown)
        {
            cooldownElapsed += Time.deltaTime;

            yield return new WaitForEndOfFrame();

            Debug.Log("Cooldown: " + (coolDown - cooldownElapsed));
        }

        onCooldown = false;

        Debug.Log("Cooldown Complete");
    }
}

Here you don’t need to look for a boolean, as the completion of the coroutine does it for you. The CastSpell coroutine will wait for the ManageCastTime to complete before going on to GoesOnCooldown.

Hope this helps a little.