Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  4. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Losing Animator State

Discussion in 'Animation' started by quinnbot, Mar 6, 2015.

  1. quinnbot

    quinnbot

    Joined:
    Sep 18, 2014
    Posts:
    10
    I have a GameObject with an Animator component. Totally works fine until..... I disable and then (later) re-enabled the game object via SetActive calls. When the object is re-enabled, all the state of the Animator component is lost.

    Is there any way to retain the Animator state??
     
  2. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    This is the expected behaviour but we would like to change this.

    Until we do this you need to save manually the state of the controller.

    For each controller layers you need to save the current and next AnimatorStateInfo
    http://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorStateInfo.html
    http://docs.unity3d.com/ScriptReference/Animator.GetNextAnimatorStateInfo.html

    Also you may need to save all the parameter values.
    http://docs.unity3d.com/ScriptReference/Animator-parameters.html

    When you are ready to active your animator you will need to push back all this information
    http://docs.unity3d.com/ScriptReference/Animator.Play.html
     
    quinnbot likes this.
  3. quinnbot

    quinnbot

    Joined:
    Sep 18, 2014
    Posts:
    10
    Thanks for the quick reply! I'll get started writing a component for that.

    Out of curiosity, why is it implemented that way? It implies that best practice for Unity is to never disable an Animator. Is that so? If that is true - should I be arranging my project in some different way?
     
  4. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    Because it the standard in Unity, when a object become disable it has to free all the resources that it is using: asset, file, memory used, etc ....
     
  5. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    139
    I just experienced the same issue and was surprised that the animator loses its state when it's disabled. My scripts all seem to pick up where they left off when I reenable them, so I expected it to work the same with the animator. I'm looking forward to a fix for this.
     
  6. paul-georges

    paul-georges

    Joined:
    Jan 20, 2013
    Posts:
    2
    Mecanim.Dev, this only works on Unity5 correct? If I'm not mistaken, Unity4's API doesn't allow us to fetch parameters...
     
  7. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    yes you can do it in unity 4 too but you need to know at runtime what are the parameters to save, either you hardcode them or you build a dictionnary in the editor with all the parameter you would like to save

    Animator.GetBool()
    Animator.GetFloat()
     
  8. mholub

    mholub

    Joined:
    Oct 3, 2012
    Posts:
    123
    I think it should be explicitly stated in documentation.
    http://docs.unity3d.com/ScriptReference/Behaviour-enabled.html — it says nothing about it.

    I do Unity development for several years and I learned this from you now.
    It looks like innocent boolean flag and it may ruin state of your object completely. It feels wrong.
    I've never met this behaviour in Unity in other places. Can you show some more examples of MonoBehaviour subclasses which unload their state on Disable and don't load it on Enable?
     
  9. akutruff

    akutruff

    Joined:
    Jul 24, 2009
    Posts:
    44
    Yikes. Enable and disable have never cleared state on monoBehaviours or models for us... We use enabling and disabling heavily for our project and all state and assets persist for us.

    This issue with the animator is now affecting us too for enabling and disabling.

    Problem is that now that StateMachineBehaviours are in the mix - SMB's are great for making new instances of prefabs when you enter a state. I need to make sure I don't create another one just for this enable / disable case.
     
    Last edited: Sep 11, 2015
  10. Julien-Lynge

    Julien-Lynge

    Joined:
    Nov 5, 2010
    Posts:
    117
    Hey Mecanim.Dev, it looks like this still hasn't been fixed. I've put together a script per your suggestion, and it does seem to work. (I'm not bothering with using CrossFade with the NextAnimatorStateInfo, but I assume that works too).

    One issue for folks to remember: Components are disabled in order from top to bottom in the inspector. If your script that's trying to save state is below the animator, trying to save the state / parameters will not work!

    Also, keep in mind that calling animator.parameters won't get the current values! It will only fill in the default values, and it's up to you to save the current parameter values yourself. If you want to save the value of a trigger, you'll need to use GetBool, and then Set/ResetTrigger.
     
  11. duplexius

    duplexius

    Joined:
    Apr 24, 2015
    Posts:
    42
    Seriously, how is still not fixed?
    Why would anyone want to reset state when disabling an object? Restoring a complex animator while keeping script execution order is a major task and shouldn't be necessary.
     
  12. mholub

    mholub

    Joined:
    Oct 3, 2012
    Posts:
    123
    Year and half later this is not changed. Any updates?

     
  13. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    The behaviour won't be changed, unfortunately we must keep the backward compatibility with existing project and many project rely on the fact that disabled GO hierachy don't consume any memory.

    What we want to do is provide an API that would allow you to save the current state of the animation system and we are still working on this
     
  14. aaronflippo

    aaronflippo

    Joined:
    Jun 7, 2012
    Posts:
    31
    I'd just like to chime in here and ask that this be fixed. I don't understand the explanation: Objects that are disabled surely consume memory, for the state that they retain on all of their components. I've never had the expectation that disabling an object in the hierarchy would free up memory, other than perhaps textures or other assets.

    But we're talking about component data here, or what's at least conceptually component data. I would *hope* that the current state of an animation tree is perhaps a few hundred bytes at worst, and I think on balance, it's totally reasonable to spend a few hundred bytes to keep whatever chunk of memory you've allocated around while an object is disabled, so that this component behaves like every other component in Unity.

    At very least, please provide a checkbox somewhere to "keep state on disable" or something like that, rather than requiring developers to use an API so they can make this component behave like every other component seems to behave.
     
  15. Cratesmith

    Cratesmith

    Joined:
    Aug 14, 2011
    Posts:
    135
    I'm jumping on this one too.
    It might internally be unity's internal design philosophy but from the developer perspective this rears it's head as unexpected behaviour.

    A boolean value that defaults to true with "keep state on disable" could be added and be defaulted to false for old projects. It could even have a default setting in projectSettings.asset to cover dynamically added animators.

    As it stands the current behaviour is just a bug waiting to happen for anyone who hasn't experienced it before, and a headache for those who have.
     
  16. pedrocahu

    pedrocahu

    Joined:
    Jul 19, 2016
    Posts:
    1
    Any update on this? In my opinion this is a bad design decision on the user point of view because it is counterintuitive, it is expected when an object is disabled and then reenabled it should be exact the same way it was when disabled. Do velocity on rigidbodies reset when disabling? No.
    The expected behaviour should be the object to retain all of its states during disabling and enabling.
    I'm my opinion this is a bug and should be adressed.
     
  17. OskarSigvardsson

    OskarSigvardsson

    Joined:
    Sep 30, 2016
    Posts:
    5
    Mecanim.Dev how do you restore state properly if the animation was in a transition? Like, i know you can save and reset all the parameters, and that you can set the currently playing state (and time in that state) with Play(), but what if the animation is currently transitioning when you are saving?

    Incidentally, I agree with other posters that this is very unintuitive that the animator loses all state on disable/enable, since this is not the case for the vast majority of Unity components. There should be a checkbox or something to change this behavior. At the very least, there should be a simple pair of methods like GetFullAnimatorState() that returns some (possibly opaque) object representing ALL animator state, paired with a RestoreFullAnimatorState(), so it's easy to do this yourself, just save in OnDisable() and restore in OnEnable().
     
    pedrocahu likes this.
  18. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    3,238
    This thread popped up again, and what? What do you mean that disabled GO hierarchies doesn't consume any memory? They totally do. They don't magically go away from memory once they're not visible.

    People are expecting the Animator to function like all of the other components in Unity, and not just randomly dump all user data due to getting their GO turned off. MonoBehaviours doesn't lose their state when they get disabled. Colliders doesn't lose their state when they get disabled. NavMeshAgents doesn't lose their state when they get disabled. The animator does!

    You would be breaking projects that rely on deactivating and reactivating the objects in order to reset the animator if you fixed this. That could be easily fixed by just exposing a method to reset it, which doesn't exist right now.

    Also, you don't have to be backwards compatible! Unity is in no way backwards compatible in any way shape of form! Every major version change breaks something. Refusing to fix a broken feature due to backwards comparability would be yet another thing that the animator would be doing completely different from the rest of Unity!

    Please, don't spend a bunch of time creating tools that your users can use to work around the animator breaking when it's GO gets turned off. Just fix the bug!
     
    IT_MAGES, coeing and pedrocahu like this.
  19. antx

    antx

    Joined:
    Feb 16, 2012
    Posts:
    27
    I also ended up here now after several hours of trying to figure out what happend there. Does anyone already have a workaround for this problem?
     
  20. Gru

    Gru

    Joined:
    Dec 23, 2012
    Posts:
    136
    Same issue here...
     
  21. markmcguire555

    markmcguire555

    Joined:
    May 10, 2015
    Posts:
    1
    What a disaster. If I disable a GameObject, Unity might as well destroy all the textures associated with it. That would free up memory.
     
  22. zhukuai

    zhukuai

    Joined:
    Sep 22, 2016
    Posts:
    4
    Same issue... Have you provided the API yet?
     
  23. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    no, we added Animator.keepAnimatorControllerStateOnDisable to allow user to change the behaviour of the component when GO is disabled. Default value is false to keep backward compatibility with older project.

    This is available in 2018.1a2 and can only be changed by a script
     
  24. MadWatch

    MadWatch

    Joined:
    May 26, 2016
    Posts:
    7
    I just tried the keepAnimatorControllerStateOnDisable property. It does remember the state of the animator when the GO is disabled. But it doesn't remember the default value of the animated properties. Therefore the "Write Defaults" option no longer works after the GO has been disabled and re enabled.
     
    Andrey-Postelzhuk and vladrybak like this.
  25. Andrey-Postelzhuk

    Andrey-Postelzhuk

    Joined:
    Nov 26, 2013
    Posts:
    67
    I found one workaround for this crazy bug:
    1. In Animator controller we have `Reset-state`. One frame animation that reset everything to default
    2. Before disabling the object we call `Reset-trigger`, than call Animator.Update() function, than call GameObject.SetActive(false).
    3. Example:
      Code (CSharp):
      1. _animator.SetTrigger("Reset");
      2. _animator.Update(Time.deltaTime);
      3. _gameObject.SetActive(false);
     
    ALL-CAPS likes this.
  26. ALL-CAPS

    ALL-CAPS

    Joined:
    Jun 23, 2014
    Posts:
    3
    I can confirm this solution works - thanks!
     
  27. PZ4_Bailey

    PZ4_Bailey

    Joined:
    Oct 15, 2017
    Posts:
    6
    Please help this doesnt work for me!
     
    Last edited: Jun 22, 2018
  28. Andrey-Postelzhuk

    Andrey-Postelzhuk

    Joined:
    Nov 26, 2013
    Posts:
    67
    Another bug with workaround for AnimatorController and deactivating/activating game object.
    My Unity version is 2017.3.0f3.
    Steps to reproduce the bug:
    1. Activate gameObject with animator controller first time. Add needed prefabs. Call Rebind() and SetTrigger().
    2. Wait for end of animation. Deactivate gameObject with animator controller.
    3. Activate gameObject second time. Clear old instantiated prefabs and add new ones. Call Rebind() and SetTrigger().
    4. On second time animation is completely broken. If run animation from Animation window in the preview mode everything will be restored and looks 'ok'. Reactivating gameObject fixes the bug too.
    Workaround:
    Don't call Rebind() right after activating the gameObject. Wait for LateUpdate() and call Rebind() here.

    Bad example with bug:
    Code (CSharp):
    1. public class BadAnimatedObject : MonoBehaviour
    2. {
    3.     public Animator animator;
    4.     public Transform prefabParent;
    5.     public Transform prefab;
    6.  
    7.     private Transform _prefabInstance;
    8.  
    9.     public void ActivateAndRunAnimation()
    10.     {
    11.         gameObject.SetActive(true);
    12.         if (_prefabInstance != null)
    13.         {
    14.             Destroy(_prefabInstance.gameObject);
    15.         }
    16.         _prefabInstance = Instantiate(prefab, prefabParent);
    17.         animator.Rebind();
    18.         animator.SetTrigger("Run");
    19.     }
    20.  
    21.     //Called from animation
    22.     void OnRunAnimationComplete()
    23.     {
    24.         gameObject.SetActive(false);
    25.     }
    26. }
    Good example with workaround:

    Code (CSharp):
    1. public class GoodAnimatedObject : MonoBehaviour
    2. {
    3.     public Animator animator;
    4.     public Transform prefabParent;
    5.     public Transform prefab;
    6.  
    7.     private Transform _prefabInstance;
    8.  
    9.     public void ActivateAndRunAnimation()
    10.     {
    11.         gameObject.SetActive(true);
    12.         if (_prefabInstance != null)
    13.         {
    14.             Destroy(_prefabInstance.gameObject);
    15.         }
    16.         _prefabInstance = Instantiate(prefab, prefabParent);
    17.     }
    18.  
    19.     void LateUpdate()
    20.     {
    21.         enabled = false;
    22.         animator.Rebind();
    23.         animator.SetTrigger("Run");
    24.     }
    25.  
    26.     //Called from animation
    27.     void OnRunAnimationComplete()
    28.     {
    29.         gameObject.SetActive(false);
    30.     }
    31. }
     
  29. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,606
    hi @Andrey-Postelzhuk,

    would you like to log a bug for us with bad example? we would like to investigate this issue and see what is going on.

    Thanks,
     
  30. Andrey-Postelzhuk

    Andrey-Postelzhuk

    Joined:
    Nov 26, 2013
    Posts:
    67
    Hi @Mecanim-Dev
    The problem has reproduced even in the most simple case. I've made simple project with bug example and reported it. Case number: 1071547

    Note that in this example calling Rebind() in the LateUpdate() is not enough. To fix the bug it's need wait for one frame. I think that the reason is in calling Rebind() from coroutine stack.
     
    Mecanim-Dev likes this.