I am trying to implement crouching in a state machine. When the transition from Idle to Crouch or vice versa happens, the player should lean the upper body forward or backwards. As long as the Coroutines can finish, everything works fine. But if the player is still going down and the first coroutine is still running and the player wants then stand up in the middle of the coroutine, it breaks. So when the player presses C again to stand up, I want to Stop the first coroutine and just then start the second one.
Unfortunately the StopCoroutine doesn’t work. When I debug, I see it still running. And I don’t unterstand why. What am I doing wrong in my code?
Note: I am starting the coroutine via the playerCamera cause my other scripts are non-MonoBehavior.
public class LeanForward
public ProcanimStateData data;
public IEnumerator LeaningForward()
// Stop the another coroutine - they cannot run at the same time.
// THIS IS WHAT IS NOT WORKING FOR ME
Vector3 target = new Vector3(data.spineDefEulerRotation.x + 11, data.spineDefEulerRotation.y, data.spineDefEulerRotation.z);
while (Vector3.Distance(data.spine.localEulerAngles, target) > 0.1f)
data.spine.localEulerAngles = Vector3.Slerp(data.spine.localEulerAngles, target, 6 * Time.deltaTime);
yield return null;
I think you’ve misunderstood what calling
else if (data.currentLeanCoroutine != this.LeaningForward())
The if-statement will ALWAYS be true because you get a new IEnumerator reference every time you call
The following code is not a direct solution to your issue, but it should help you understand how coroutine references work:
public class CoroutineExample : MonoBehaviour
private IEnumerator currentAttackCoroutine;
IEnumerator AttackCoroutine(float attackSpeed)
Debug.Log("Started attacking with speed: " + attackSpeed);
// Do some attacking here (until we stop the attack)
yield return null;
// Animate until done leaning
// (or until we stop the coroutine)
yield return null;
// Note that both of these IEnumerators are returned from the same method, AttackCoroutine(),
// only the attackSpeed arguments differ,
// yet the IEnumerator references will not be the same
IEnumerator attackCoroutineSlowVersion = AttackCoroutine(10);
IEnumerator attackCoroutineFastVersion = AttackCoroutine(50);
Debug.Log(attackCoroutineSlowVersion == attackCoroutineFastVersion); // false
// Points currentAttackCoroutine to the slow version of the AttackCoroutine
currentAttackCoroutine = attackCoroutineSlowVersion;
// Starts the slow version of the AttackCoroutine.
// This is the same as StartCoroutine(currentAttackCoroutine) in this case.
// currentAttackCoroutine is still not the same as AttackCoroutine(10)
// even though that's how it was created.
Debug.Log(currentAttackCoroutine == AttackCoroutine(10)); // false
// Stops whatever coroutine the currentAttackCoroutine variable is pointing to.
// This is the same as StopCoroutine(attackCoroutineSlowVersion) in this case.
// Note that when calling (not starting) the same Coroutine method twice
// you will get two different references
Debug.Log(AttackCoroutine(20) == AttackCoroutine(20)); // false
// This is true even when the Coroutine's method definition has no parameters
// like in your case
Debug.Log(LeaningForwardCoroutine() == LeaningForwardCoroutine()); // false
Do you see why this will always be true?:
if (data.currentLeanCoroutine != this.LeaningForward())
Something that’s confusing me and preventing me from giving you a solution is why are you letting the
LeaningForward() method start and stop coroutines?
Why is this not handled outside the method?
Is this a limitation of some animation tool in Unity or something? (I don’t use the animation tools often to be honest)