[SOLVED] Pausing a Coroutine mid-execution, and then picking up exactly where you left off

I have an IEnumerator with several functions in it, each with a yield return waitforseconds.

I would like to be able to interrupt this IEnumerator’s sequence of events, and later resume right where the IEnumerator was stopped. (By analogy, imagine a transcript of a conversation, where a phone rings and briefly derails the conversation, but then everyone goes back to what they were talking about before.)

I spent quite a while (hours!) searching forums going back over 10 years. The closest I’ve come to anything like what I’ve tried to describe is a $10 asset in the store. I’m not against buying assets, but I’d far rather learn and understand for myself. But I am not really getting far.

The other option I’ve seen is from a ~ 10 year old thread , where it is suggested that one could insert a value every so often, but I am having a hard time wrapping my head around how one might “load” the state again properly. And it’s been 10 years and Unity’s seen a lot of changes. So it does make sense to me to ask anew, here and now. And in either case, I would assume there is by now a more known, optimal way to go about this, rather than something I’d cobble together from 10 year old forum threads.

Many, many posts exist describing another inserted “while(!somebool) {yield return null}” or somesuch, but that’s not the same sort of thing I would want. Those examples stop loops; they don’t seem to take stock of where the coroutine is in its executions, and then resume from that point.

Others have suggested solutions involving “timescale=0” or somesuch, but that also doesn’t do what I would want. In the analogy I gave earlier, time doesn’t stop when the phone rings; everyone just stops what they are doing for a moment, and then shake their heads and say “Oh right, as I was saying…” And that’s the sort of functionality I’m hoping for.

Can anyone help?

You’d need to implement your own coroutine framework for that. That’s actually not that hard, it’s implemented in a pretty straightforward way.

@lordofduct 's spacepuppy framework (free, github) has support for this, with it’s RadicalCoroutine. Picking up the entire framework is probably way overkill, but you can grab just the bit you need, or look over the code to write your own.

2 Likes

I don’t understand what exactly you are looking for, but could CustomYieldInstruction be it?

It seems to go in the direction that you are looking for.

Vergils answer about using a custom time manager in this thread was very helpful with solving this problem for me.
https://forum.unity.com/threads/pause-using-timescale-0.616324/

The idea is you’d insert that after every real wait. For example:

yield return new WaitForSeconds(3.0f);
while(globalPause) yield return null; // delay if globalPause has been set, until unset
do thing A;
yield return new WaitForSeconds(5.0f);
while(globalPause) yield return null;
do thing B;

It will work, but it’s a big pain to add that in every place (unless your coroutine is mostly a loop).

Also note that this doesn’t allow you to pause the waits. If you turn on globalPause when you are 1 second into that first 3-second wait, then when you later turn globalPause off, it will continue immediately instead of waiting for 2 more seconds.

If there’s just one or two specific pre-defined places within the coroutine where it might need to pause, then this is probably a good solution. But it’s not really a “general” solution for pausing coroutines.

My coroutine is made up of several individual, smaller coroutines.

I was able to solve the problem by inserting a line at the start of each coroutine:
yield return new WaitUntil(()=>ImportantBool==true);

Each of my characters in the scene have this boolean, and so they are each capable of pausing the larger coroutine by pausing a smaller coroutine of which they are a part.

1 Like

A special “Thank you!” to you, Baste, because this helped me on my way. I really appreciate it!

1 Like

If you have any questions, I’m more than happy to assist here in this thread.

Note that that’s the same as the thing you wrote about seeing in many, many posts. It’s just a fancy way of writing “while(ImportantBool==true) yield return null”. It even has the same minor flaw Antisone mentions.

1 Like

Actually, the thing I was trying to say I saw in many posts was setting TimeScale = 0. That, I wanted to avoid.
And I can live with the minor flaw. If anything it makes sense to me. :smile:

I was thinking of this from your Q:

You found the answer you’re using now, but didn’t realize it. Where you put “new WaitUntil”, you could have put that “while(!somebool)” loop.

There is so much I don’t know; I appreciate you taking the time to explain.

I thought the “While” loop used resources every frame, and that’s why I used WaitUntil.

I know the basic approach is supposed to be “Make the thing and then optimize,” but someone as new as me can’t really tell if something is obviously a dumb approach or not. (If someone said they were going to try to use sewing needles instead of finishing nails when making a bookcase, 'cause they are basically the same shape, this would to me be obviously a bad idea.)

WaitUntil basically just asks the UnityEngine to check your condition every frame for you, instead of doing it yourself. There may be some small savings.

The main thing to remember is that computers are so fast that making things easier for you, as the programmer, is often more valuable than making things easier for the computer. (Not always, but often.) The time you spend figuring out how to optimize your program isn’t free–and it’s very often more expensive than it looks, because it doesn’t only take time now, but it also takes time later when you have to alter or debug the optimized code, which is usually harder to understand than if you’d done it in the “obvious” way.

1 Like