New instance of StateMachineBehaviour every time SetActive is called

Hi, I have Animator controller object and for some states I added my behavoiur class which derives from StateMachineBehaviour. This class has member variable holding callback and notifies me on animation state exit.

Unfortunately, I found, that every time I call SetActive(false) on GameObject which has Animator component and then again SetActive(true), my behaviour class is newly instanced. So, I am loosing any previous setup of callback as I have new class.

Is creating new instance of behaviour class every time on SetActive(true) intended behaviour? It looks, like it is wasting of memory and adds complexity into game code (need for repeated setups).

I’m afraid that’s the way Mecanim works right now. See Mecanim.Dev’s post.

Thanks. If: “The reason why you lose everything on enable/disable is because normally in unity when an object is disable it does free all the resources used by the gameobject: memory, asset, handle, etc…”, then I think it is not good solution at least for StateMachineBehaviour (SMB). You are adding it to Animator to enhance its behaviour and unless you want to destroy it, you would probably like it to stay there with settings you did from code, as settings from Editor is not possible (as it is not MonoBehaviour).

I thought that, setting something inactive removes it from scene tree processing unless you activate it back again (it is just skipped). But if there is allocation/deallocation every time it can be pretty expensive. I would expect this to happen when I want destroy whole GameObject or particular Component, but not when temporarily disabling it.

Agreed. It’s not perfect, but we have to live with what we have. :slight_smile: You could put your persistent data on a MonoBehaviour component. In your StateMachineBehaviour’s OnStateEnter, just find the MonoBehaviour:

public class MyData : MonoBehaviour {
    ...
}

public class MySMB : StateMachineBehaviour {

    private MyData myData;

    public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
        myData = animator.GetComponent<MyData>();
    }
}

Thanks again! I needed only small thing - be notified when animation is finished or state exited (either was ok for me in my case).

I tried first animation events, but unfortunately I got very unreliable behaviour with it - see: Animation events not triggered - Unity Engine - Unity Discussions (minimal project + video included)

Then I tried StateMachineBehaviour. It was reliable as it is triggered always. But there is overhead with resetting / re-instantiating.

Finnaly, I stick to good old plain solution (where AnimationEvent is my optional delegate):

  // -----------------------------------------------------------
  public void Hide(AnimationEvent aCallback = null) {
  _animator.SetBool("Hidden", true);

  if (aCallback != null) {
  StartCoroutine(WaitForAnimationEnd(_hideAnimShortHash, aCallback));
  }
  }

  // -----------------------------------------------------------
  public IEnumerator WaitForAnimationEnd(int aWaitAnimHash, AnimationEvent aCallBack) {

  while (_animator.GetCurrentAnimatorStateInfo(0).shortNameHash != aWaitAnimHash) {
  yield return 0;
  }

  while(_animator.GetCurrentAnimatorStateInfo(0).shortNameHash == aWaitAnimHash &&
  _animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1) {
  yield return 0;
  }

  //Debug.Log("Animation finished");
  aCallBack();
  }

I hope this solution does not have any hidden problems as I am still new to Unity…