Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Animator locking animated value even when current state has no curves/keys for that value

Discussion in 'Animation' started by stregillus, Nov 10, 2016.

  1. benthroop

    benthroop

    Joined:
    Jan 5, 2007
    Posts:
    135
    This behavior caused me to waste almost an entire day. In our case, we had a group of animations in a single controller that set active/inactive on some UI elements. When we would get to an animation state that didn't include a prior UI element, it would get set to the UI Element's last active value, even though it wasn't in the track list. We noticed that this was happening when we tried to toggle active/inactive in the inspector but something was locking the value. Turns out it was Animator.

    The expected behavior here is that only the tracks that are in the active animation should be affected.

    Our solution is to manage active state in code and remove all tracks relating to Active from the entire animation controller.
     
  2. MildlyAnnoyed

    MildlyAnnoyed

    Joined:
    Jan 12, 2017
    Posts:
    7
    This problem could be solved though by introducing a root object for your heart that you don't animate. E.g.:
    HeartRoot
    |---Actual heart (Put Animator here)
    |---|---Graphics

    By animating locally in your hierarchy rather than the root object, you should be able to retain your offset position since that position is specified on the Root object. The root object should just be an empty game object.
     
  3. G-Reusch

    G-Reusch

    Joined:
    Sep 28, 2013
    Posts:
    5
    I also experienced issues with an animator applying defaults and overriding my code. I basically have an idle animation where the character bobs slightly, but the mouth sprite needed to change for the talking animation. The enabled property of the SpriteRenderers was getting set by the animations even though I wasn't animating them. I tried to set the enabled property in the animations but state transitions in the animator put an end to that real quick.

    I ultimately had to set some bools in my speaking coroutine and have the proper mouth sprite enable/disable in LateUpdate every frame the character is talking. There's no performance hit that I can notice, but if unchecking "Write Defaults" worked as intended it would not have been an issue.
     
  4. masky007

    masky007

    Joined:
    Mar 21, 2019
    Posts:
    2
    I just spent a whole day debugging why setting a simple transform.rotation wouldn't work in code.. after i figured that the animator is causing this lockdown o_O ... i just set my rotation to be set (before i set my object active) But in the near future i will want to use idle animation and not disabling the the object at all - what do i do then?

    Is Unity having plans to improve on this behaviour? It really is just headaches as it is behaving at the moment!
     
  5. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    166
    Crazy it's been 2 years since the dawn of this thread. I have a question which is nagging me: Are we using animations correctly? I commonly set up the graphics for my objects in a separate child from the main collision/ AI parent object. This seems to be best practice, as far as I've seen. But seeing as unchecking the "write defaults" checkbox does not cease the writing of values as defaults (Iron clad defaults, as we've found, with the exception of LateUpdate), are we supposed to animate changes in the transform in some other fashion than the "add property" tab in the animation editor window?

    The issue I am facing is that I have an enemy death animation, where the enemy (which is part of a pool) shrinks and spins up into the sky (kinda like what happens when you cause an extinction event in SPORE). The child object gets pushed from a y position of 0, to a y position of 3. Then I have an event at the end of the animation which disables the parent root object, returning the parent and all children to the enemy object pool. When that object is next spawned, the parent transform is fine, but the child (with the graphics) is stuck at a y position of 3. Additionally, before the animation has been played, that child is stuck at a y position of 0 (which is technically unnoticeable because it's grounded, but that's where the animation starts, so... still an issue, even if not evident).

    If anyone has a solution, a better practice, or an update on the status of a Unity response the animation property lockdown, I would greatly appreciate it. :)
     
    Last edited: May 15, 2019
  6. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    583
    Since my last post I've actually tested the behaviour of the Simple Animation component and found that the behaviour described under the headding "SimpleAnimation doesn’t support only writing the values of the current clip by default" doesn't actually work as they say. After adding a property to expose keepStoppedPlayablesConnected publicly to make it actually usable, I found that it does indeed disconnect stopped playables from the graph, yet that still doesn't prevent them from writing the values of all their curves every frame (i.e. locking the animated values). I submitted a bug report (case 1143585) and they were able to reproduce it, but I haven't heard anything else since.

    @MadboyJames Try out my Animancer plugin (link in my signature). The issue you're describing should not be a problem when you use it.

    To be honest, that only makes this whole problem more confusing because Animancer doesn't actually do anything to fix it, the problem simply doesn't happen when using the Playables API. And since Mecanim uses the Playables API internally, that means the Animator Controller must be intentionally doing something extra which screws it up ...
     
    ModLunar likes this.
  7. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    166
    Interesting. That could very well work. My dilemma is I like the Animator GUI. It has decent organizational capacity for any object with, say, less than 10 animations (arguably only 5 or less). Good for prototyping. I'll give Animancer a go.

    Update: Animancer seems pretty solid (using Lite), but the issue I'm running into is being able to edit animations without adding in a AnimatorController. Do I just need to have the AnimatorController attached while editing, then delete the component once I'm done?

    Update 2: Strangely enough, The animations are still locking my values, even with Animancer.
     
    Last edited: May 16, 2019
  8. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    583
    I meant that Animancer should fix the issue of animated values not resetting when you reuse a pooled object, not the issue with locking animated values while active. I haven't found a solution for that one.

    Unfortunately you do currently have to assign an AnimatorController to edit animations. But in Unity 2018.3 they introduced the ability for custom components to provide AnimationClips to the Animation window so I've added support for that in the v3.0 update I'm currently working on. I'm planning on releasing a beta once I finish the documentation in a couple of days so people can try it out and give me feedback while I make a trailer video and improve the store page. If it's a big part of your workflow at the moment I can put together a package of the Lite version for you in the morning.

    It would probably be best to send me a private message or post over here if you have any other questions about Animancer so we don't derail this thread.

    Edit: Animancer v3.0 is up on the store now.
     
    Last edited: May 29, 2019
  9. dormouse

    dormouse

    Joined:
    Mar 1, 2011
    Posts:
    65
    Interesting problem! I had the same headache with Mechanim/Animation state with UI. For example,
    I would like to fadeout a button (via script) then flash it. After creating an animationclip that animates alpha value, the whole UI element has been locked.
    The fadeout effect via script has no effect since the animation state stays at 'idle' state that locks everything.

    The only solution i found:
    i have to manually disable the 'animator' component on my UI element.
    When i want to play the 'flash' effect, i have enabled=true.

    To me it is very unintuitive design. Or it is better to mention this some where...overwise, we will waste thousand hours on this topic.

    thanks
     
    ModLunar likes this.
  10. killakiwi

    killakiwi

    Joined:
    Sep 5, 2013
    Posts:
    18
    Agree with everyone else that this is really intuitive.

    I have luckily found a solution that satisfies my needs.
    My goal was to have an idle animation that bobs the hips up and down, but leaves the feet to use IK so that they may fall naturally on stairs etc.
    The AnimatorOverrideController solution didn't really work for me but I managed to get it working with Playables.
    Basically you remove everything from your AnimationController as playables doesn't need it. Then you can just call this:
    Code (CSharp):
    1.  if (!animationClipPlayable.IsNull ())
    2.             animationClipPlayable.Destroy ();
    3.         animationClipPlayable = AnimationPlayableUtilities.PlayClip (GetComponentInChildren<Animator> (), randomClip, out graph);
    The Destroy is to stop the previous animation playing if there was one.
     
  11. Karsten

    Karsten

    Joined:
    Apr 8, 2012
    Posts:
    105
    wow this is a bug sold as a feature : 9 you have an animation on your character that moves the player transform just becaus eyou want to let it "slide" somewhere into bed for example, and then your pos and rotation is locked forever , except you turn off the Animator , lol jeeeez, even if you let the animcontroller run on a complete empty animation your pos and rot is still locked, my god....

    Edit: To be fair, Timeline looks interesting for such "cutscenes" , but it also looks like a hack , adding an empty Animator

    Update: look my message below how I solved this for my cases, maybe you can use the info to solve your case too!
     
    Last edited: Nov 9, 2019 at 7:32 PM
    asimdeyaf likes this.
  12. lorux

    lorux

    Joined:
    Feb 9, 2017
    Posts:
    29
    Hello, i know this has been an issue for long time. One approach i know it works is to save all keyframes shared between clips in the same animator. Another way that sometimes works is to restore hierarchy transform original state before deactivating the object that contains the animator.


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

    public static class TransformExtensions
    {
    public static void RestoreHierarchyTransforms(this Transform transform, Transform source)
    {
    transform.localPosition = source.localPosition;
    transform.localRotation = source.localRotation;
    transform.localScale = source.localScale;

    var childs = transform.OfType<RectTransform>().Join(source.OfType<RectTransform>(),
    t => t.name,
    t => t.name,
    (dest, src) => new KeyValuePair<RectTransform, RectTransform>(dest, src));

    foreach (var pair in childs) pair.Key.RestoreHierarchyTransforms(pair.Value);
    }

    public static void RestoreHierarchyTransforms(this RectTransform transform, RectTransform source)
    {
    transform.anchorMin = source.anchorMin;
    transform.anchorMax = source.anchorMax;
    transform.anchoredPosition = source.anchoredPosition;
    transform.sizeDelta = source.sizeDelta;
    transform.localScale = source.localScale;

    var childs = transform.OfType<RectTransform>().Join(source.OfType<RectTransform>(),
    t => t.name,
    t => t.name,
    (dest, src) => new KeyValuePair<RectTransform, RectTransform>(dest, src));

    foreach (var pair in childs) pair.Key.RestoreHierarchyTransforms(pair.Value);
    }
    }


    This is how i use it:


    ((RectTransform) someUiObjectThatContainsAnimator.transform)
    .RestoreHierarchyTransforms((RectTransform) GetPrefab().transform);

    someUiObjectThatContainsAnimator.gameObject.SetActive(false);


    Where the function GetPrefab() returns the object that has the hierarchy transform original state and someUiObjectThatContainsAnimator is an instance of that prefab that changed its state due current animation clip.
    The downside of this is that if you have an object that contains more than 1 child that has the same name, it may not restore it. Also if instance has changed its hierarchy state compared to the source transform (or prefab) it may not restore it.
     
    Last edited: Oct 4, 2019
    ModLunar likes this.
  13. vitorfgd

    vitorfgd

    Joined:
    Nov 4, 2014
    Posts:
    7
    It's been 3 years and unity is still pretending this is ok. This is risible.
     
    ModLunar likes this.
  14. unity_I6490ybpCNI3vg

    unity_I6490ybpCNI3vg

    Joined:
    May 30, 2018
    Posts:
    1
    Just leave +1 here.
     
  15. Karsten

    Karsten

    Joined:
    Apr 8, 2012
    Posts:
    105
    I found a way to circumvent this problem in many/most cases,
    try to do your animations (trigger animator params and code of your animation) in Unitys LateUpdate() method
    this worked in my case, seams like LateUpdate is really called even after transforms have moved "internally"
    however , try it out and please post here if it worked for you, i'm interested how it has gone in your specific case.