Search Unity

How To Find Animation Clip Length

Discussion in 'Animation' started by johnnieZombie, Apr 11, 2017.

Thread Status:
Not open for further replies.
  1. johnnieZombie

    johnnieZombie

    Joined:
    Oct 23, 2012
    Posts:
    27
    I'm using multiple Animator Controllers (one for each enemy model) with four states: Idle, Attacking, Damage, Dead

    I need to find the length of Attacking, Damage, and Dead animations on the current enemy so I can use a timed delay for other actions.

    I understand how to get Animation time but in this case I have the Animator/Controller on the models, not an Animation component.

    Thanks in advance.
     
    sveinnoli and hopetolive like this.
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    anim.GetCurrentAnimatorStateInfo(layer).length gives you the length of the current animation that's playing. There is no way to get any information whatsoever about states that are not currently playing without generating that information and adding it to the gameobject before you start playing.
     
    Apeles, MrFMS, MikaFika and 4 others like this.
  3. johnnieZombie

    johnnieZombie

    Joined:
    Oct 23, 2012
    Posts:
    27
    Thanks Baste.

    I was actually able to find a solution. Here's the code I created to assign the value to a float:



    Code (CSharp):
    1.  
    2.  
    3.     public float attackTime;
    4.     public float damageTime;
    5.     public float deathTime;
    6.     public float idleTime;
    7.  
    8.     private Animator anim;
    9.     private AnimationClip clip;
    10.  
    11.     // Use this for initialization
    12.     void Start () {
    13.         anim = GetComponent<Animator>();
    14.         if(anim == null)
    15.         {
    16.             Debug.Log("Error: Did not find anim!");
    17.         } else
    18.         {
    19.             //Debug.Log("Got anim");
    20.         }
    21.  
    22.    UpdateAnimClipTimes();
    23.     }
    24.     public void UpdateAnimClipTimes()
    25.     {
    26.         AnimationClip[] clips = anim.runtimeAnimatorController.animationClips;
    27.         foreach(AnimationClip clip in clips)
    28.         {
    29.             switch(clip.name)
    30.             {
    31.                 case "Attacking":
    32.                     attackTime = clip.length;
    33.                     break;
    34.                 case "Damage":
    35.                     damageTime = clip.length;
    36.                     break;
    37.                 case "Dead":
    38.                     deathTime = clip.length;
    39.                     break;
    40.                 case "Idle":
    41.                     idleTime = clip.length;
    42.                     break;
    43.             }
    44.         }
    45.     }
     
    Last edited: Apr 11, 2017
    raymondy1, Gernata, Monocles and 45 others like this.
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    Would you look at that, I was completely wrong!
     
  5. johnnieZombie

    johnnieZombie

    Joined:
    Oct 23, 2012
    Posts:
    27
    Took me a little bit. I just learned to use any sort of mecanim or 3D modeling last week so it's all new to me. Regardless, I really appreciate you trying to help. It's frustrating to post a question here and not get anything.
     
    DaemonBreed likes this.
  6. KiddUniverse

    KiddUniverse

    Joined:
    Oct 13, 2016
    Posts:
    115
    if you're going for a timed delay, doesn't this method only work if each animation is set to a speed of 1?

    edit: i'm guessing you can reference the animation speed as well as the length and just multiply the result together to get your time delay?
     
    Last edited: Feb 19, 2019
  7. Zappppp

    Zappppp

    Joined:
    Dec 5, 2018
    Posts:
    9
    You can also manually do it by dividing the number of frames by the framerate, like 180/60 = 3 seconds
     
    ezed1, no00ob and ElegantUniverse like this.
  8. Rafaelski

    Rafaelski

    Joined:
    May 1, 2019
    Posts:
    12
    THANKS MAN! Smart solution. It helped me a lot
     
  9. MWellman

    MWellman

    Joined:
    May 27, 2017
    Posts:
    15
    Exporting from Maya, all my animations are named 'Take 001'

    Otherwise this could have been a good solution to my problem
     
  10. JustStezi

    JustStezi

    Joined:
    Jun 23, 2018
    Posts:
    25
    Is there a possiblty to do this to when you are using AnimatorOverrideController? Becaues with these the Name changes and the above code dosent work.

    All I found was this code:
    Code (CSharp):
    1.         AnimationClip[] clips = anim.runtimeAnimatorController.animationClips;
    2.         //17 is the current number of the attack animation, this can be seen in an AOC
    3.         attackAnimationClipLenght = clips[attackAnimationClipNumberInAOC].length;
    Is there a better option I just cant find?
     
  11. lnwhitling

    lnwhitling

    Joined:
    Nov 17, 2018
    Posts:
    1
    Just a heads up with this - I was also really struggling with the AnimatorOverrideController scenario:

    My use-case was that I was setting a trigger for an animation, and then wanting to know when the animation was complete. But of course, just because I'd set the trigger did not mean that it was the current (or even next) Animator state info - these will only get set at some point in the future.

    However, I noticed that you can actually tag your animations in the base animator controller - and these tags persist onto the inherited animations. So my code was:

    Code (CSharp):
    1. private bool AnimationComplete(string theTagIPutOnTheBaseAnimation)
    2.     {
    3.         var state = Animator.GetCurrentAnimatorStateInfo(0);
    4.  
    5.         return state.IsTag(theTagIPutOnTheBaseAnimation) && state.normalizedTime >= 1;
    6.     }
    EDIT: by tag - I mean, open the base animator controller in the editor view, then click on a state, and you'll see a "tag" field for it in the inspector.
     
    Last edited: Aug 13, 2020
  12. andrebm

    andrebm

    Joined:
    Oct 17, 2020
    Posts:
    1
    you can rename your animation clips, just click on them -> go to the inspector -> top right corner -> edit (dont forget to tap Enter once you renamed the clip and click save after that)
     
    MWellman likes this.
  13. ryanmillerca

    ryanmillerca

    Joined:
    Aug 12, 2012
    Posts:
    143
    I strongly suggest you try using Maya's Game Exporter for files with animation. It makes managing clip names & multiple clips in one file a lot easier.
     
    MWellman likes this.
  14. yektasarioglu

    yektasarioglu

    Joined:
    Dec 29, 2018
    Posts:
    3
    I used it at an animation event and it did give different values each time. I'm not sure if it's working as you explained. On the other hand, johnnieZombie's solution is more robust and working well.
     
  15. vuslystyi

    vuslystyi

    Joined:
    Aug 26, 2020
    Posts:
    5
    Found solution for the case when we are using multiple animator controllers (1 - base animator and many which override base animator):

    Code (CSharp):
    1.  
    2.         public Animator animator;
    3.         private AnimationClips<HeroAnimationType> _animationClips;
    4.  
    5.         private void Awake()
    6.         {
    7.             _animationClips = new AnimationClips<HeroAnimationType>(animator.runtimeAnimatorController);
    8.  
    9.             AnimationClip idleAnimationClip = _animationClips.GetAnimationClip(HeroAnimationType.Idle);
    10.         }
    11.  
    Your enums must be named exactly like animations used in the base animator controller. Animations assigned to overridden animator controllers could have any name.
    Strongly recommends Rename animations used in base animator instead of creating enums with the current animation's name. For example, if you have an animation with the name "idle-001" rename it to "Idle".

    Code (CSharp):
    1.  
    2.     public enum HeroAnimationType
    3.     {
    4.         Idle,
    5.         Attacking,
    6.         Damage,
    7.         Dead
    8.     }
    9.  
    And general class which can get animation clip by enum:

    Code (CSharp):
    1.  
    2.     public class AnimationClips<TClipType> where TClipType : struct, Enum
    3.     {
    4.         private readonly RuntimeAnimatorController _runtimeAnimController;
    5.  
    6.         private Dictionary<TClipType, AnimationClip> _animationClips;
    7.  
    8.         public AnimationClips(RuntimeAnimatorController runtimeAnimController)
    9.         {
    10.             _runtimeAnimController = runtimeAnimController;
    11.  
    12.             InitializeAnimationClips();
    13.         }
    14.  
    15.         public AnimationClip GetAnimationClip(TClipType clipType)
    16.         {
    17.             if (ContainClip(clipType))
    18.             {
    19.                 return _animationClips[clipType];
    20.             }
    21.  
    22.             return null;
    23.         }
    24.  
    25.         private void InitializeAnimationClips()
    26.         {
    27.             _animationClips = new Dictionary<TClipType, AnimationClip>();
    28.          
    29.             if (_runtimeAnimController is AnimatorOverrideController)
    30.             {
    31.                 InitializeFromOverridenController();
    32.             }
    33.             else
    34.             {
    35.                 InitializeFromBaseController();
    36.             }
    37.         }
    38.  
    39.         private void InitializeFromBaseController()
    40.         {
    41.             AnimationClip[] clips = _runtimeAnimController.animationClips;
    42.  
    43.             foreach (AnimationClip clip in clips)
    44.             {
    45.                 if (Enum.TryParse(clip.name, out TClipType type))
    46.                 {
    47.                     if (_animationClips.ContainsKey(type))
    48.                     {
    49.                         continue;
    50.                     }
    51.                  
    52.                     _animationClips.Add(type, clip);
    53.                 }
    54.             }
    55.         }
    56.  
    57.         private void InitializeFromOverridenController()
    58.         {
    59.             AnimatorOverrideController overrideController = _runtimeAnimController as AnimatorOverrideController;
    60.             var overrides = new List<KeyValuePair<AnimationClip, AnimationClip>>();
    61.          
    62.             overrideController.GetOverrides(overrides);
    63.  
    64.             foreach (var overrideClip in overrides)
    65.             {
    66.                 if (Enum.TryParse(overrideClip.Key.name, out TClipType type))
    67.                 {
    68.                     if (_animationClips.ContainsKey(type))
    69.                     {
    70.                         continue;
    71.                     }
    72.                  
    73.                     _animationClips.Add(type, overrideClip.Value);
    74.                 }
    75.             }
    76.         }
    77.     }
    78.  
     
  16. KalOBrien

    KalOBrien

    Administrator

    Joined:
    Apr 20, 2021
    Posts:
    89
    Going to lock this now as it has multiple solutions!

    Good thread folks.
     
    harlandpj likes this.
Thread Status:
Not open for further replies.