Search Unity

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??
     
    Tymianek and juanitogan like this.
  2. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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
     
    nilsdr and quinnbot like 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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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:
    195
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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:
    142
    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:
    44
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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:
    45
    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.
     
    NIOS likes this.
  15. Cratesmith

    Cratesmith

    Joined:
    Aug 14, 2011
    Posts:
    137
    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.
     
    NIOS likes this.
  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.
     
    arpeggi5150, NIOS and TextusGames like this.
  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().
     
    NIOS and pedrocahu like this.
  18. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    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!
     
  19. antx

    antx

    Joined:
    Feb 16, 2012
    Posts:
    28
    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:
    142
    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?
     
    arpeggi5150 likes this.
  23. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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:
    112
    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.
     
  25. Andrey-Postelzhuk

    Andrey-Postelzhuk

    Joined:
    Nov 26, 2013
    Posts:
    75
    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:
    9
    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:
    75
    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

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    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:
    75
    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.
  31. nilsdr

    nilsdr

    Joined:
    Oct 24, 2017
    Posts:
    374
    works for me, thanks
     
  32. douglassophies

    douglassophies

    Joined:
    Jun 17, 2012
    Posts:
    141
    I spent way too long trying to debug this 'feature' before i found this thread. As someone who does not normally work with animation but is used to the Unity convention of things being as you left them when you re-enable, this is a headache. Nice that we have the new code setting but can we not have this in the editor? I can almost guarantee this will trip me up again one day when i forget to enable the keepAnimatorControllerStateOnDisable in code. With presets and import settings we could make this default to what seems normal to us and we would never have to worry about it again.
     
    TextusGames likes this.
  33. gdbjohnson3

    gdbjohnson3

    Joined:
    Mar 11, 2018
    Posts:
    13
    Is this problem still not solved? I just tried it, if my animated object was animated to a rotation of say 180 degrees when it was disabled, then on enable, as soon as the animation is completed, the GO returns to 180 degrees rotation, the value at the time the GO was disabled. This basically makes this feature unusable. I'm going to try and play with events to see if I can overcome this, but I'm worried anything I come up with will be buggy as hell.

    If anyone has a workaround approach, I would appreciate hearing it.

    -- EDIT --

    Reading the above quote, just as a lark after posting this, I tried turning off "Write Defaults" on the Controller, and voila, for me, the problem is solved. Since the animation exits at the values I want the GO to be at, I don't get the undesired behaviour of the GO flipping to whatever values the GO was at when it was disabled. Of course, this is fragile, and I'm sure I'll be running into more problems related to animations on disable soon.
     
    Last edited: Feb 3, 2019
  34. Tymianek

    Tymianek

    Joined:
    May 16, 2015
    Posts:
    97
    keepAnimatorControllerStateOnDisable didn't appear to do anything in my case

    Edit: Back then I probably missed the interaction between nested animators. For example, I should enable keepAnimatorControllerStateOnDisable on a Button, and not on my UIPanel that holds the button.
     
    Last edited: Sep 19, 2022
  35. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    My Animancer plugin (link in my signature) has a toggle in the Inspector (and in code) to determine whether it should stop all animations when disabled.

    Incidentally, the reasoning that this behaviour is to conserve memory seems ridiculous to me. One of the most common reasons (if not the most common) to deactivate and reactivate objects is for object pooling, the main purpose of which is to improve performance by avoiding memory allocation and deallocation when reusing objects, not to conserve memory. Memory is cheap. Speed and functionality are almost always more important.
     
    Last edited: Jun 13, 2019
    TheSecretGordon likes this.
  36. reitzensteinm

    reitzensteinm

    Joined:
    Feb 9, 2015
    Posts:
    16
    Any news on when this bug will be fixed?
     
  37. lorux

    lorux

    Joined:
    Feb 9, 2017
    Posts:
    31
  38. themeshpotato

    themeshpotato

    Joined:
    Apr 11, 2018
    Posts:
    55
    Would be cool with a simple way to make animator state persistent. Any news on a way to do this besides saving the state yourself?
     
  39. alexerd

    alexerd

    Joined:
    Nov 5, 2019
    Posts:
    11
    Thanks for sharing good information
     
  40. phonicpod

    phonicpod

    Joined:
    Mar 23, 2020
    Posts:
    1
    Me either. It's only been 5 years though I guess we should still wait for a fix right?
     
    arpeggi5150 and gustavoluciogd like this.
  41. s-sixteen

    s-sixteen

    Joined:
    Aug 22, 2015
    Posts:
    7
    Sometimes you need to create a checkpoint system. To do this, the state of non-static and/or moving objects needs to be saved, as some of these might get destroyed later in the game.

    One particularly easy way to do this is creating duplicates of those GameObjects that need to be saved and disabling them. Then, when loading the checkpoint, the original objects (if they still exist) are deleted and the duplicates are activated.

    However, If a duplicated object had an Animator component, the activated copy is not identical to the original. This may cause some trivial errors such as incorrect model pose, but may be more troublesome e.g. if physics is involved (animated doors that are closed instead of opened etc.).

    It would have been really, REALLY awesome if the Animator could simply save its exact state. As others have already stated, this is consistent with other Unity objects
     
    themeshpotato likes this.
  42. oleg_v

    oleg_v

    Joined:
    Nov 10, 2017
    Posts:
    68
    Another hero meet this problem :)
    Found
    keepAnimatorControllerStateOnDisable
    only by code completion. Later found it in this thread :| first question - why this is still not editor property?

    Unity animations are really hard to play with: simple task - menu animation grown to some monstruous code-ui-stuff-mix. Thats why:
    • Conditional transitions from init state is not working (hi to hack with extra state)
    • States w/o motions are hard (or impossible) to setup as freeze-frame for given offset
    • Material animations are not supported (yes, they can be shared, yes, it's possible to write property-setter-wrapper, but...)
    • Animation state/params are not preserved on enable/disable (w/o help of this thread :)

    Don't want to mention dev team, but i think it's time to completely rewrite Unity Animations for actual dev needs and actual Unity state (URP, materials, new ShaderGraph etc) :|
     
  43. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    They are making a new animation system called Kinematica.

    But I have faith in their ability to screw it up again just like the last 3 attempts and totally miss the basic needs of an animation system.
     
  44. oleg_v

    oleg_v

    Joined:
    Nov 10, 2017
    Posts:
    68
    Kinematica is character animation system w/o state graph (per description, mentioned auto posing and so on). Not sure it'll be suitable for simple animations like menu transitions.

    Anyway i solved my problems with UI with a help of hacks and garbage code :) Will generalize it after finalizing of UI concept.
    Btw, thats why i don't believe in bolt - it's easier to write code from start comparing to write workarounds later for system built visually.
     
  45. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    429
    private void Awake
    {
    GetComponent<Animator>().keepAnimatorControllerStateOnDisable = true;
    }

    This keeps default values now.
     
  46. Warptarium

    Warptarium

    Joined:
    Feb 5, 2018
    Posts:
    1
    Thanks! :D
     
    arpeggi5150 and TextusGames like this.
  47. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Was doing optimization by disabling animator for doors and other "fixed" state items... and found out they were losing states. Glad that flag exists.

    But honestly, there should be an easy way to "pause" an animator so it doesn't take any CPU cycles.
     
  48. LaneMax

    LaneMax

    Joined:
    Aug 12, 2013
    Posts:
    194
    ...wtf Unity!

    image.png
     
  49. arpeggi5150

    arpeggi5150

    Joined:
    May 23, 2021
    Posts:
    27
    You Rock
     
    Ben_Harding_Audio likes this.
  50. arpeggi5150

    arpeggi5150

    Joined:
    May 23, 2021
    Posts:
    27