Home > Software design >  Can't I use coroutine without a Monobehaviour?
Can't I use coroutine without a Monobehaviour?

Time:12-23

I want to use Coroutine in my script. But I couldn't use "StartCoroutine" because I didn't inherit MonoBehaviour.

As far as I know, I have to inherit Monobehaviour to use Coroutine. But now I can't inherit Monobehaviour. Is there any way to use Coroutine in this situation? The same goes for the Invoke function.

CodePudding user response:

I will call what you want to achieve: a Coroutine Management feature and my understanding is that you want to include that feature inside your non-MonoBehaviour class. But thanks to my Remember quote above you cannot do it right now.

But including it in-side a .dll might be possible as a .dll can contain many classes. And you can use Access Modifiers to enforce your rules (the internal modifier is my favorite).

If I were you I would treat Coroutine Management as a separate problem and would build a .dll to handle them separately so that it would not mess up with my game-play business.

CodePudding user response:

You could do what @Nikel said, and create a new MonoBehaviour class to use for your Coroutine, or you could pass a MonoBehaviour in parameters:

public class Timer
{
    private IEnumerator _timerCoroutine;
    
    private readonly Action _action;
    private readonly float _timeToWaitInSeconds;

    /// <summary>
    ///     Creates a new timer that will execute the given action after the given time.
    /// </summary>
    /// <param name="timeToWaitInSeconds"></param>
    /// <param name="action"></param>
    public Timer(float timeToWaitInSeconds, Action action)
    {
        _timeToWaitInSeconds = timeToWaitInSeconds;
        _action = action;
    }

    /// <summary>
    ///     Starts a timer that will execute an action after the time has passed
    /// </summary>
    /// <param name="monoBehaviour">The MonoBehaviour that will be used to start the coroutine</param>
    public void Start(MonoBehaviour monoBehaviour)
    {
        _timerCoroutine = TimerCoroutine();
        monoBehaviour.StartCoroutine(_timerCoroutine);
    }

    /// <summary>
    ///     Stops the timer
    /// </summary>
    /// <param name="monoBehaviour">The MonoBehaviour that will be used to stop the coroutine</param>
    public void Stop(MonoBehaviour monoBehaviour)
    {
        monoBehaviour.StopCoroutine(_timerCoroutine);
    }

    /// <summary>
    ///     The coroutine that will execute an Action after the time has passed
    /// </summary>
    /// <returns></returns>
    private IEnumerator TimerCoroutine()
    {
        yield return new WaitForSeconds(_timeToWaitInSeconds);
        _action?.Invoke();
    }
}

Then create a Timer in a MonoBehaviour as follows:

private void Start()
{
    var timer = new Timer( 5f, () => Debug.Log("Timer with 5 seconds finished") );
    timer.Start(this);
}

CodePudding user response:

Coroutine doesn't work without MonoBehaviour, but if you want to use Coroutine in non-MonoBehaviour class you can transmit MonoBehaviour class in constructor or create empty MonoBehaviour to run coroutines on them. It`s will looks like:

pubclic class CoroutineHost : MonoBehaviour{}


public class NonMonoClass
{
   private CoroutineHost _host;
   NonMonoClass()
   { 
       _host = new GameObject("CoroutineHost")
          .AddComponent<CoroutineHost>();
   }

   public void RunYourCoroutine()
   {
       _host.StartCoroutine(nameof(YourCoroutine));
   }

   // Here is should be your coroutine logic
   private IEnumerator YourCoroutine();

    //Finalizer need to destroy  gameobject 
    //when non-mono class will be ready for garbage collection.
   ~NonMonoClass()
   {
       _host.StopAllCoroutines();
       GameObject.Destroy(_host.gameobject);
       _host = null;
   }
}
  • Related