MecAnim SubState Animation Complete

Hi folks,

Browsing around online, I’ve seen a lot of questions and answers revolved around determining if a specific animation is playing or not. What I need to do is check if any animation in a particular sub-state is playing.

Instead of storing the hash for every animation in a sub-tree (and having to add code each time a new animation is added), I’d rather simply make a check to see if any animation inside my sub-state is playing or not.

Is that feasible at all?

Attempting this in Unity 4.6 and below will result in a huge mess of unmaintainable code (made that mistake a while back). But with Unity 5’s shiny new State Machine Behaviours you can easily monitor a sub-state with a few lines of code. In order to do this we’ll need to monitor a bool parameter on our Animator component.

Add a new bool to the animator representing when you are in your sub-state such as “attacking.” This worked best for me since I’m monitoring the end of my attack animation sub-state.

On your desired sub-state machine, add this script by selecting it and clicking “Add Behaviour”.

public class SubStateMonitor : StateMachineBehaviour {
   [SerializeField] string myBool;

	override public void OnStateEnter(Animator anim, AnimatorStateInfo stateInfo, int layerIndex) {
		anim.SetBool(myBool, true);
	}

	override public void OnStateExit(Animator anim, AnimatorStateInfo stateInfo, int layerIndex) {
		anim.SetBool(myBool, false);
	}
}

You can now check if the sub-state machine is running anywhere with the following code snippet.

Animator anim = GetComponent<Animator>();
bool isSubState = anim.GetBool(myBool);

For more info on State Machine Behaviors please see the following resources.

SOLUTION!!!

The above author might have made a typo. We do not want to overwrite OnStateEnter() or OnStateExit(); we want to overwrite OnStateMachineEnter() and OnStateMachineExit(). Put this in your new script and remember to define your boolean in the Animator state machine, and enter the name in the serialized field in the editor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SubStateMonitor : StateMachineBehaviour
{
    [SerializeField] string myBool;
    override public void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
    {
        animator.SetBool(myBool, true);
    }

    override public void OnStateMachineExit(Animator animator, int stateMachinePathHash)
    {
        animator.SetBool(myBool, false);
    }
}

You can do the same boolean check as before
(animator.GetBool("YourBooleanNameHereInQuotes"));

ORIGINAL POST

So, I can test when I’m inside a state machine now but it doesn’t seem to recognize when I am inside a state anymore with (for example)

if (animator.GetCurrentAnimatorStateInfo(0).IsName("First_Punch"))

inside the state machine “Attack_Punch”

EDIT I have confirmed that when I am inside an animation state INSIDE a submachine, that inside the new behaviour script we wrote for the submachine, we automatically go through OnStateExit(), which turns our new boolean to false. This may be because I am already checking to see if I am inside another animation state (see IF statement above) and Unity can’t allow me to be in two animation states at once (or check for it, or perhaps it has something to do with indexing). During the transition between animations, the I can see that OnStateEnter() is ran again and the new boolean’s value is true again.

So this is either an unfortunate oversight or (preferably) I am forgetting to do something when I run my existing code inside an IF statement that does
if (animator.GetBool("sm_Attack_Punch")){ //Existing code, if statements here}.

Can somebody please clarify?


In the above state machine, if I attach the behaviour to Battle_JumpAttack, check that I am inside that state machine, and provided that is true, check that I am inside the first state called Jump_Start_Beginning, the current state will not be Battle_JumpAttack anymore when I am running the first animation.