- Home /
Yielding in between functions...
Hey, so...I think there's something I don't understand about yielding.
What I would like is for one function to be called, then another, and then another, but without overlapping in time. The first function, let's say, will always take a different amount of time on every computer, because it involves some buffering. But there's a catch -- some things, such as asynchronous scene loading, or other functions might yield return an object-- to wait until an object has been completely created. This is useful in my game because I'm trying to load in a lot of images at one point, and I dont' want the game to rstop and think whil e I'm doing this. Is it possible to do this with the Here's how I'm trying to implement that now. Is it correct?
private IEnumerator DoInOrder() {
GetShelves();
yield return null;
NameShelves();
yield return null;
MediaPlacer.instance.PlaceMedia();
yield return null;
}
Okay, and assuming I understand this correctly, why does "yield return null" work at all? What does it even do? It seems it's asking the program to wait until the value "null" is returned -- but from what? The previous line? I don't get it. What does yield return break do? I've decided this yield business is thoroughly confusing to me. Please explain it to me like I'm five, via a kitten analogy. Or just explain it any way you can!
It means you wait for next frame. The compiler calls GetShelves(), then hit the yield and gets out. Next frame, it gets back to yield and continues to call NameShelves, hits the yield and gets out. Next frame, it gets to $$anonymous$$ediaPlacer, then hits the yield and gets out. Last frame it comes back to find nothing (useless).
Fact is when a yield is found the compiler, puts it on side and when back check if the time provided is done. In your case null is 0 but if you provide a WaitForSeconds(10), each time it comes back, it will decrease the deltaTime, check if it is 0 and yield if not or continue if 0.
You might want to call each function from the end of the previous so that you do not get machine dependency.
Hey, fafase, what you're saying about null translating to zero, and therefore yielding until the n ext frame makes a lot of sense. I guess now I realize, though, that the problem is that I don't think I completely thought out what I wanted. I've updated my answer in response to your comment, and owen's! cheers.
Answer by Statement · Dec 22, 2012 at 07:02 PM
The first thing to check would be the docs: http://docs.unity3d.com/Documentation/ScriptReference/index.Coroutines_26_Yield.html
Okay, and assuming I understand this correctly, why does "yield return null" work at all? What does it even do?
yield is used with enumerators. It's not a Unity specific thing, but Unity does make use of it in a "clever" way to allow code to run sequentially, over time.
http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/
I agree that "null" is not very descriptive, but what it means to Unity is that Unity will resume executing the code the next frame. So yielding null is just a way to say "Stop for 1 frame, then resume here."
What does yield return break do?
yield break; simply terminates the Coroutine by ending the Enumerator. (If this is very confusing, just read up documentation for how enumerators and yield works. You should also try out some code outside of Unity to fully appreciate what construct it is). So if you had:
//some more code above omitted...
yield return null;
yield break;
yield return null;
//some more code below omitted...
Then it would be read in english as
"Wait one frame"
"Stop the coroutine"
"Wait one frame"
What the program would do is execute the code until it reaches the first yield. Then it will resume executing the next line the next frame. That happens to be yield break, so it stops executing the code from that point. The third line (the second yield return null) would never be reached.
It seems it's asking the program to wait until the value "null" is returned -- but from what? The previous line? I don't get it.
No, you got it wrong. It just means "wait one frame".
I've decided this yield business is thoroughly confusing to me. Please explain it to me like I'm five, via a kitten analogy. Or just explain it any way you can!
I'm glad you're taking the effort to demystify something that is unknown to you. I am sure you'll have a great "AAHAA" moment once you've got your head around it.
Basically what you need to know is that Unity will accept some values that are yielded, and that you can start and stop coroutines. "yield break;" is just like a "return;" in a regular method or a "break;" in a for loop.
You can chain Coroutines together, so a Coroutine won't start until another Coroutine has ended.
IEnumerator DoTwoThingsOneAtATime()
{
Debug.Log("Entering DoTwoThingsOneAtATime");
yield return StartCoroutine(TaskOne());
yield return StartCoroutine(TaskTwo());
Debug.Log("Exiting DoTwoThingsOneAtATime");
}
IEnumerator TaskOne()
{
Debug.Log("Entering TaskOne");
Debug.Log("TaskOne waiting for 2 seconds");
yield return new WaitForSeconds(2);
Debug.Log("Exiting TaskOne");
}
IEnumerator TaskTwo()
{
Debug.Log("Entering TaskTwo");
while (!Input.GetMouseButtonDown(0))
{
Debug.Log("TaskTwo waiting for mouse press");
yield return null;
}
Debug.Log("Exiting TaskTwo");
}
There are some special objects that you can yield. For example you can yield return www; if you had a WWW object. Unity would detect it and resume executing your code once the download has completed for instance. These are the yield instructions, any type that extends YieldInstruction is designed to be passed back through a coroutine, to wait for some operation to finish. Just like WaitForSeconds.
http://docs.unity3d.com/Documentation/ScriptReference/YieldInstruction.html http://docs.unity3d.com/Documentation/ScriptReference/WWW.html http://docs.unity3d.com/Documentation/ScriptReference/WaitForSeconds.html
This summary is over 9000. Thank you so much, Statement. I understand, now, what these things mean in English -- I think yield return StartCoroutine-ing was just the process I was looking for. thanks for that!
great summary helps a lot thanks for taking the time to write this. ..."AAHHAAA" moment
Answer by Owen-Reynolds · Dec 22, 2012 at 03:46 PM
Functions normally don't "overlap in time." If you just call getShelves(), nameShelves() then placeShelves() it will for sure completely finish Get before starting Name.
If you think about this, it has to work this way. Suppose you have x=12*z+pow(y,3); print(x);
. The computer will never say "all that math is taking a while -- I'll just jump ahead and print x."
If fact, using coroutines can cause the problem you want to avoid. If you said "StartCoroutine(getShelves), Wait 0.2 seconds, nameShelves," then you're saying to not to automatically wait until Get finishes. The StartCoroutine sort of says "somebody else needs to run this."
Hey, Owen! Good to see you again. Thanks for the answer.
Unfortunately, I neglected to mention that the three functions I've mentioned also have coroutines in them -- and when the computer reaches those coroutines, it does end up going ahead without having finished the whole function. So I think my question is whether I can yield in some way that guarantees all the functions have "finished" in order. I'll update my question with regard to this. The problem is that I want to load images in a Coroutine -- and I can only do that (and some other things, like asynchronous scene loading) in a coroutine. So is there any way to make everything wait while a coroutine finishes?
What you've said, though, makes tremendous sense, and does help.
I would think the easiest way for a function to wait for another is to simply call it at the end. Other way could be to have some manager with some static variables for instance and go like
In static $$anonymous$$anager.cs
static bool done = false;
void Func$$anonymous$$anager() {
FuncA();
FuncB();
}
IEnumerator FuncA(){
//Stuff and yields
// all is done the bool is changed
$$anonymous$$anager.done = true;
}
IEnumerator FuncB(){
while(!$$anonymous$$anager.done)yield return;
//FuncA is done processing
//I can use the stuff it has loaded
}
Func A is called and return at some point to be continued later on. FuncB is called but nothing will be performed until done is turned to true. It is then somehow put on side and checked every frame.
Launching many coroutines that depends on common variables could lead to the issue of multithreading. But I do not know if you can assign locking on variables as thread does (locking ensures a variable is used in only one thread at a time) so you need to be really careful how it goes.
Edit:Few corrections done...
Thanks, fafase! I think statement's explanation really did it for me, but I can see that you're telling me the same thing! Cheers
Your answer
Follow this Question
Related Questions
Ienumerator return string 0 Answers
C# How to ping servers and get server latency? 1 Answer
How to return a variable outside NotificationCenter 0 Answers
Re-using the "same" for loop? 1 Answer
Coroutoutine doesnt work properly. 3 Answers