Mixed luck stopping a coroutine.
Throwing this one out to the community. I'm in the process of building a state machine for a turn-based rpg battle system, but have had trouble getting one of my coroutines to stop running. I am attempting to instruct the PlayerTurn coroutine to run the PlayerAttack function, which generates the damage score, just once before ceasing. To do this I'm employing a flag called coRunning. When I don't use the NextState function to advance to the next state this seems to work perfectly fine. The damage number outputs once to the console and is not calculated a second time.
When I use the NextState function, however, it outputs 32 times before moving to the next state. That in particular is what I find confusing, it isn't that it isn't working, it's just doing so on a delay. Messing with the WaitForSeconds parameter seems to change the number of times it outputs, but I don't understand why since the NextState function should be sending me into another state in which PlayerTurn cannot run. Just FYI in case of relevance, BattleProgression is being called in the Update function.
public enum BattleStates {
START,
PLAYERTURN,
ENEMYTURN,
LOSE,
WIN
}
private BattleStates currentState;
void BattleProgression() {
switch (currentState) {
case (BattleStates.START):
StartCoroutine(BattleStart());
break;
case (BattleStates.PLAYERTURN):
StartCoroutine(PlayerTurn());
break;
case (BattleStates.ENEMYTURN):
StartCoroutine(EnemyTurn());
break;
case (BattleStates.LOSE):
break;
case (BattleStates.WIN):
break;
}
}
//establishes a coroutine flag.
bool coRunning = true;
//Used to advance to the next state once all code is executed and text printed.
void NextState(BattleStates state) {
if (newText.textPrinted == newText.textToPrint.Length) {
currentState = state;
coRunning = true;
}
}
IEnumerator BattleStart() {
yield return new WaitForSeconds(0.5f);
newText.textToPrint = "The " + enemyAttackStat.brownFang.name + " approaches you."; //a + sign is used to join strings, not a &&.
if (coRunning == true) {
StartCoroutine(newText.PrintTextByLetter());
coRunning = false;
}
NextState(BattleStates.PLAYERTURN);
}
IEnumerator PlayerTurn() {
yield return new WaitForSeconds(0.5f);
if (coRunning == true) {
PlayerAttack();
Debug.Log(playerTotalDamage);
coRunning = false;
}
NextState(BattleStates.ENEMYTURN);
}
IEnumerator EnemyTurn() {
yield return new WaitForSeconds(0.5f);
if (coRunning == true) {
EnemyAttack();
Debug.Log(enemyTotalDamage);
coRunning = false;
}
}
Answer by doublemax · Oct 02, 2016 at 08:56 AM
During the time you wait 0.5sec in BattleStart(), Update() will run approximately 30 times (at 60 fps) and each time it will start a new Coroutine. That's probably not what you intended.
It only seems to do that if I use the NextState function at the end of PlayerTurn. If I don't use it, the coRunning flag does its job and shuts off the coroutine, outputting the damage figure only once. I'm confused by this because all the NextState function is doing is moving me into the next state and resetting the coRunning flag. I even found that when I removed the WaitForSeconds from Playerturn and replaced it with a null return I got the exact same behavior, multiple outputs.
I tried moving NextState out of the coroutine and place it in the next line of code in each case after the coroutine, but then it wouldn't advance to the next state at all, which also doesn't make sense to me.