Search Unity

Animation API acts funny, some parts not documented.

Discussion in 'Scripting' started by horsman, Apr 3, 2009.

  1. horsman

    horsman

    Joined:
    Jul 19, 2008
    Posts:
    156
    So there is some interesting things about the animation API, especially when it comes to using AnimationState.

    It seems like Animation states, which animations are enabled, and more (I'm not sure what else) get reset when you disable / enable a gameobject with an animation. All the layers are set back to 0, for instance.

    Is this intended functionality, and if so, why isn't it documented? If not, what are the other pitfalls?

    Some other weird things: If you play an animation by name, editing the animation state for that name takes effect, however if it is the default clip and you play it with Play(), changing the animation state for the default clip does not effect playback.

    Animations set to Once have a normalizedTime at 0 once they finish playing, where I would expect they would sit at 1.0, Clamp forever does not finish playing, so if it was a 1 second animation, and you let it play for 8, setting the speed to -1 would not start the backwards animation for 7 seconds. I would expect it would start right away, or that Once would fulfill this role.

    One other thing I don't get about the animation API is why it insists on using Strings for looking up the animations states or referring to clips. We have the AnimationClip type and you would think it would be best to just pass in the object.

    These are just comments, I don't really care which way Unity implements animations as long is there is consistency with the documentation, and that stranger parts such as above are documented.

    What other strange things have you guys noticed with Animations? Maybe if we talk about it we can get it worked out on our own.
     
  2. horsman

    horsman

    Joined:
    Jul 19, 2008
    Posts:
    156
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Disabling a game object will cleanup animation states, Instead you might want to look at the animation.enabled flag.


    The usage of the animation API is usually that AnimationClips are automatically assigned to characters based on the importing of a model. Thus a script usually doesn't have a reference to an actual animationclip. Thus in 99.9% of all use cases, the string based version is more handy. Easier to understand and nicely decouples the script from specific animationclips.

    As far as I can see this works correctly for me. Do you have a sample project that shows the behaviour you describe? If so, file a bug with the project folder.

    Possibly that would be the more intuitive behaviour. Of course it's a bit more consistent the way it's handled now, as in, the time value always progresses forward even when loop and pingpong is used. It's something we can't change at this point however for backwards compatibility reasons.
    Just use AnimationState.time to set it to the right position when starting the animation backwards.
     
  4. horsman

    horsman

    Joined:
    Jul 19, 2008
    Posts:
    156
    Here s some other great ones!

    if you call an animation state function in OnEnable, animations will no longer work for that object.

    Likewise, if you call an animation state function and the object is disabled, animations will no longer work for that object.

    There is really not a good way to deactivate an object with an animation on it and keep state.
     
  5. MikaMobile

    MikaMobile

    Joined:
    Jan 29, 2009
    Posts:
    845
    I ran into this same issue with my last project - I wanted to disable/enable my enemy gameObjects to hide them when they died or despawned, but it caused seriously bizarre results when I recycled them later by re-enabling them.

    The workaround I used was to disable the mesh renderer and the script component, rather than the gameObject. In my case, this produced the same desired results (the object wasn't running its script anymore and it was invisible) and didn't have the side effect of mangling my animations when the object was reactivated.
     
  6. horsman

    horsman

    Joined:
    Jul 19, 2008
    Posts:
    156
    I have here a summary of the problems.

    1. Deactivating and Reactivating a GameObject with an Animation clears all it's AnimationStates.

    2. Any attempt to edit AnimationState on a deactivated object results in Animations no longer working on the object (even when they are re-enabled), and no errors are reported.

    3. Editing AnimationStates during OnEnable results in the same behavior.

    4. These problems also exist when using GameObject.SampleAnimation().

    5. Enabling, editing AnimationState, calling Sample(), and disabling also does not work, resulting in the same behaviour, though not always breaking Animations.

    6. Enabling and then editing Animation state after the object is re-enabled does not work, unless you use Play or CrossFade.

    This results in a situation where it is impossible to save the state of an object with animations that can be deactivated. If you try to save when the object is deactivated, you will ruin the animations on it because you can't access the state information.

    If you try to set the animation to a saved version when the object is disabled, you will ruin it. If you dont try to set the animation until after you enable the object, animation states and Sample do not work until the animation has been played by .Play or .CrossFade at least once.

    This requires building the game from the ground up to have all things with Animations have custom code for disabling and re-enabling.

    Does anyone have more information on what is happening or solutions to the problem?
     
    nventimiglia likes this.
  7. MikaMobile

    MikaMobile

    Joined:
    Jan 29, 2009
    Posts:
    845
    Does the workaround I posted not work in your case? (disabling the renderer and script instead of the gameobject)
     
  8. BogdanDude

    BogdanDude

    Joined:
    Jun 18, 2009
    Posts:
    89
    Did you guys find any better way to set a gameobject active/inactive and keep the animation states?

    I ran into this problem too, and I think it's also crashing my game on the iPhone when I get the error "The animation state could not be played because it is not attached to the animation component!
    You have to provide an animation state that is attached to the same animation component."
    BTW, that error doesn't even tell me where it tried to play an animation in the code.
     
  9. jerrodputman

    jerrodputman

    Joined:
    Jun 4, 2008
    Posts:
    181
    Unfortunately, if you use Unity the way you're supposed to (in a component-ized manner), you could have a variety of scripts and components attached to a GameObject that all need to be deactivated at the same time.

    The animation system is a mess. Plain and simple.
     
  10. GhostDog

    GhostDog

    Joined:
    Nov 11, 2009
    Posts:
    103
    I agree w Jerrod. Ran into this as well. Traversing every component of a core object (from outside of that core object) and toggling each component is a little silly. Ideally, I'd want to place high level controls at the container level and expect the container to manage the components. Not a tremendous amount of functionality but create/destroy and activate/deactivate seem pretty fundamental. My last project was an MMO where the number of components could reach up to 20+. As Jerrod points out there are times were you are required to release things in a specific order or all at the same time. There needs to be a management layer controlling that. Component patterns 101. I'm assuming that would be placed at the GameObject level in Unity.
     
  11. FenrirWolf

    FenrirWolf

    Joined:
    Feb 10, 2010
    Posts:
    37
    Ah, thanks. I was seeing this problem, but at the time didn't know what was wrong. I was setting the player object inactive upon death that had active blended animations, but whenever it was re-enabled, animations weren't working correctly. I am guessing for the reasons Horsman listed.

    My solution was exactly PirateNinjaAlliance's: I just disabled the collider, rigidbody, mesh renderer, and the script that controlled the object's movement.

    I don't like it, either.
     
  12. Orion

    Orion

    Joined:
    Mar 31, 2008
    Posts:
    261
    This is especially annoying because it's not possible to create a generic solution - you can't just "get" all components on a GameObject! Otherwise one could just iterate through them and disable/enable everything but the animation component.

    I was hoping for something like

    Code (csharp):
    1. public void SetEnabled(bool enable)
    2. {
    3.   foreach(Component component in gameObject.GetComponents())
    4.   {
    5.     if(!(component is Animation))
    6.       component.enabled = enable;
    7.   }
    8. }
    Too bad GetComponents always needs a type :(
     
  13. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Hello, old thread but I found some other weird issues with the Animation system (2011) :

    - animation.Play() doesn't trigger instantly, there is some delay. For example this code :
    Code (csharp):
    1.  
    2.  
    3. animation.Play("bindpose");
    4.  
    5. [ stuff here where you change the character's torso model
    6. bindposes remapping, bones remapping, etc
    7. so you need to set the skeleton animation to a bindpose state]
    8.  
    Well, all the bindpose remapping model changing stuff will happen before the animation "bindpose" has started. Even if it's placed after. It's actually preventing correct bindpose remapping. "Bindpose" animationClip is one frame long, and always have the same transformations. So it should trigger the correct state instantly.

    - GameObject.SampleAnimation() nullify itself outside of the function where it was called. Example :
    Code (csharp):
    1.  
    2. void Start(){
    3.  
    4. animation.Play("Walk");
    5. ChangeTorso("armor2");
    6.  
    7. }
    8.  
    9. void ChangeTorso(string _armorName){
    10. gameObject.SampleAnimation(animation["bindpose"].clip, 0f);
    11.  
    12. [ stuff here where you change the character's torso model
    13. bindposes remapping, bones remapping, etc
    14. so you need to set the skeleton animation to a bindpose state]
    15. }
    16.  
    Here, the SampleAnimation() function will correctly place the animation to "bindpose" state before the model change code block.
    But after that function, the animation will automatically return to "Walk". Wasn't it supposed to stay in "bindpose" state at time 0f ?

    - Animation.Sample() doesn't work like it should. Example this code :
    Code (csharp):
    1.  
    2. animation["Walk"].normalizedTime = 0f;
    3. animation["Walk"].enabled = true;
    4. animation.Sample();
    5.  
    doesn't work. Even if I perform no Play() before its call.
    While :

    Code (csharp):
    1.  
    2. gameObject.SampleAnimation(_modelAnim["Walk"].clip, 0f);
    3.  
    works perfectly.

    Something is really weird inside this class :)
     
    Last edited: Jun 14, 2011
  14. n0mad

    n0mad

    Joined:
    Jan 27, 2009
    Posts:
    3,732
    Ok .... About the Animation.Sample() not working, the documentation here :
    http://unity3d.com/support/documentation/ScriptReference/Animation.Sample.html

    didn't mention that the Sample() function, unlike gameObject.SampleAnimation(), take into account the animationState weight. So as weights are by default set to 0 when the target animation is not playing, we have to manually set the animationState weight to 1f before calling Sample().
    gameObject.SampleAnimation() automatically sets it to 1f.
     
  15. Antitheory

    Antitheory

    Joined:
    Nov 14, 2010
    Posts:
    549
    GetComponents<Component>();
     
  16. Kryptos

    Kryptos

    Joined:
    Mar 30, 2011
    Posts:
    29
    Maybe with coroutine:
    Code (csharp):
    1.  
    2. IEnumerator MyMethod()
    3. {
    4.     animation.Play("bindpose");
    5.     yield return null;
    6.     [ stuff here where you change the character's torso model
    7.    bindposes remapping, bones remapping, etc
    8.    so you need to set the skeleton animation to a bindpose state]
    9. }
     
  17. akotranza

    akotranza

    Joined:
    Sep 7, 2011
    Posts:
    36
    One issue I have is that the built-in "let Unity handle everything" animation methods do not put the AnimationState in a state that distinguishes it from DIY animation manipulation. E.g. if you enable an AnimationState and are manipulating its weight, time, etc. manually, its time is still being advanced in internal Unity code, overriding (adding to, actually) your manually set time value. Luckily, in this one instance, you can keep this from causing a problem by setting Speed to 0.

    But the issue remains: If you are going to expose a low-level "DIY" animation api, then you need to distinguish between automatically updated AnimationStates and manually updated AnimationStates. OR, post the code (or more doc) for the automatic updates so that we can see what internal AnimationState manipulation we need to UNDO in our DIY code in order to get the anticipated result.
     
  18. DDowell

    DDowell

    Joined:
    Feb 8, 2012
    Posts:
    52
    I have recently run into this problem. After testing a few things out and almost passing out from banging my head against the table, I came up with a work-around. It seems that just accessing the animation-object with a call to Animation.IsPlaying(<whatever string here>) in the gameobject's Awake-method is sufficient to prevent the bugs from appearing. This is great news since you can easily make such a workaround script and assign it automatically to all game objects that have an animation component.
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class ForceAnimationInitWorkaround : MonoBehaviour {
    5.  
    6.     // Use this for initialization
    7.     void Awake ()
    8.     {
    9.         if (animation != null) animation.IsPlaying("WHATEVER MAN!");
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void Update () {
    14.    
    15.     }
    16. }
    17.  
     
  19. DDowell

    DDowell

    Joined:
    Feb 8, 2012
    Posts:
    52
    I have filed a report with Unity (Case 537045).
     
  20. DDowell

    DDowell

    Joined:
    Feb 8, 2012
    Posts:
    52
    An interesting quirk is that if the game object with the animation is inactive from the beginning (that is, inactive in the scene view when we enter play mode), the animation will always work. Such inconsistent behavior on core functionality is really not flattering to Unity.
     
  21. huhudage

    huhudage

    Joined:
    Jun 1, 2013
    Posts:
    3
    Does these problems fixed yet?
     
  22. scobi

    scobi

    Unity Technologies

    Joined:
    May 14, 2014
    Posts:
    32