Hello everyone I have a code that loops through each “action” and it works as I want it to work except it has one bug in it that I cannot for the life of me figure out why it is happening. Pretty much I loops through all my “actions” and the very last one it never calls the end of the coroutine.
public IEnumerator SetupActions(MonsterData tempAttacker, float delayTime){
YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
for (float duration = delayTime; duration > 0; duration -= Time.fixedDeltaTime) {
yield return waitForFixedUpdate;
}
for (int n = 0; n < tempAttackerSkill.actions.Count; n++) {
//Do action stuff
Debug.Log("start nested coroutine");
StartCoroutine(InitAction(tempAttackerSkill.firstActTime));
Debug.Log("end nested coroutine");
Debug.Log ("***** BEFORE *****" );
for (float duration = tempAttackerSkill.actions[n].nextActionTime; duration > 0; duration -= Time.fixedDeltaTime) {
yield return waitForFixedUpdate;
}
Debug.Log ("***** AFTER *****" );
//Check if all actions are finished
if (passToNextMonster ){
//Do Stuff...
}
}
//Never Reaches this debug statement...
Debug.Log ("DONE LOOP" );
}
IEnumerator InitAction(float delayTime)
{
YieldInstruction waitForFixedUpdate = new WaitForFixedUpdate();
for (float duration = delayTime; duration > 0; duration -= Time.fixedDeltaTime) {
yield return waitForFixedUpdate;
}
Debug.Log ("START ACTION" );
//Do action stuff...
//Now always check if it is the last action or not to properly flow through combat!
if (action.lastAction){
//Now finished all actions
passToNextMonster = true
}
Debug.Log("END ACTION");
}
For some reason it NEVER reaches the debug statement “***** AFTER *****” on ONLY the last action, I don’t get why this is happening and its messing up my program badly lol. Once it calls InitAction on the last iteration of the for loop it never comes back to the “AFTER” debug statement. I would like it to keep going after it is done on the last iteration.
Is there some particular reason you’re having it loop and check “if the duration is 0 yet” 50x a second instead of just using WaitForSeconds for the amount of time in question? I would at least make it yield for a tenth of a second to cut that down a bit. It’s a perfectly valid way of using coroutines, so I’m not criticizing you, I’m just curious.
As to why it never gets to the AFTER, I can’t tell from this- there’s no breaks in the code, so the only thing I can think of is that the timeScale is getting changed to 0f somewhere else, or something is calling StopCoroutine() on it.
Actually, I do have one idea: nextActionTime may be getting some sort of massive out-of-proportion number or something for the final action only. I would run the Debug.Log inside of the loop to see if it’s actually breaking it at all instead of just running forever.
Hey thanks for the advice, the reason I do the coroutine like that is because when I started I was scared of potential future lag problems and I didn’t want it to break under bad conditions (I still get perfect fps, I just like to be secure) and I used the advice from this thread:
Which appears to be working nicely, am I doing something wrong or checking too much where I shouldn’t be? Coroutines is a hard concept for me to grasp for some reason and if I am doing it incorrect I would like to know
You are correct it never actually finishes the loop and no clue why honestly, I did a debug statement to see if I ever get out of my for loop and it doesn’t come out, BUT it does not loop infinitely it loops only the number of actions and just randomly stops…the last debug statement appears to be inside the “InitAction” coroutine and doesn’t come back after the for loop iteration.
I do not have any StopCoroutines(); in my code and not setting any timeScale to 0. This is very weird lol.
EDIT: I added the new debug statements in the above code to show that it never reaches the “DONE LOOP” or “end nested coroutine” and the last print statement stops at the last “END ACTION”, and if I set the loop to 3 times for example, it will show 3 START ACTION / END ACTION only so it does not infinite loop.
Maybe I am having a problem with nested coroutines?
I’m not really sure exactly why a new WaitForFixedUpdate has to be instantiated every time you call it rather than being saved in a temporary variable like you’re doing, but I assume that there’s a reason, otherwise why make it work that way? Therefore, I would change the inside of the loop to “yield return new WaitForFixedUpdate();” instead and see if that makes any difference. Also, you can put in a condition for force-breaking out of the loop using “if(counter reaches some number) break;” or w/e if necessary too.
Are you disabling this GameObject or this component in particular from outside of the code at some point? Because doing so (or doing so to its parent) will also stop the Coroutine I think… Other than that, I really absolutely can’t figure out why it would loop only the correct number of times and then stop, without actually continuing with the code afterward. Hopefully someone more familiar with Coroutines than me will come by and shed some light on the situation.
I just tried: yield return new WaitForSeconds(delayTime); AND I also tried yield return new WaitForFixedUpdate(); in replacement of the for loop delays I been using and that those both gave the same output as the original ( as in did not fix the bug that I am having). Did not work I also checked to make sure I do not disable the gameobject, and I am not.
BOOM got it solved! I had a silly piece of code inside my nested coroutine:
if (deactivateWhenDone != null){
deactivateWhenDone.SetActive(false);
}
Which would set random gameobject to false, I just didn’t think it would effect it but after you got me to start seriously double checking everything I realized this could be the problem…thank you very much for the help man! VERY HAPPY