- Home /
Change WaitTime, Pause and Resume Coroutines during runtime
I´ve read a couple of topics about coroutines, but haven´t figured out all solutions to my current problems. The situation is that I have a couple of different Coroutines with different WaitForSecond return values. The coroutines should stop when a specific event is happening and resume when the event is over. Furthermore the seconds-value in WaitForSeconds should be changable during runtime.
My current approach is:
private IEnumerator IncomeCoroutine()
{
while (true)
{
if (!event)
{
// Only do this if event is not true
if (currProduction != 0)
{
currFood += currProduction;
if (currFood < 0)
currFood = 0;
}
}
yield return new WaitForSeconds(incomeTime);
}
}
The problem is that I don´t know how to pause the coroutine without fully stopping it. My workaround is the if-condition in the while-loop so the main part of the IEnumerator won´t be executed during the event. Additionally I´m not sure about the performance, since I have multiple coroutines like this one and also I allocate memory for every "new WaitForSeconds(xSeconds)" in order to be able to change the "xSeconds" during runtime.
Answer by jdean300 · Dec 03, 2017 at 10:20 PM
Unity's coroutines cannot be paused by default and neither can they be changed once created. It seems like you will need to look into writing custom coroutine IEnumerators. Here is a script for a custom IEnumerator I wrote for a executing an arbitrary action as soon as a coroutine finishes:
/// <summary>
/// Routine that executes a given action as
/// soon as a given routine finishes
/// </summary>
public class DoAfter : IEnumerator
{
private readonly IEnumerator m_WaitingFor;
private readonly Action m_ActionToDo;
public bool MoveNext()
{
if (!m_WaitingFor.MoveNext())
{
m_ActionToDo();
return false;
}
return true;
}
public void Reset()
{
}
public object Current {
get { return m_WaitingFor.Current; }
}
public DoAfter(IEnumerator waitFor, Action doAfter)
{
m_WaitingFor = waitFor;
m_ActionToDo = doAfter;
}
}
Regarding the performance impact of WaitForSeconds - you can reuse WaitForSeconds as much as you want without creating new ones. Here is a little setup to do that:
public static class Wait
{
// Cache of wait times
private static readonly Dictionary<float, WaitForSeconds> m_WaitForSeconds = new Dictionary<float, WaitForSeconds>();
/// <summary>
/// Wait's the specified number of seconds.
/// </summary>
public static WaitForSeconds ForSeconds(float s)
{
// Check cache
if (m_WaitForSeconds.ContainsKey(s))
return m_WaitForSeconds[s];
m_WaitForSeconds[s] = new WaitForSeconds(s);
return m_WaitForSeconds[s];
}
}
Now instead of calling yield return new WaitForSeconds(xSeconds) you'd write yield return Wait.ForSeconds(xSeconds). For any given value of xSeconds there will only be one WaitForSeconds object instantiated. The same value can be used by multiple coroutines at the same time without issue. Note that if xSeconds is randomly calculated or involves a moderate amount of math, float precision limitations will mean the cache of WaitForSeconds values could get really large, so be careful.
Answer by Felbinger · Dec 04, 2017 at 12:51 AM
Thanks, there is pretty much everything I needed in your answer. Especially the Wait class seems very helpful. I solved the pause/play issue by starting and stopping all coroutines in the Update function when specific boolean events are given and immediately toggle them so the start/stop is only called once.
Your answer
Follow this Question
Related Questions
How to use Coroutines in C++/CLI? 1 Answer
Generating Objects at High Speeds 0 Answers
coroutine in update method 1 Answer