Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it 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. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Current animator state name?

Discussion in 'Animation' started by Rodolfo-Rubens, Jun 9, 2015.

  1. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    Is there no way to get the current animator state name? I don't want to compare if the current state name is name, I want to fetch the state name, to make for example a switch-case, or print the name on the console for debug purposes.
     
    Last edited: Jan 16, 2018
  2. Griffo

    Griffo

    Joined:
    Jul 5, 2011
    Posts:
    652
    I don't think you can, maybe someone will come along and prove me wrong.

    But if you know all the animation names you could loop through them ..

    Code (JavaScript):
    1. if( anim_Animator.GetCurrentAnimatorStateInfo(0).IsName("AnimationName"))
    2.      {
    3.       // Do stuf !!
    4.      }
     
  3. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    2,618
    Make arrays of boolean switches with the same names as your controller states and an array of strings matching the boolean indexes and states names. Loop through them each time a state is switched turning on the corresponding true boolean using
    Code (CSharp):
    1.  
    2. if (stateSwitches[i]) {
    3.      animator.SetBool(stateNames[i], true)
    4. }  else if (!stateSwitches[i]) {
    5.      animator.SetBool(stateNames[i], false)
    6. }
    7.  
    8.  
    and turn all other booleans to false as well as the animator bools. This will keep one state at a time active and you can see which one it is in the Inspector if you make the vars public and pass it to any function needing the current animator state..

    edit.(for spelling and might as well add). The advantage here is that you are looping through booleans and not strings so it is faster with much less overhead and keeps things tidy.
     
    Last edited: Jun 9, 2015
  4. TrickyHandz

    TrickyHandz

    Joined:
    Jul 23, 2010
    Posts:
    194
    To my knowledge there is no way to get the name of the current animator state name at runtime. There is a way to get the information in an editor script using some of the functionality in the UnityEditorInternal namespace, but It doesn't sound like that would serve your purposes. If I'm wrong about that just let me know and I'll see what can be done with editor scripting.
     
    Rodolfo-Rubens likes this.
  5. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    I knew that... It's useful but it's not what I need... :/ Thanks anyway!

    That looks good, I'll take a look at this! I will see if I can make something with this. Thank you very much!

    I saw that somewhere, but I can't compile anything with classes that belongs to the UnityEditor namespace right? Or am I wrong? Thanks for taking your time to reply!
     
  6. TrickyHandz

    TrickyHandz

    Joined:
    Jul 23, 2010
    Posts:
    194
    That is true, you won't be able to use any UnityEditor functionality at runtime, nor build editor code into your final project.
     
  7. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    And here I am again... Waiting for this to be implemented.

    Why can't I access the name of the state directly?!
     
    sama-van likes this.
  8. alexeibabin

    alexeibabin

    Joined:
    Feb 8, 2016
    Posts:
    4
    Remember that post back then from 2012?
    Apparently reading hashes is still the best way.
     
  9. ivangarciafilho

    ivangarciafilho

    Joined:
    Sep 2, 2015
    Posts:
    5
    Nope ! its isn't ... with hundreds of **king threads around, none of them works with hases :

    NONE OF THEM MATCH !!!
    • Animator.StringToHash(AnimationClip.name);
    • Animator.StringToHash("Base."+AnimationClip.name);
    • Animator.StringToHash("HardcodedNameOfAnimationClip");
    • Animator.StringToHash("Base."+"HardcodedNameOfAnimationClip");
    • Animator.StringToHash("HardcodedNameOfState");
    • Animator.StringToHash("Base" + "HardcodedNameOfState");
    • Animator.runtimeAnimatorController(0).GetHashCode();
    • Animator.runtimeAnimatorController(0).IsName(AnimationClip.name);
    • Animator.runtimeAnimatorController(0).IsName("Base." + AnimationClip.name);
    • Animator.runtimeAnimatorController(0).IsName("HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).IsName("Base."+"HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).IsName("HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).IsName("Base."+"HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).IsName("Base."+"HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).shortNameHash(AnimationClip.name);
    • Animator.runtimeAnimatorController(0).shortNameHash("Base." + AnimationClip.name);
    • Animator.runtimeAnimatorController(0).shortNameHash("HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).shortNameHash("Base."+"HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).shortNameHash("HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).shortNameHash("Base."+"HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).shortNameHash("Base."+"HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).fullPathHash(AnimationClip.name);
    • Animator.runtimeAnimatorController(0).fullPathHash("Base." + AnimationClip.name);
    • Animator.runtimeAnimatorController(0).fullPathHash("HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).fullPathHash("Base."+"HardcodedNameOfAnimationClip");
    • Animator.runtimeAnimatorController(0).fullPathHash("HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).fullPathHash("Base."+"HardcodedNameOfAnimationState");
    • Animator.runtimeAnimatorController(0).fullPathHash("Base."+"HardcodedNameOfAnimationState");

    NO WAY THAT HASHES WORKS!!!
    EVEN WITH TRIM() AND TOLOWER() THAT SH*** DON`T WORK!!!
     
    jojoblaze, nonlin and sama-van like this.
  10. emeraldy

    emeraldy

    Joined:
    Nov 26, 2015
    Posts:
    2
    just want to point out that the state name should be "Base Layer.Idle" for example, if you use the default base layer name and the string is case sensitive.
     
    AndyMartin458 likes this.
  11. supremegrandruler

    supremegrandruler

    Joined:
    Jul 19, 2014
    Posts:
    1,098
    So how can one get the current animator state name?
     
  12. sama-van

    sama-van

    Joined:
    Jun 2, 2009
    Posts:
    1,498
    Can't believe this thread is 2 years old and there is still no damn way to access to the every states names?
    Seriously, what could be the excuse you can't make open for ReadOnly in runtime the infos for every States??

    Doing some very base script for Animator reader in runtime, but really cannot access anything.
    Animations class is Editor only.
    Its the same pain as 3-4 years ago to deal with Animator Controller.

    Seriously??????
     
    iLyxa3D, delongli, jojoblaze and 5 others like this.
  13. rsodre

    rsodre

    Joined:
    May 9, 2012
    Posts:
    117
    I love the Animator but want to punch it in the face.
     
  14. hotozi

    hotozi

    Joined:
    Nov 19, 2012
    Posts:
    5
    Best answer would be...
    call it everytime you play the animation... so the var would stay


    var CurrentAnim:String;
    theAnimatorAsVar.play(''ThePlayingAnim''); CurrentAnim=ThePlayingAnim;
     
  15. jonjons

    jonjons

    Joined:
    Oct 13, 2016
    Posts:
    33
    Same problem here:
    void rollFall()
    {
    if (anim.GetCurrentAnimatorStateInfo(0).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(1).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(2).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(3).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(4).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(5).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(6).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(7).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(8).IsTag("Roll") || anim.GetCurrentAnimatorStateInfo(9).IsTag("Roll"))
    {
    fallRoll = true;
    Moving = true;
    }
    }

    If i could just get that stateinfo into an int or float... damm it...
     
  16. jecky111

    jecky111

    Joined:
    Jun 11, 2016
    Posts:
    5
    how about attaching this to the animator controller's layer?

    public class AnimChangeCallback : StateMachineBehaviour {
    // fill in the names of your animations in the inspector!
    public List<string> animationNames;
    // OnStateEnter is called before OnStateEnter is called on any state inside this state machine
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
    string currentAnimName = "unknown";
    foreach (string animationName in animationNames)
    {
    if (stateInfo.IsName(animationName)) { currentAnimName = animationName; }
    }
    Debug.Log("Starting animation:" + currentAnimName);
    }
    }

    you can store the currently played anim name in for ex. a static variable to access it from anywhere
    not an elegant workaround, but a workaround :)
     
  17. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,067
    If you're not going to use transitions, why use animator at all?

    Filling out 40+ fields is not a workaround, just work.
     
  18. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    183
    Instead of comparing the string every time with IsName you could just convert them to the hash once and compare them to the stateInfo.fullPathHash property, i don't know why everyone wants to compare their names/strings, hash is way better, the only reason for the string would maybe be for debug logs etc but otherwise comparing hashes is better than strings.

    Btw to convert a state name to the fullPathHash you have to call Animator.StringToHash with the full path seperated with a .
    Example:
    Animator.StringToHash("Default.MyStateName")
    Animator.StringToHash("Default.MySubStateMachine.MyStateName")
    where "Default" is my starting (default) StateMachine

    Also if i would for some reason want to get the current state name i would just make editor script which converts all my state names to hashes and stores them in a dictionary with the hash as key and the name as value then i would drag the dictionary to the script where i need them and at runtime i would just feed the dictionary with the currentstate info hash to get my state name
     
    Last edited: Oct 2, 2017
  19. alpha-cast

    alpha-cast

    Joined:
    Nov 18, 2017
    Posts:
    2
    I've been banging my head against an animation issue for days which ended up just being user error (bad state name string in the first place). On the long road too that realisation I ended up creating some extension functions that dig into the internals of the Animator class to get the string back from a hash created with Animator.StringToHash(). Turns out there's an internal function to do exactly that.

    Please be aware that this code could break at any time, for instance if the Unity devs refactor this stuff. This is absolutely not cool for production, but I found it a lifesaver for debugging.

    Even though this uses reflection, I've added some runtime compilation magic to make it nearly as fast as a direct call, although I've no idea how optimised the internal functions themselves are. I'd still stress that this really doesn't belong in a production build.

    Code (CSharp):
    1. public static class AnimatorExtensions
    2. {
    3.     /// <summary>Gets an instance method with single argument of type <typeparamref
    4.     /// name="TArg0"/> and return type of <typeparamref name="TReturn"/> from <typeparamref
    5.     /// name="TThis"/> and compiles it into a fast open delegate.</summary>
    6.     /// <typeparam name="TThis">Type of the class owning the instance method.</typeparam>
    7.     /// <typeparam name="TArg0">Type of the single parameter to the instance method to
    8.     /// find.</typeparam>
    9.     /// <typeparam name="TReturn">Type of the return for the method</typeparam>
    10.     /// <param name="methodName">The name of the method the compile.</param>
    11.     /// <returns>The compiled delegate, which should be about as fast as calling the function
    12.     /// directly on the instance.</returns>
    13.     /// <exception cref="ArgumentException">If the method can't be found, or it has an
    14.     /// unexpected return type (the return type must match exactly).</exception>
    15.     /// <see href="https://codeblog.jonskeet.uk/2008/08/09/making-reflection-fly-and-exploring-delegates/"/>
    16.     private static Func<TThis, TArg0, TReturn> BuildFastOpenMemberDelegate<TThis, TArg0, TReturn>(string methodName)
    17.     {
    18.         var method = typeof(TThis).GetMethod(
    19.             methodName,
    20.             BindingFlags.Instance | BindingFlags.NonPublic,
    21.             null,
    22.             CallingConventions.Any,
    23.             new[] { typeof(TArg0) },
    24.             null);
    25.  
    26.         if (method == null)
    27.             throw new ArgumentException("Can't find method " + typeof(TThis).FullName + "." + methodName + "(" + typeof(TArg0).FullName + ")");
    28.         else if (method.ReturnType != typeof(TReturn))
    29.             throw new ArgumentException("Expected " + typeof(TThis).FullName + "." + methodName + "(" + typeof(TArg0).FullName + ") to have return type of string but was " + method.ReturnType.FullName);
    30.         return (Func<TThis, TArg0, TReturn>)Delegate.CreateDelegate(typeof(Func<TThis, TArg0, TReturn>), method);
    31.     }
    32.  
    33.     private static Func<Animator, int, string> _getCurrentStateName;
    34.     /// <summary>[FOR DEBUGGING ONLY] Calls an internal method on <see cref="Animator"/> that
    35.     /// returns the name of the current state for a layer. The internal method could be removed
    36.     /// or refactored at any time, and may not have good performance.</summary>
    37.     /// <param name="animator">The animator to get the current state from.</param>
    38.     /// <param name="layer">The layer to get the current state from.</param>
    39.     /// <returns>The name of the currently running state.</returns>
    40.     public static string GetCurrentStateName(this Animator animator, int layer)
    41.     {
    42.         if (_getCurrentStateName == null)
    43.             _getCurrentStateName = BuildFastOpenMemberDelegate<Animator, int, string>("GetCurrentStateName");
    44.         return _getCurrentStateName(animator, layer);
    45.     }
    46.  
    47.     private static Func<Animator, int, string> _getNextStateName;
    48.     /// <summary>[FOR DEBUGGING ONLY] Calls an internal method on <see cref="Animator"/> that
    49.     /// returns the name of the next state for a layer. The internal method could be removed or
    50.     /// refactored at any time, and may not have good performance.</summary>
    51.     /// <param name="animator">The animator to get the next state from.</param>
    52.     /// <param name="layer">The layer to get the next state from.</param>
    53.     /// <returns>The name of the next running state.</returns>
    54.     public static string GetNextStateName(this Animator animator, int layer)
    55.     {
    56.         if (_getNextStateName == null)
    57.             _getNextStateName = BuildFastOpenMemberDelegate<Animator, int, string>("GetNextStateName");
    58.         return _getNextStateName(animator, layer);
    59.     }
    60.  
    61.  
    62.     private static Func<Animator, int, string> _resolveHash;
    63.     /// <summary>[FOR DEBUGGING ONLY] Calls an internal method on <see cref="Animator"/> that
    64.     /// returns the string used to create a hash from
    65.     /// <see cref="Animator.StringToHash(string)"/>. The internal method could be removed or
    66.     /// refactored at any time, and may not have good performance.</summary>
    67.     /// <param name="animator">The animator to get the string from.</param>
    68.     /// <param name="hash">The hash to get the original string for.</param>
    69.     /// <returns>The name of the string for <paramref name="hash"/>.</returns>
    70.     public static string ResolveHash(this Animator animator, int hash)
    71.     {
    72.         if (_resolveHash == null)
    73.             _resolveHash = BuildFastOpenMemberDelegate<Animator, int, string>("ResolveHash");
    74.         return _resolveHash(animator, hash);
    75.     }
    76. }
     
    canis and samuelchou like this.
  20. kryzodoze

    kryzodoze

    Joined:
    Nov 6, 2013
    Posts:
    16
    There is one solution that I haven't seen mentioned here:

    var layer = 0; // 0 if you only use the Base Layer
    var animator = yourObject.getComponent<Animator>();
    var clipInfo = animator.GetCurrentAnimatorClipInfo(layer);
    AnimationClip clip = clipInfo[0]; // I haven't seen clipInfo be larger than one before
    animator.Play(clip.name, layer, 0);
     
    delongli, nonlin and jister like this.
  21. abella08

    abella08

    Joined:
    Jan 25, 2018
    Posts:
    1
  22. ser_dominic

    ser_dominic

    Joined:
    Feb 11, 2017
    Posts:
    1
  23. o2deprived

    o2deprived

    Joined:
    Jun 17, 2013
    Posts:
    4
  24. theANMATOR2b

    theANMATOR2b

    Joined:
    Jul 12, 2014
    Posts:
    7,781
  25. o2deprived

    o2deprived

    Joined:
    Jun 17, 2013
    Posts:
    4
    Thanks for the suggestion, I think they're having more or less the same problem in that thread. The OP in this thread was looking for a way to read the current state (string name) of the Animator -- and there doesn't seem to be a good way other than the post above, suggesting creating a dictionary of names and state-hashes and then comparing them in a loop -- which does nothing for typo debugging anywhere in the process.

    For my particular purpose, I have an external state-machine that needs to know when the animation is finished prior to switching its state. For example, a door isOpen state mechanism -- I don't want the door state to be isOpen == true until the animation is completed. From my tests, the Animator switches the state the moment a trigger fires, regardless of the length of animation. So if the Animator has states "open" and "closed" and I trigger the transition to "open", the Animator immediately reports back the state is "open", even though the animation transition is not complete. In code, I know this only by checking the equality of Animator.GetCurrentAnimatorStateInfo(0).IsName("open"). I can't simply read the state name from the Animator.

    I've worked around all of this nonsense in my particular situation by limiting and standardizing my state names and using a co-routine to monitor the progress of the animation and once it is complete, call back to the state machine to toggle/change the state of the mechanism. The fact that I cannot read the state directly makes troubleshooting difficult as the OP mentioned. I have to guess what it should be and test if I am correct. And then the fact the state change is immediate puts further requirements on my application, needing to monitor the animation until it is complete. But, depending on application, that may be beneficial to some.
     
    theANMATOR2b likes this.
  26. luislodosm

    luislodosm

    Joined:
    Apr 26, 2016
    Posts:
    21
    A solution:

    1 - Make this script:
    Code (CSharp):
    1. public class AnimationName : MonoBehaviour
    2. {
    3.     public Animator animator;
    4.     public string currentStateName;
    5.  
    6.     public void SetCurrentName(string name)
    7.     {
    8.         currentStateName = name;
    9.     }
    10. }
    2 - Make an Animation Event in the Animation timeline that calls SetCurrentName("name of the animation state").

    Now you have access to the name of the current state animation.
     
    Last edited: Mar 11, 2018
  27. dibdab

    dibdab

    Joined:
    Jul 5, 2011
    Posts:
    649
    yes but
    pmi found best

    animator state behaviours onstateenter/exit calls the reliableest

    because the animation transitions have effect how the events
    faya

    I use this code
    Code (CSharp):
    1.     public string methodIn;
    2.     public string methodEx;
    3.  
    4.     override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    5.     {
    6.         if(methodIn!="")
    7.             animator.gameObject.GetComponent<cWalker> ().Invoke (methodIn, 0f);
    8.     }
    9.  
    10.  
    probably is possible to directly set name
    like this
    Code (CSharp):
    1.     public string statename;
    2.  
    3.     override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    4.     {
    5.         if(statename!="")
    6.             animator.gameObject.GetComponent<cWalker> ().statename = statename;
    7.     }
    8.  
    9.  
     
  28. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,067
    @luislodosm
    I hope you meant "dopesheet" because there's no way I'm re-doing all animated objects to include timelines.

    @dibdab
    Great but this thread is about getting, not setting. And I have no idea what class' methods you're overriding.
     
  29. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    183
    I still don't understand why anyone needs or wants the state name at runtime (unless it's for debugging messages). If you want to know when the state changes then you should use a animator behaviour and override the enter/exit methods instead of comparing state names.
     
  30. LazyKnight

    LazyKnight

    Joined:
    Jul 28, 2017
    Posts:
    7
    Try add "AnimationEvent" and send animation's name by that.
    It's a shame that they didn't provide this feature yet, make some function ugly.
     
  31. BFS_Samuel

    BFS_Samuel

    Joined:
    Jul 24, 2017
    Posts:
    1
    There's a plugin on the asset store that lets you have access to the current state name. It can also be used to trigger events on Animator States with custom parameters, preview animator state in the scene, filter states more easily and much more!

    Here's the link:
    https://www.assetstore.unity3d.com/#!/content/115408
     
  32. karthikeyaneced

    karthikeyaneced

    Joined:
    Dec 1, 2017
    Posts:
    1
    I think this may help to get animator name https://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorClipInfo.html

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class GetCurrentAnimatorClipInfoExample : MonoBehaviour
    4. {
    5.     Animator m_Animator;
    6.     string m_ClipName;
    7.     AnimatorClipInfo[] m_CurrentClipInfo;
    8.  
    9.     float m_CurrentClipLength;
    10.  
    11.     void Start()
    12.     {
    13.         //Get them_Animator, which you attach to the GameObject you intend to animate.
    14.         m_Animator = gameObject.GetComponent<Animator>();
    15.         //Fetch the current Animation clip information for the base layer
    16.         m_CurrentClipInfo = this.m_Animator.GetCurrentAnimatorClipInfo(0);
    17.         //Access the current length of the clip
    18.         m_CurrentClipLength = m_CurrentClipInfo[0].clip.length;
    19.         //Access the Animation clip name
    20.         m_ClipName = m_CurrentClipInfo[0].clip.name;
    21.     }
    22.  
    23.     void OnGUI()
    24.     {
    25.         //Output the current Animation name and length to the screen
    26.         GUI.Label(new Rect(0, 0, 200, 20),  "Clip Name : " + m_ClipName);
    27.         GUI.Label(new Rect(0, 30, 200, 20),  "Clip Length : " + m_CurrentClipLength);
    28.     }
    29. }
     
    Rodolfo-Rubens and dval like this.
  33. jojoblaze

    jojoblaze

    Joined:
    Aug 2, 2010
    Posts:
    15
    This problem seems extremely odd.
    I can't believe there is no an easy way to know in what state the animator is.
    Hashes simply doesn't work. I did a lot (tons!) of experiments with different combination, but without results.

    Obviously hashes are extremely hard to debug because you cannot reverse the hash process.
    Documentation is so poor that I'm thinking seriously to switch to Unreal.
    Example guys, if you cannot give us real documentation, the community need working examples, not stupids HelloWorld.
    I'm trying to create a little fighting engine and the biggest problem I'm facing is to know in what state the animator is.
    This sounds ridicolous, isn't it?

    Scenario: character A need to know if the animator is performing some action (if so, it must wait until animation is finished, because it cannot performe a kick, while it is performing a punch for example).
    In addition, deal with transitions is a real mess.
    I ended up wrapping the animator with a class wich poll every frame the animator, checking the transition and the state, trying to guess if a transition is ended or an animation is playing.

    After playable api release, I tryied to give it another chance, but the lack of documentation about playable is sadly non-existent.

    It's full of people out there wich struggle about this, but nor Unity or community could come up with a reasonable solution.
     
  34. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    In this case I would create animation events inside the animation clips (one in the beginning that tells that the animation X started and another in the end that tells that the animation X finished), of couse, in this case you would need to put animation events in every animation clips that needs to be "tracked".

    But I'm with you in this one... all the animation system seems abandoned by UT, or at least the docs... still, not being able to know the current animator state name is just sad.

    I remember that a while ago I created an IEnumerator method that waits for the current animator state ends to keep executing something inside a coroutine, it may be useful for someone, I will try to find it and I will share it here...
     
    jojoblaze and Griffo like this.
  35. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    183
    Hashes do work, i use them with no problem, maybe you can post a example on how you used them and then we can find out why it doesn't work for you?

    The animator currently doesn't give you a string name of the current state (i guess that the strings for the state names aren't even included in the build, because the internal animator code uses only the hash for performance reasons) but you can ask the animator if it is in a specific state by name, for example you can ask the animator if it is currently in the "kick" state, there is a documentation / example for this, in this example they are checking if the animator is in the jump state:
    https://docs.unity3d.com/ScriptReference/Animator.GetCurrentAnimatorStateInfo.html

    Also if your game logic heavly depends on your animator being in a specific state (for example certain actions are only allowed while being in a specific state) then you could consider to put your logic inside a (animator) state machine behavior which you can add to any state that way instead of checking/pooling the animator all the time and check in which state it is you can write specific logic for each state:
    https://docs.unity3d.com/ScriptReference/StateMachineBehaviour.html
    https://unity3d.com/de/learn/tutorials/modules/beginner/5-pre-order-beta/state-machine-behaviours
     
    Last edited: Jul 8, 2018
    Griffo likes this.
  36. Hanross

    Hanross

    Joined:
    Aug 11, 2018
    Posts:
    9
    anim.GetCurrentAnimatorClipInfo(0)[0].clip.name
    will give u name
     
  37. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    These are used to get the clip name not the animator state name...
     
    jojoblaze likes this.
  38. Hanross

    Hanross

    Joined:
    Aug 11, 2018
    Posts:
    9
    Yes my bad friend I misread clip instead of state o_O
     
  39. SilentSin

    SilentSin

    Joined:
    Jan 3, 2013
    Posts:
    99
    I actually have two plugins on the Asset Store that can address this issue in different ways:
    • Weaver procedurally generates a script containing constants for the state and parameter names of all AnimatorControllers in the project as well as a HashToString method that takes a hash code and uses a switch to determine which string it came from (and a GetName extension method that calls it for AnimatorStateInfo).
    • Animancer does away with AnimatorControllers and lets you just play AnimationClips directly. I find it to be a much better workflow in general and it also gives you full access to the internals of any state at any time. The store page has a full description and a link to the user manual.
    I'm currently working on the v2.0 update for Animancer which adds a bunch of improvements, including the ability to play and blend AnimatorControllers with separate clips and with each other. So your movement script could have a reference to an AnimatorController containing just a movement blend tree, your idle script only needs a reference to a single AnimationClip, each weapon could have an AnimatorController with its attack animations or just an array of clips, and so on.
     
    Last edited: Sep 25, 2018
  40. jojoblaze

    jojoblaze

    Joined:
    Aug 2, 2010
    Posts:
    15
    Yeah, I used the same approach with a while yielding until "a new transition" starts. It works, but it's quite ugly to me. :)
     
    Rodolfo-Rubens likes this.
  41. NicTda

    NicTda

    Joined:
    Jan 11, 2018
    Posts:
    5
    Not sure if that will help Rodolfo-Rubens or anyone, but after struggling with the state name issue for a while, I ended up using the hashes, as per R1PFake's suggestion.
    I'm posting my code for people wanting a concrete example of use.


    First, I've defined a StateMachineBehaviour to redirect my state enter / exit events.
    This behaviour is added on my base layer of the Animator Controller so it catches all states' changes.
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public sealed class StateEventsBehaviour : StateMachineBehaviour
    5. {
    6.     public event Action<int> OnEnterState;
    7.     public event Action<int> OnExitState;
    8.  
    9.     public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    10.     {
    11.         // Using the shortNameHash to avoid dealing with layers. Can use nameHash instead.
    12.         OnEnterState.SafeInvoke(stateInfo.shortNameHash);
    13.     }
    14.  
    15.     public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    16.     {
    17.         OnExitState.SafeInvoke(stateInfo.shortNameHash);
    18.     }
    19. }
    I'm then using a MonoBehaviour so I can listen to the events I want (by state name) in my animator.
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public sealed class FSMAnimator : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     private Animator animator = null;
    9.  
    10.     private sealed class StateCallbacks
    11.     {
    12.         public int stateHash = 0;
    13.         public Action callbackEnter = null;
    14.         public Action callbackExit = null;
    15.     }
    16.  
    17.     private int stateRequest = 0;
    18.     private StateCallbacks currentState = null;
    19.     private Dictionary<int, StateCallbacks> registeredStates = new Dictionary<int, StateCallbacks>();
    20.  
    21.     public void Start()
    22.     {
    23.         // Assuming the animator is assigned in the inspector
    24.         var stateBehaviour = animator.GetBehaviour<StateEventsBehaviour>();
    25.         stateBehaviour.OnEnterState += OnEnterState;
    26.         stateBehaviour.OnExitState += OnExitState;
    27.     }
    28.  
    29.     public void RegisterStateCallback(string stateName, Action onEnter, Action onExit)
    30.     {
    31.         // Using the state names to register, but using the hash internally
    32.         int shortNameHash = Animator.StringToHash(stateName);
    33.         if (registeredStates.ContainsKey(shortNameHash) == false)
    34.         {
    35.             registeredStates.Add(shortNameHash, new StateCallbacks()
    36.             {
    37.                 stateHash = shortNameHash,
    38.                 callbackEnter = onEnter,
    39.                 callbackExit = onExit
    40.             });
    41.         }
    42.     }
    43.  
    44.     public void Trigger(string trigger)
    45.     {
    46.         animator.SetTrigger(trigger);
    47.     }
    48.  
    49.     private void OnEnterState(int stateNameHash)
    50.     {
    51.         if(registeredStates.ContainsKey(stateNameHash) == true)
    52.         {
    53.             if (currentState != null)
    54.             {
    55.                 // This enforces the order of which the states are exiting / entering
    56.                 // It helped when transitions are used to avoid the State1Enter, State2Enter, State1Exit scenario
    57.                 stateRequest = stateNameHash;
    58.             }
    59.             else
    60.             {
    61.                 EnterState(stateNameHash);
    62.             }
    63.         }
    64.     }
    65.  
    66.     private void OnExitState(int stateNameHash)
    67.     {
    68.         if(currentState != null && currentState.stateHash == stateNameHash)
    69.         {
    70.             // Copying the callback just in case the callbackExit triggers a OnEnterState
    71.             // This would lead to nulling the new current state instead of the one we want
    72.             var callbackExit = currentState.callbackExit;
    73.             currentState = null;
    74.             if(callbackExit != null)
    75.             {
    76.                 callbackExit.Invoke();
    77.             }
    78.            
    79.             // Check if we have a state request
    80.             if(stateRequest != 0)
    81.             {
    82.                 EnterState(stateRequest);
    83.                 stateRequest = 0;
    84.             }
    85.         }
    86.     }
    87.  
    88.     private void EnterState(int stateNameHash)
    89.     {
    90.         currentState = registeredStates[stateNameHash];
    91.         if(currentState.callbackEnter != null)
    92.         {
    93.             currentState.callbackEnter.Invoke();
    94.         }
    95.     }
    96. }
    And here's a simple example on how I use it, assuming that my scene is comprised of an object called "MyFSMAnimator", with FSMAnimator attached. The animator controller has two states, Idle and Walk, which are linked with transitions triggered by "Next".
    Code (CSharp):
    1. using System;
    2.  
    3. public sealed class TestClass
    4. {
    5.     // List of the animator's triggers
    6.     private const string k_triggerNext = "Next";
    7.  
    8.     // List of the animator's states
    9.     private const string k_stateIdle = "Idle";
    10.     private const string k_stateWalk = "Walk";
    11.  
    12.     private FSMAnimator fsm = null;
    13.  
    14.     public void Initialise()
    15.     {
    16.         fsm = GameObject.Find("MyFSMAnimator").GetComponent<FSMAnimator>();
    17.         fsm.RegisterStateCallback(k_stateIdle, EnterStateIdling, ExitStateIdling);
    18.         fsm.RegisterStateCallback(k_stateCatwalk, EnterStateWalk, null);
    19.         fsm.Trigger(k_triggerNext);
    20.     }
    21.  
    22.     private void EnterStateIdling()
    23.     {
    24.         Debug.LogError("EnterStateIdling");
    25.         fsm.Trigger(k_triggerNext);
    26.     }
    27.  
    28.     private void ExitStateIdling()
    29.     {
    30.         Debug.LogError("ExitStateIdling");
    31.     }
    32.  
    33.     private void EnterStateWalk()
    34.     {
    35.         Debug.LogError("EnterStateWalk");
    36.         fsm.Trigger(k_triggerNext);
    37.     }
    38. }
    Hope this helps!
     
    Last edited: Oct 24, 2018
  42. SilentSin

    SilentSin

    Joined:
    Jan 3, 2013
    Posts:
    99
    That looks pretty similar to the setup I was using before I made Animancer.

    I also had an editor-only method to add the behaviour to the layers automatically so you don't need to do it manually all the time:
    Code (CSharp):
    1. /// <summary>
    2. /// If the specified behaviour type isn't already on each layer, it is added.
    3. /// Returns the last one added.
    4. /// </summary>
    5. public static T GetOrAddBehaviour<T>(this RuntimeAnimatorController controller) where T : StateMachineBehaviour
    6. {
    7.     if (controller == null)
    8.         return null;
    9.  
    10.     T addedBehaviour = null;
    11.  
    12.     foreach (var layer in (controller as UnityEditor.Animations.AnimatorController).layers)
    13.     {
    14.         foreach (var behaviour in layer.stateMachine.behaviours)
    15.         {
    16.             if (behaviour is T)
    17.                 goto NextMachine;
    18.         }
    19.  
    20.         addedBehaviour = layer.stateMachine.AddStateMachineBehaviour<T>();
    21.  
    22.         NextMachine:;
    23.     }
    24.  
    25.     return addedBehaviour;
    26. }
     
  43. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    368
    It is utter insanity that you can't simply get the current state from the animator.

    It's just ....... it's the sort of thing that can only happen with Unity.

    It's all of

    - utterly embarrassing

    - hilarious

    - an absolutely typical example of the shambles that is Unity.

    It's just .. funny. You couldn't make it up. So, so embarrassing.
     
  44. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    2,618
    Simply use the function and vars I posted a long time ago above using List<> or even faster builtin array state names and correspondingly indexed bools. You pass the string of the state name in you are transitioning to and loop through the list turning on only that state and turning off every other bool. You can easily control and track via strings which animation is currently triggered. The other long bloviations disguised as answers are enterprise coders trying to apply their paradigm to the Unity game engine.. My solution is a game engine programmer solving a problem whilst keeping framerates high in the least amount of lines of code possible. Where is your headspace at to post such a rant as you have? Unity gives you toolsets to break out of the box if you observe their functionality in overall context. In that context your mockery is possibly a shambles.
     
    SilentSin likes this.
  45. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    10
    I think I have a solution to this. We can actually add a behaviour script to individual state in the Animator. And then in the script, we simply add a public string variable, then we can assign the name to that variable in the inspector. Note that the script has to inherit StateMachineBehaviour, we want to use OnStateEnter method here. Then add a public static string variable to another script. When OnStateEnter method is called, assign the name to that public static string variable. This way, we are able to check the name of current state.