x


Figuring out Coroutines

So I have done a Tone of research into Coroutines, finding very little on thier limitations or dynamics when it comes to actually using them

so please Correct me if any of this is even remotely incorrect.

A Coroutine is a function that is starts Compatible functions (those that are IEnumerable and contain a yield). I have also heard that you can't (or there is little point to) start a Coroutine inside the update function (simply because it will update every frame anyways). though i soon realized that Update(); is also a special type of Coroutine (as is fixed update and late update).

so I haven't heard my questions asked yet so I thought I would give them a try.

  1. Can you start a Coroutine inside the update (obviously behind an if statement or some sort of filter.
  2. Can you have conditional yield statements for more complex code
  3. Can you yield for a function in a different script, perhaps one inside its own coroutine? and how would you go about it?
  4. Is it possible to Read data from a yielding Coroutine?(obviously in a way that is safe)
  5. Is a Coroutine called every frame when yield is not null?

For any of you who can post an answer I thank you in advance

more ▼

asked Mar 26 '12 at 08:35 AM

MasterLetch gravatar image

MasterLetch
239 2 6 9

yield just means WAIT UNTIL THE NEXT FRAME - it's that simple man.

a concept I love is scheduling on the next frame ... investigation here ...

http://answers.unity3d.com/questions/347468/how-to-invoke-one-frame.html

Also exactly as Sycla says, you can be your own better run loop in life if you use yield the right way.

Feb 26 at 07:27 AM Fattie

Simplistically, "yield return null" means "wait for next frame". It is very possible to yield on other things too. (See syclamoth's answer).

Feb 26 at 08:12 AM Tarlius

indeed, in US you can simply say "yield;" to yield to the next frame

Mar 01 at 03:08 PM Fattie
(comments are locked)
10|3000 characters needed characters left

3 answers: sort voted first

1: Yes, you can start a coroutine inside Update, and in fact this is a perfectly valid form of control flow (for example, if you want to perform some coroutined action over time after recieving a key-press). So long as you use 'StartCoroutine(nameOfCoroutine(paramaters));', you should be fine.

2: The yield statement can be used like any other line of code, and as such can be controlled by conditionals and loops just like anything else. There is aboslutely no reason why you can't do this.

3: If you want to yield for a function in a different script, first make sure you have a reference to that object (obviously!), and then you can call it just like any other public function, so long as you couch it inside the StartCoroutine method call. So:

yield return new StartCoroutine(otherScript.SomeCoroutine());

will work perfectly.

4: Unfortunately, it is not possible to return data from a coroutine (because of the way the scheduler works internally). If you need to read from data that is modified inside the coroutine, you'll have to just refer to members variables (rather than scope variables), since these will exist outside the scope of the coroutine.

int incrementMeOverTime = 0;

IEnumerator IncreaseTimer(float tickTime, int countUpTo)
{
    do {
        yield return new WaitForSeconds(tickTime);
        incrementMeOverTime++;
    } while (countUpTo-- > 0);
}

Outside this, you can read off 'incrementMeOverTime' to find the state of the coroutine, although I admit that this doesn't really feel like an 'elegant' solution.

The best way to get around this would be to declare a class to hold your output data, and then pass a reference to that class into the coroutine. Then, when the corutine is finished, you can read the data contained in that class.

class CoroutineInfo
{
    public int incrementMeOverTime = 0;
}

// in the function
CoroutineInfo myInfo = new CoroutineInfo;
StartCoroutine(IncreaseTimer(myInfo));
Debug.Log("The timer got to: " + myInfo.incrementMeOverTime);

5: Every time you use the 'yield' statement, the coroutine will pause execution for at least one frame. If you use 'yield return null', it will still pause for a frame- which allows you to use it a little like a temporary 'Update' function (that only gets executed up until the coroutine finishes). If you use something like 'WaitForSeconds', of course, execution will wait for longer than just one frame.

(Code examples are in C# because the syntax for coroutines is clearer in that language, and makes it more obvious exactly what is going on. I have had any number of questions here about JS couroutine, mostly stemming from justified confusion about exactly how they work. My apologies if it's not your preferred language)

Used correctly, Coroutines can almost completely supplant the Update loop. They tend to be more efficient, because if you code them right they will only be called when they actually need to do something, not just every frame like Update, and it's extremely easy to insert timing information into them (where you would have to keep and increment a member variable if you were to do that kind of thing in Update). Lately I've been reimplementing a lot of my older code to use them more extensively, because they make control flow more generally intuitive.

While it takes a little bit of practice to get your head around exactly what can and cannot be done with them (for example, you can't pass references to value types into a coroutine- however, you can pass a reference to a reference type), coroutines are a very powerful tool in your shed, and you would do well to familiarise yourself with them.

more ▼

answered Mar 26 '12 at 09:03 AM

syclamoth gravatar image

syclamoth
14.8k 7 15 80

(comments are locked)
10|3000 characters needed characters left
  1. Yes, you can start coroutines in Start but you can't make them blocking coroutines. If you need a blocking update, consider the CoUpdate pattern.

  2. Yes.

  3. All your coroutine needs is to return IEnumerator, through yield, and it will work in any function. You must still start coroutines from a script or game object though.

  4. Consider using a callback to pass data, but yes, you can do your own "wrapper" around the coroutine functionality. Coroutines aren't much more than a loop, that each frame calls MoveNext and accesses Current. You can extract the data in your own loop and then yield the result or some other value in turn. (Think a coroutine in a coroutine, but you provide the coroutine engine for the nested coroutine).

  5. It depends. If it yields null, it means to call it again next frame. If it yields for example WaitForSeconds, then it will post pone the call until the time is up.

more ▼

answered Mar 26 '12 at 08:57 AM

Statement gravatar image

Statement ♦♦
20.1k 35 70 175

If you want to "demystify" coroutines, just start learning about IEnumerator or IEnumerable, yield in general and you will understand them in much more depth.

Mar 26 '12 at 08:59 AM Statement ♦♦
(comments are locked)
10|3000 characters needed characters left

I am using coroutines for many tasks but it is exceptionally useful for clearing scene after operation is performed. It shouldn't be however used in all cases.

In post Auto destroying particle system in unity3d on my blog I am explaining behavior difference between using update and coroutine when autodestroying particle system.

Have a look you might find it usefull.

more ▼

answered Feb 17 at 04:24 AM

IEvaluation gravatar image

IEvaluation
1 1

(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x3332
x496
x334
x324

asked: Mar 26 '12 at 08:35 AM

Seen: 1679 times

Last Updated: Mar 01 at 03:08 PM