The question is answered, right answer was accepted
yield return StartCoroutine() doesnt wait for coroutine to finish
I have a coroutine that starts a series of nested coroutines that controls how my NavMeshAgent behaves. Now this works the first time it is called, however once ChaseNav finishes and breaks, and then aiDetect.alertState == 3 again, it gets called repeatedly, firing off hundreds of my nested coroutines.
IEnumerator DoNavigation()
{
while (true)
{
if (aiDetect.alertState == 3)
{
Debug.Log("DoNavigation: Start ChaseNav Called");
yield return StartCoroutine(ChaseNav());
}
yield return 0;
}
}
Am I using coroutines or yield statements incorrectly?? Or does this look fine, and is the issue probably inside one of my nested coroutines??
Any help appreciated.
//EDIT: ChaseNav added
IEnumerator ChaseNav()
{
Debug.Log("ChaseNav called, begin Chase");
//Declare NavMeshAgents variables, speed, targetlocation and what not.
//Removed them to keep the code short
yield return 0;
int i = 0;
while (i < 1)
{
if(aiDetect.hasTarget)
agent.destination = aiDetect.targetTransform.position;
if (agent.remainingDistance < agent.stoppingDistance)
{
isChase = false;
Debug.Log("ChaseNav close, starting cover");
yield return StartCoroutine(CoverNav());
i++;
}
yield return 0;
}
//CoverNav and SearchNav done? Break out of coroutine.
Debug.Log("ChaseNav finished, break ChaseNav");
isChase = false;
yield break;
}
Can you post the code for ChaseNav as well? And just to be clear those repeated calls are all in the same frame right?
Ive added the ChaseNav coroutine to my question.
I also should have said that ChaseNav starts and waits CoverNav, which then starts and waits for a SearchNav...
Answer by SVTiare-Tom · Feb 09, 2016 at 01:15 AM
Issue has been fixed! Turns out my internal timer inside my coroutines wasn't resetting! Simply setting them to zero once started fixed it all.
Sorry for any inconvenience!
Answer by coolraiman · Feb 05, 2016 at 01:35 PM
you coroutine looks fine
you should check in your other coroutine if you have any circular coroutine calls or something
Answer by cjdev · Feb 05, 2016 at 01:35 PM
Try using yield return null;
instead of 0.
This wouldn't change the behaviour in any way. Any value that doesn't have a special meaning is interpreted by the coroutine scheduler as "wait for the next frame". You could return anything. So those values would all make it wait one frame: "Hello World"
, gameObject
, this
, false
, true
, ...
However i also would recommend to use null
ins$$anonymous$$d of 0
because "0" is a value type (int) which will be boxed on the heap and creates garbage while "null" is already a "reference type" and isn't boxed.
Note: boolean values like true and false are also value types and would be boxed. "gameObject" and "this" are a reference types and wouldn't create garbage. Though if a reference type != null is returned, the scheduler has to check if it's one of the special classes (WaitForSeconds, WaitForEndOfFrame, WWW, Coroutine, ...) so it's better to use just null
to wait one frame.
Yes, you're right sorry, while null is the better practice and what triggered the itch, what I meant was to use yield break;
ins$$anonymous$$d because the point was it's clearly an infinite while loop. But that's not really what it looks like the method is for so ins$$anonymous$$d I guess I'd do this:
IEnumerator DoNavigation()
{
if (aiDetect.alertState == 3)
{
Debug.Log("DoNavigation: Start ChaseNav Called");
yield return StartCoroutine(ChaseNav());
yield break;
}
yield return DoNavigation();
}
The while loop is a way better approach than restarting the same coroutine over and over again. That would create huge amount of garbage since everytime you start a coroutine a new object is created. A coroutine that keeps running won't allocate any garbage. His "DoNavigation" coroutine is essentially a "CoUpdate" coroutine. So it simply checks every frame if a condition is met, and if so it starts another coroutine. "DoNavigation" will wait until that nested coroutine is done and then continue checking if the condition is met again.
It's just important that the "DoNavigation" coroutine is only started once since it will keep running.
btw: You're missing "StartCoroutine" in your last line ^^.
The while loop is definitely a better approach but I was trying to work with what the OP put up there. However, I didn't consider the waste from it although I don't think it's from what you think it is. Have you ever tried calling the method in the last line without StartCoroutine? $$anonymous$$y guess is that it's returning a delegate rather than an instance of a new iterator. But still, it's a waste and would lead to a stack overflow if it was done in an infinite loop like that.
Answer by Bunny83 · Feb 06, 2016 at 02:21 AM
Make sure you only start one instance of your "DoNavigation" coroutine. You can add a Debug.Log at the beginning to see it you start it several times:
IEnumerator DoNavigation()
{
Debug.Log("DoNavigation started");
// ...
You should start that coroutine only once in Awake or Start.
When you said:
it gets called repeatedly, firing off hundreds of my nested coroutines
do you mean that this Debug Log is fired several times:
Debug.Log("DoNavigation: Start ChaseNav Called");
? If so then there are only two possible reasons:
your nested coroutine is terminated immediately without changing "alertState" and thus DoNavigation is starting a new one each frame.
you somewhere start several DoNavigation coroutines and each one is starting a seperate "ChaseNav".
Answer by SVTiare-Tom · Feb 06, 2016 at 04:08 AM
Just to clarify things, alertState is a variable in my AI_Detection script. StartNavigation and ChaseNav are all inside my AI_Navigation script, and has no control over it.
I believe the issue lies inside one of my coroutine, which yield breaks too early. Ill take a look over it over the weekend and report back if I managed to solve it!
Follow this Question
Related Questions
change the speed of animation during runtime in unity c# 0 Answers
How to get a for loop to run once per coroutine? 0 Answers
How to play a random audio clip from an array in C#? 1 Answer
Anim object with Relative Position 1 Answer
Trying to move buttons via Coroutine and transform.Translate 0 Answers