Search Unity

Current animator state name?

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

  1. jhughes2112

    jhughes2112

    Joined:
    Nov 20, 2014
    Posts:
    178
    Hey all. Waaaay up near the top was a runtime solution using reflection by @alpha-cast (which is awesome, thanks!). If you want to just collect all the state names, whether full or short, and do so in the editor, here's a quick inspector that shows you how to do it. Just drag the animator controller onto the inspector field and it'll collect all the states in your whole animator. What you do with it from this point on is up to you. (Obviously, change the name of MyObjType to a script you actually have somewhere... doesn't matter what.)

    Hope this helps someone!

    JH

    Code (CSharp):
    1. [CustomEditor(typeof(MyObjType))]
    2. class AnimInspector : Editor
    3. {
    4.     public UnityEditor.Animations.AnimatorController controller;
    5.    
    6.     private HashSet<UnityEditor.Animations.AnimatorStateMachine> statesVisited = new HashSet<UnityEditor.Animations.AnimatorStateMachine>();
    7.     private HashSet<string> stateNames = new HashSet<string>();
    8.  
    9.     private void RecurseStates(UnityEditor.Animations.AnimatorStateMachine asm)
    10.     {
    11.         statesVisited.Add(asm);
    12.  
    13.         foreach (var states in asm.states)  // collect state names, ignore collisions
    14.         {
    15.             stateNames.Add(states.state.name);
    16.         }
    17.         foreach (var childState in asm.stateMachines)
    18.         {
    19.             if (statesVisited.Contains(childState.stateMachine)==false)
    20.                 RecurseStates(childState.stateMachine);
    21.         }
    22.     }
    23.  
    24.     public override void OnInspectorGUI()
    25.     {
    26.         base.OnInspectorGUI();
    27.         UnityEditor.Animations.AnimatorController newController = (UnityEditor.Animations.AnimatorController)EditorGUILayout.ObjectField(new GUIContent("Animator Controller"), controller, typeof(UnityEditor.Animations.AnimatorController), false);
    28.         if (controller != newController)
    29.         {
    30.             controller = newController;
    31.  
    32.             // reset and retraverse all states
    33.             statesVisited.Clear();
    34.             stateNames.Clear();
    35.             if (controller!=null)
    36.             {
    37.                 foreach (var layer in controller.layers)
    38.                 {
    39.                     RecurseStates(layer.stateMachine);
    40.                 }
    41.             }
    42.         }
    43.  
    44.         foreach (string stateName in stateNames)
    45.         {
    46.             EditorGUILayout.LabelField(stateName);
    47.         }
    48.     }
    49.  
    50. }
    51.  
     
    MikeAtOO and andreyefimov2010 like this.
  2. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Nice editor script . However your recommendation to use a reflection based method as though it is the cat's meow is not a good recommendation. Game devs should always have performance in mind and throw out their MSDN practices and work with the engine which marshalls C#..a scripting language.. into C++ at compile time. Reflection is ssslllooowwwww. https://jacksondunstan.com/articles/2972
     
    stonstad and Unplug like this.
  3. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    It's an editor script. Its runtime performance doesn't matter because it doesn't exist at runtime, that's why its called an editor script. And if you actually read the script, it's not even using any reflection.

    It seems like a rather clunky solution to me, but an editor script is exactly the place where inefficient operations like this and reflection should be performed.
     
    Alverik and Alic like this.
  4. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    Im not 100% sure what you mean with this comment, but Unity doesn't compile C# into C++ at compile time unless you use IL2CPP (for example for mobile) but a "normal" desktop game is compiled as C# (IL) dll and the engine code itself (which is C++) calls the C# code at runtime.
     
  5. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    That is why it was said good editor script but pointing to a runtime solution was not optimal performance wise. I would use this script to gather the stateNames into a string builtin array and creating a stateBool matching bool builtin array. By passing the name of the next state into a loop and seeking the match of either bool or string as is suited to your triggering method you have only one current string stateName which stateNames index matches the index of the bool which is true and the loop turns all others false. Superfast and bulletproof.
     
  6. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Thanks for clarifying the jargon. I admit. I am not a jargon guy. I am a programmer/technical artist/procedural animator. More like the backyard hotrod mechanic whose bondoed jalopy will outperform the factory trained mechanics every time in the quarter mile. .. Fact remains..C# is not the final leg of the journey before display..so whatever is in C# to my sensibilities is still scripting the C++ when all is said and done per frame. The less of this you are pipelining the better the performance.
     
  7. FireGreeks

    FireGreeks

    Joined:
    Jan 14, 2017
    Posts:
    5
    For those still searching for a solution years after this, after some hours of thinking, I came up with this code/script :

    Code (CSharp):
    1. static public T GetInDictionnary<T>(List<T> list, System.Func<T, bool> method)
    2.     {
    3.         T toReturn = default(T);
    4.         foreach (T t in list)
    5.         {
    6.             if (method(t))
    7.                 toReturn = t;
    8.         }
    9.         return toReturn;
    10.     }
    NOTE: This code can also be used for any List or Dictionary with any key type...

    List<T> list
    is a list with all the names of the
    AnimationStates 
    (I know this work but its just copy pasting, takes a couple of minutes). This function is called like this :

    Code (CSharp):
    1. GetInDictionnary<string>(ListofAllStates,(name) => {return animatorStateInfo.IsName(name); });
    Using the lambda expression, you check through every existing state if the name of the state is equal to the current
    AnimationState
    and then returns
    name
    if true.

    This is a pretty good workaround, just needs a bit of copy-pasting... Unity is great but come on, it just takes one line of code to implement this. There must be a reason they didn't do it. But, here you go, you're welcome...
     
  8. wechat_os_Qy04nNLpF6XvuRptWsvltyzug

    wechat_os_Qy04nNLpF6XvuRptWsvltyzug

    Joined:
    Feb 12, 2019
    Posts:
    1
    to 2d project,here is a simple but not universal way:
    animator takes effect by changing the spriterenderer.sprite (on the same game object).the name of sprite is like “xxx_01”,"xxx" is texture name.so if your state names just equal the names of texture,it could be get while game running.
    Code (CSharp):
    1. public string get_anime_name_now()
    2.     {
    3.         string sp=gameObject.GetComponent<SpriteRenderer>().sprite.name;
    4.         string[] subs=sp.Split('_');
    5.         return sp.Substring(0,sp.Length-subs[subs.Length-1].Length-1);
    6.     }
     
  9. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    How to use this code?

    Missing some specific apply example...

    How to replace [ListofAllStates]?
     
  10. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    How to use actually this script? I got errors

    The type or namespace name 'HashSet<>' could not be found
     
  11. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    You need the proper using, I think it's System.Collections.Generic for HashSet<>.

    Also there is no need to continue the loop if you already found the item, just return inside the if instead of setting a variable, or at least add a break.

    Or you can just add a using for System.Linq and use the FirstOrDefault extension method, it does the same thing.
     
  12. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    So how to use this script? What the script name should be?
     
  13. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    So it just shows animator's states name, but when I play game, it disappears. And still how to know what state is currently playing?
     
  14. dibdab

    dibdab

    Joined:
    Jul 5, 2011
    Posts:
    976
    I was under the impression that
    animator.GetCurrentAnimatorStateInfo (0).IsName (_stateN) has an impact on performance just like GetComponent<>()

    made a test with 100 animated characters and I don't see any change in the stats
    if the script is On or Off
    Code (CSharp):
    1. void Update () {
    2.    if (isOn) {
    3.             if (animator.GetCurrentAnimatorStateInfo (0).IsName ("idle")) isIdle = true;
    4. }}
    looks like as if the info is already there and makes no difference if you access it or not.
    is it true?
    (though string compare probably takes some time)
     
    Last edited: Aug 20, 2019
  15. GuardHei

    GuardHei

    Joined:
    Feb 10, 2018
    Posts:
    89
    It is the name of the animator state, not the clip
     
  16. alti

    alti

    Joined:
    Jan 8, 2014
    Posts:
    94
    It will at least give you the clue you otherwise need. Otherwise you can make life super simple and just name the animation and the clip the same thing.
     
  17. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    660
    Everyone has their own implementation... My requirements are as follows:
    • Be performant. Minimal run-time cost (i.e. no SendMessage, no runtime reflection, no GetSomething() invocations)
    • Allow me to use strings or hashes based on my performance need
    • Tell me if missed declaration of a state during editor playback, but not runtime
    Usage:
    Code (CSharp):
    1. private void Start()
    2. {
    3.    _Animator = GetComponent<Animator>();
    4.    var listeners = Animator.GetBehaviours<StateMachineBehaviorListener>();
    5.    foreach (StateMachineBehaviorListener listener in listeners)
    6.    {
    7.       listener.OnStateEnterEvent += OnStateEnter;
    8.       listener.OnStateExitEvent += OnStateExit;
    9.    }
    10. }
    11.  
    12. private void OnStateEnter(int stateHash, string stateName)
    13. {
    14.    Debug.Log("ENTER " + stateName);
    15. }
    16.  
    17. private void OnStateExit(int stateHash, string stateName)
    18. {
    19.    Debug.Log("EXIT " + stateName);
    20. }
    Configuration: Add StateMachineListener.cs as an animation behavior and expose states by name. A single class implementation may be assigned to multiple states.

    StateMachineListener.cs...
    Code (CSharp):
    1. static StateMachineBehaviorListener()
    2. {
    3.    AddState("Grounded");
    4.    AddState("Pickup");
    5.    AddState("Horizontal Chop");
    6. }

    Gist w/ files: https://gist.github.com/stonstad/7bdd805d52f43d6880cc073a48757aa9

    The reflection code executes to warn if a state is missing only during Editor playback. Accolades to @alpha-cast.

    If you see an optimization or bug let me know and I'll update the gist. I understand there are so many ways to handle this but the best way is for the Unity team to listen and make APIs more developer friendly.

    @Unity dev team -- adding a collection with hashed look-up for a state name is never going to be a deal breaker in terms of memory usage or performance. It's on you to make humane APIs for your developers, and judging by the size of this thread and others, you dropped the ball here. Please fix it.
     
    Last edited: Nov 10, 2019
    Alic, Giantbean, JoeStrout and 2 others like this.
  18. Mathius123

    Mathius123

    Joined:
    May 21, 2018
    Posts:
    14
    Came here simply to post that this asset works like a charm. It places an SO under the animator controller of the game object that contains the Animator you attached the Animator Handler script component to and then you can simply call:

    animator.GetCurrentStateName(layerIndex) and it returns the actual animation state name as a string. Perfect!
     
    andreiagmu likes this.
  19. neoRiley

    neoRiley

    Joined:
    Dec 12, 2008
    Posts:
    162
    Worked just fine for my setup - thanks much
     
  20. UsefulYdyot

    UsefulYdyot

    Joined:
    Sep 20, 2014
    Posts:
    3
    This should do the job in C#; it works for me. Yet, it is not too good in matters of performance and I would only use it for debugging.

    Code (CSharp):
    1.  
    2. static public string GetCurrentName(Animator animator, int layer=0)
    3. {
    4.         AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(layer);
    5.        
    6.         foreach(AnimationClip clip in animator.runtimeAnimatorController.animationClips)
    7.         {
    8.                 if(info.IsName(clip.name))
    9.                         return clip.name;
    10.         }
    11.        
    12.         return null;
    13. }
    14.  
    You could place that method in some util class called AnimationUtil.

    I also stumbled upon this issue and I think it should be part of the default API, since it is vital for debugging animations.
    But this is up to the Unity devs. And maybe it is me, who has just missed some already existing API method like that.
     
  21. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    That solution is very inefficient and will only work if all your state names exactly match their clip names (and you aren't using blend trees).
     
  22. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    this stuff is still a nightmare. there is no way to "get" the current hash of what's playing you can only "get" it by name (A STRING) which is worse for performance. You can only "play" with animiator.stringtohash and it seems to have no other use...
     
    sama-van likes this.
  23. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,570
    animator.GetCurrentAnimatorStateInfo(0).shortNameHash

    I mean, Animator Controllers are definitely a nightmare and I don't recommend using them, but they can at least do that much.
     
  24. Ziron999

    Ziron999

    Joined:
    Jan 22, 2014
    Posts:
    282
    ya i figured it out...still need to figure out a performance based way to handle this via multiplayer though.
    you have to re-decode hashes when sending a byte and it does not seem worth sending a int instead of a byte just because of this...
     
    Last edited: Jul 17, 2020
  25. revanaii

    revanaii

    Joined:
    Jun 13, 2017
    Posts:
    11
    Spinoza0 likes this.
  26. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
  27. Giantbean

    Giantbean

    Joined:
    Dec 13, 2012
    Posts:
    144
    First, Why is the state so important to git if the clip name is easily usable? Can you not use a clip name if its nested in a blend tree state? Is the state vs the clip name something that would be needed at run time for some specific use other than debugging? It seems that the state could be good for game actions and the clip name would be good enough for debugging especially if you have a good naming convention for your clips so you can keep the states names aligned. Even if more than one state refers to the same clip couldn't that still be used in debugging and the hash for the actual game mechanic? Even if I have states idle and idle 0 as two states with the same clip called standing_idle and I debug and see GetCurrentAnimatorClipInfo(0)[0}.clip.name return the clip name standing_idle twice is that not useful? I'm just asking out of curiosity as some one who wants to see a state API added from Unity but is not holding out any hope of it actually happening. Multiple options in this thread that can get around the limitation but it would still be nice if the limitation didn't exist in the first place.

    Second, Even if your using clips instead of states why can't you get anything but the first clip and the entire length of a sub-state machine? If I have an idle that leads into a pick up animation clip each 5 seconds long and I try to debug with a getCurrentAnimationClip info it doesn't tell me the current clip it just tells me the idle clip and if I use clip.length I don't get the length of one clip (5) I get the length (10) of all clips in the sub state combined. ...Although thinking as I wrote I may not be triggering the debug log at the right point as I enumerate through the clips. So my second point may just be user error even if I have seen others complaining of the same issue.

    update: I also think my first set of questions glazed over animation layers which could be an issue.
     
    Last edited: Jul 19, 2021
  28. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    The name is not needed for anything if the animator is used properly and there are workarounds to get the name if you need it for debug logs. I don't even know why this thread is still active, there are already multiple working solutions posted on the first page.
     
  29. Giantbean

    Giantbean

    Joined:
    Dec 13, 2012
    Posts:
    144
    Its still active because comparing isName or a dictionary to bool switch requires a lot of writing out state name strings in code especially when you have a growing library of animations and states that you just want to debug. For production you can use hash but for debug the solutions all feel like a waste of time so people still want a better solution and an API script seems like it would be simple enough for unity to implement; since however they aren't going to, new programmers like me show up and still feel a better debugging solution should be available and documented.

    Edit: I will note that the array to clip name is fine if you name the clips and states well. The trouble is its still giving you a clip name and not a state as the OP and others have asked for. Why people need the state I'm not sure but they do so rather then say its never needed just because I don't need it I think its good to see if it can be easily retrieved or if the solution is in rethinking the architecture to use clip names to get the same debugging result and hashes for the same game play result.
     
    Last edited: Jul 19, 2021
    Superjayjay likes this.
  30. alti

    alti

    Joined:
    Jan 8, 2014
    Posts:
    94
    Getting the state name is impossible.

    But all is not lost, developer, you're savvy. You know there are workarounds.

    Code (CSharp):
    1.  
    2.     AnimationClip[] clips = anim.runtimeAnimatorController.animationClips; //this gets all your clips in your animator. ALL.
    3.     for (int i = 0; i < clips.Length; i++){
    4.         print(clips[i].name); //you should create a list to store all of these.
    5.     }
    6.     Animator _aci = GetComponent<Animator>().GetCurrentAnimatorClipInfo(0);
    7.     List<theClassYouMadeForYourList> theListYouMade = new List <theClassYouMadeForYourList>(); //make sure you make a class for your list "theClassYouMadeForYourList"
    8.     for(int i = 0; i < theListYouMade.Count; i++){
    9.         if(theListYouMade[i] == _aci[0].clip.name){ //is the list item equal to the current clip name? Then do something.
    10.             print("doing something");
    11.             break;
    12.         }
    13.     }
    I haven't tested this, but it should work. ;)
     
  31. kloot

    kloot

    Joined:
    Mar 14, 2018
    Posts:
    78
    I love how getting the name of the currently active clip is still not doable in 2021...

    Note that solutions based on Animator.GetCurrentAnimatorClipInfo() assumes the name of the state is the same as the name of the clip, which isn't necessarily the case.
     
  32. lacas8282

    lacas8282

    Joined:
    Apr 25, 2015
    Posts:
    139
    How to get the current animator transition name and/or time?

    I want this:

    Grounded->GroundedWithGun transition name (between the two states)

    And a time attribute, like 0.5, 1.0 is the transition end.

    Thanks
     
  33. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    396
    Code (CSharp):
    1. public float GetCurrentAnimatorTime(Animator targetAnim, int layer = 0)
    2. {
    3.     AnimatorStateInfo animState = targetAnim.GetCurrentAnimatorStateInfo(layer);
    4.     float currentTime = animState.normalizedTime % 1;
    5.     return currentTime;
    6. }
    Also something similar to get name, layer is 0 by default (or you don't have more than one)
    Code (CSharp):
    1. public string GetCurrentClipName(){
    2.     clipInfo = animator.GetCurrentAnimatorClipInfo(0);
    3.     return clipInfo[0].clip.name;
    4. }
     
  34. OdZhurbii

    OdZhurbii

    Joined:
    Aug 11, 2021
    Posts:
    1
    THANKS A LOT. GetCurrentClipName method returns the name of the animation is being played in runtime. Love you <3
     
  35. NazariuX

    NazariuX

    Joined:
    Jul 20, 2021
    Posts:
    1
    This works fine for me:

    Animator anim;

    var name = anim.GetCurrentAnimatorStateInfo(0).nameHash;

    Debug.Log("My Animation name is "+name);
     
  36. realkillerx

    realkillerx

    Joined:
    Nov 9, 2013
    Posts:
    10
    We live in a society where this functionality is still not provided by Unity
     
  37. Superjayjay

    Superjayjay

    Joined:
    Mar 28, 2013
    Posts:
    69
    There are multiple WORKAROUNDS, each with their downsides, there isn't a single simple proper solution which is quite frankly unbelievable considering this is something you'd expect to have been there from the moment mecanim was released, almost a decade ago, but no, we still have to come up with S***ty workarounds. How is this even possible? The incompetence is almost as baffling as people defending the indefensible, just what is even your point here?
     
    kloot and TacticalShader like this.
  38. MagyarPeter

    MagyarPeter

    Joined:
    Nov 28, 2020
    Posts:
    11
    You can get the int identifier of an aniamtor state with "anim.GetCurrentAnimatorStateInfo(0).shortNameHash;"
    This int is fix and it can be used to play a state by using "anim.Play(anim.GetCurrentAnimatorStateInfo(0).shortNameHash);"//this code play the current state again, but you can story the state int id for other porpuses.

    A "Dictionary<string, int>" can convert the ints to more understandable names
     
  39. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    OMFG I didn't know were I was headed when I google'd something as simple as how to get the animator state name... :confused::rolleyes:
     
    BarriaKarl, lacas8282 and kloot like this.
  40. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Yeah..you get these enterprise coders and their 90lines of code and reflection when you only need a bool and string List to get er done..
    Code (CSharp):
    1. if (stateSwitches[i]) {
    2.      animator.SetBool(stateNames[i], true)
    3. }  else if (!stateSwitches[i]) {
    4.      animator.SetBool(stateNames[i], false)
    5. }
     
  41. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    Maybe because your solution only works for the most basic use case, it assumes that every state is triggered by a bool parameter without any other conditions. It is only a way to "guess" which state the animator has, the only way to get the accurate state information is to "ask" the animator itself.

    It will not work if:
    - any other parameter type is used (like int or triggers)
    - any transitions with multiple conditions
    - any animator state change which bypasses your switches, for example transitions without conditions or if the animator is controlled by a timeline etc.
    - animator with multiple layers

    A very simple example would be a trigger for an attack or reload animation
    IdleState -> AttackTrigger -> AttackState -> ExitTime -> IdleState

    The transition from AttackState back to IdleState is based on the attack animation duration (exit time) and not based on any bool parameter switch, so your solution already fails in that simple case.

    Btw since you seem to like short code so much, you can reduce your code even further:
    animator.SetBool(stateNames[ i ], stateSwitches[ i ])
     
    Last edited: Apr 16, 2022
  42. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    It is meant to get and set state via a string and matched index bool and only use one state at a time. Ya know..what the question asked was. Go ahead and complexify and enterprise out your solution. You gotta live with it..not me.. Triggers also work with this format even though written well prior to their integration.. In your example I can fire off the state via name and then do whatever and I have kept track of state I still know which state is firing..the essence of what the OP wanted to know.. Good optimization on the code snippet. Used to be the way the Unity dev thought until we got invaded by C# enterprise coders and their boilerplate complexities for no effing good reason.
     
  43. DarkGate

    DarkGate

    Joined:
    Jan 26, 2016
    Posts:
    33
  44. bestknighter

    bestknighter

    Joined:
    Dec 2, 2014
    Posts:
    18
    edit: changed code screen captures for written text for accessibility reasons.

    Here's my solution to this problem. I needed to notify some components that were in the same GameObject as a custom Animator Controller we wrote about its state changes. Stripping out code related to exactly what we needed, here is how I made:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class AnimatorStateName : StateMachineBehaviour {
    4.     [SerializeField] private string StateFullName = "";
    5.  
    6.     public string StateName { get { return StateFullName; } }
    7. }
    8.  
    This class was added to every state we wanted to be notified about when entered like so:
    upload_2022-6-14_11-53-46.png
    Ugh! Yes, it's ugly and terrible that we have to repeat the name of the state into the field, but it is what it is. Unity doesn't give us any other better way.

    Then, on the state machine layer I added the following script:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3.  
    4. public class StateChangeNotifier : StateMachineBehaviour {
    5.     public UnityAction<AnimatorStateName, int> onStateChanged;
    6.  
    7.     private AnimatorStateName[] states;
    8.     private bool initialized = false;
    9.  
    10.     override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) {
    11.         if( !initialized ) Initialize(animator);
    12.         foreach( var state in states ) {
    13.            if( stateInfo.IsName(state.StateName) ) {
    14.                onStateChanged?.Invoke(state, layerIndex);
    15.                return;
    16.            }
    17.         }
    18.     }
    19.  
    20.     private void Initialize(Animator animator) {
    21.        states = animator.GetBehaviours<AnimatorStateName>();
    22.        initialized = true;
    23.     }
    24. }
    25.  
    I send the entire AnimatorStateName when invoking because we need some extra info that was added to that class but I striped out for these prints (that is also why the property's name mismatches the field. I removed some sanitization we do) but if you just want the state name, you can simply send the string.

    Then, every component that is interested in those state changes just had to add this:
    Code (CSharp):
    1. private void Start() {
    2.     GetComponent<Animator>.GetBehaviour<StateChangeNotifier>().onStateChanged += StateChanged;
    3. }
    4.  
    5. private void StateChanged(AnimatorStateName state, int layerIndex) {
    6.     // Do stuff
    7. }
    8.  

    By doing like this way, we do not affect any kind of transitions, do not create a huge and/or unnecessary amount of booleans, arrays, strings and the like. Also, since the array of AnimatorStateInfo is dinamically populated, we do not need to change any code if we create/remove/change states. Better yet, if there's any state that we want to NOT notify when entered, we can simply not add the AnimatorStateName to it.
    It is write and forget, unless you want to add more functionality (instead of spending time to keep an existing functionality working).

    The only down side is, as stated, that you'll need to retype the state name into the field. This opens spaces for typos. At least those bugs will be easy to spot. Well, at least in most cases. If you want to, you could add a
    Code (CSharp):
    1. Debug.LogWarning()
    after line StateChangeNotifier.cs:17 about not found names. But then, states with no AnimatorStateName will also cause this line to be executed.
     
    Last edited: Jun 14, 2022
  45. kloot

    kloot

    Joined:
    Mar 14, 2018
    Posts:
    78
    It's a bit sad how no one at Unity seem to pay attention to these ancient threads.
    Pause work on Dots for one year and sooo many if these glaring holes could be fixed.
    The engine would come looking out a lot less like a Swiss cheese afterwards. Well, one can dream :)
     
  46. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Actually, this is not a bug, it's a feature: the mecanim animator doesn't store the name of the states for optimization reasons. The best way to handle this is using tags instead.
     
  47. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    so its 2022 and still has no nice and slick solution to get just string name of current playing animation state name?
     
    kloot likes this.
  48. IoannisNoukakis9390

    IoannisNoukakis9390

    Joined:
    Jan 13, 2017
    Posts:
    2
    That was the missing piece, thank you :)
     
  49. robotrods

    robotrods

    Joined:
    May 10, 2020
    Posts:
    2
    Hello, I'm a bit late to the party, but this works for me in Unity v2020.3.30f1:
    Code (CSharp):
    1. [SerializeField]
    2. Animator animator = GetComponent<Animator>();
    3. AnimatorClipInfo[] clipInfo;
    4.  
    5. public string GetCurrentClipName(){
    6.     clipInfo = animator.GetCurrentAnimatorClipInfo(0);
    7.     return clipInfo[0].clip.name;
    8.  
    9. void FixedUpdate()
    10.     {
    11.         Debug.Log("FixedUpdate Animation name is " + GetCurrentClipName());
    12.     }
     
  50. mexicano

    mexicano

    Joined:
    Nov 12, 2013
    Posts:
    23
    Your saviour is here after many years here it is:

    Code (CSharp):
    1. //this are variables you get inside the StateMachineBehaviour
    2. Animator _Animator, int _iLayer, AnimatorStateInfo stateInfo
    3.  
    4. UnityEditor.Animations.AnimatorController _AnimatorController = _Animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
    5.         UnityEditor.Animations.AnimatorStateMachine _StateMachine = _AnimatorController.layers[_iLayer].stateMachine;// this is reference to Base Layer
    6. //this is how you get the name of each state inside a for loop
    7. _StateMachine.states[i].state.name
    8. // you can use teh compare to see if name matches
    9. stateInfo.IsName(_StateMachine.states[i].state.name);
    10.  
     
    Rodolfo-Rubens and Alic like this.