Search Unity

Is there a way to check whether the current Mecanim state is in a specific Sub-State Machine?

Discussion in 'Animation' started by dreasgrech, Apr 9, 2015.

  1. dreasgrech

    dreasgrech

    Joined:
    Feb 9, 2013
    Posts:
    205
    Whenever I need to check for the current Mecanim state, I use Animator.StringToHash and then compare it to the current state's fullPathHash.

    But what should I do when I want to check if the current state is in a sub state machine (ideally without adding state behaviors to manually keep track)? Maybe the current sub state machine can be extracted from the fullPathHash with some bit tricks?
     
    Last edited: Apr 9, 2015
  2. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    Not really, this is a hash of the full path, reverse operation of hashing is not possible.

    Could you use tag on your state? You could tag all your state from a sub statemachine with the name of the substatemachine.
     
    dreasgrech likes this.
  3. dreasgrech

    dreasgrech

    Joined:
    Feb 9, 2013
    Posts:
    205
    Thanks for your reply.

    Ending up going with State tags eventually, and it works just fine.
     
  4. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,147
    I'm having this problem too, I have a subStateMachine with lots of states within it.

    I just want to know if I'm in that subStateMachine, don't care about the states within it.
     
    RickshawDerpyDerp likes this.
  5. dreasgrech

    dreasgrech

    Joined:
    Feb 9, 2013
    Posts:
    205
    Make use of state tags instead and check using the current state's tag with IsTag.
     
  6. theANMATOR2b

    theANMATOR2b

    Joined:
    Jul 12, 2014
    Posts:
    7,790
    I've seen this asked a half dozen times over the last couple days.
    @CDF @dreasgrech - what are some common reasons to want/need this information? (what sub-state machine is mecanim in)

    I'm guessing maybe to fire off an event when the specific sub-state is recognized as the active state, but that doesn't seem right since events are readily available? It's just a little bothersome not to understand the 'why' to this question when it has been asked several times. :confused:
    Why do you guys 'check' the states?

    Thanks - Any help/clarification is greatly appreciated.
     
  7. dreasgrech

    dreasgrech

    Joined:
    Feb 9, 2013
    Posts:
    205
    Imagine having two state machines, one for idle stance and one for combat stance, and from the code you need to check which stance the player is in according to the animation tree.

    If you were able to check if the current state is under a specific state machine, then you would be able to determine whether the player is in idle or combat.

    Unity doesn't support this functionality, but supports State Tags instead i.e. you tag specific states (rather than state machines) and then in the code you check if the current state's tag matches a specific tag.
     
    theANMATOR2b likes this.
  8. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,147
    ^ yep. Sometimes I need to know if my animation is currently in an "Air" substate, "Attack" substate or "Normal" substate. The logic controlling the character needs to know this in order to tailor functionality around those states.

    Maybe unnecessary if we created bools defining current state, but things tend to get out of whack when transitions occur and your animation can get out of sync from your logic, I also find it cleaner if I can grab the substate name rather than define all these bools or enums.
     
    theANMATOR2b likes this.
  9. theANMATOR2b

    theANMATOR2b

    Joined:
    Jul 12, 2014
    Posts:
    7,790
    Thanks a lot for the replies.

    Can you give a simple example of tailored functionality that uses the state information? I might be really trying too hard to think around this.
    Possibly a fall from a specific height causes damage if the registered state is falling for a long duration? Is that a simple type of functionality that would use the state information to update -50 health - fire a 'ugh' sound, maybe activate the limping animation sub-state for the character?
    Haha - my mind is going crazy trying to figure this out, trying to understand the use/usefulness of knowing which state/sub-state the animation is in.

    Anyway - Thanks again.
     
  10. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,147
    Yeah I that falling example is a good one.

    Recently I had to create a simple fighting game. I was using subStates for attack animations, grouping them all under an "Attack" subStateMachine. I needed to know when the character had successfully transitioned into one of the states within "Attack" subStateMachine so I could allow attack combos. Pressing the attack key again while in the "Attack" subStateMachine would advance the current type of attack to the next animation. If the player didn't press quickly enough the animator would return to an "Idle" state and as a result, the attack combo script would be disabled.

    I ended up using Tags to achieve this which is fine. But could probably get messy if the animator became very complex.

    Have you guys thought of a LayerMask type setup? Assigning masks to states and subStateMachines, we could do bitwise logic to determine states.

    Code (CSharp):
    1. attackMask = NormalAttack | SpecialAttack;
    2.  
    3. if ((animator.currentMask & attackMask) != 0) {
    4.  
    5.      //we're in some kind of attack state
    6. }
     
    Silly_Rollo and theANMATOR2b like this.
  11. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    I'm trying to figure out how to get code to run anytime you exit a substatemachine to change some details about a character. When you enter certain subStateMachines, it hides their weapons and when you exit them, it shows them.

    Currently I use OnStateMachineExit... however that ONLY runs if you hit the exit node for the subStateMachine. If an AnyState transition happens while you're in the subStateMachine, that event won't fire.

    I was planning on making a StateMachineBehavior that uses OnStateExit, which will run anytime you exit any state in the subStateMachine and then check if the state it's transitioning to is in the current subStateMachine... however this seems impossible as well.


    As far as I can tell so far, it's impossible to implement functionality that runs whenever you exit a subStateMachine for any reason (including transitions to "Any State").

    The only work around is to tag everything in every state... but this is incredibly impractical and it wastes the tags. I won't be able to use them for any other functionality.

    This is a terrible oversight and must be addressed.

    Does anyone have any suggestions for any non-horrific workarounds?
     
  12. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    5,615
    Nope!

    For the exact reason you're pointing out, I've had to create a script that collects data about all the states in the animatorController in edit time, and saves them. Then, in runtime, the script checks which state the machine is currently in, and sends custom version of OnStateMachineEnter/Exit whenever a state machine is entered or exited.

    It's ugly, and probably has an overhead, but OnStateMachineEnter/Exit is very useful concepts, so creating a script that implements them properly was worth it.
     
    theANMATOR2b and Eluem like this.
  13. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    I see, so that's how you did it... that's really frustrating lol. I wish there was a native way to do this correctly... I guess I'll either try to implement a similar solution or try to work around the problem by trying to force all my statemachines to always enter through the entry node.

    The main issue I'm having right now is that I toggle something off upon entering a few subStateMachines and then I turn it back on upon exiting. If I exit via AnyState interrupting the process, it never gets reenabled.

    The "thing" that I'm toggling is the currently equipped weapon, so I guess I can toggle it back on when I reenter a "normal" combat statemachine.. assuming I always make sure they enter the machine in the prescribed manner.

    frustration++;
     
  14. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    5,615
  15. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    1,147
    That is very cool. Wish Unity would do the same.
     
  16. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    382
    @Mecanim-Dev You see what you've done guys? :D You monsters!!
     
  17. RickshawDerpyDerp

    RickshawDerpyDerp

    Joined:
    Nov 6, 2018
    Posts:
    22
    Unity needs to be able to tell when it's inside a substate machine for all the reasons described above. I have several substate machines with LOTS of states inside, and it would be tedious, if not too much overhead, to add the same tag (in addition to whatever other tag I need) to every state in that machine. Example:

    I use the names of animation states in my Update() and FixedUpdate() methods to do checks in IF statements. that check looks like (for one example):

    Code (CSharp):
    1. if (animator.GetCurrentAnimatorStateInfo(0).IsName("Run_Back_Home"))
    2. {
    3.     //Do stuff
    4. }
    Now, a lot of these animation states are inside of other state machines. Take the `Battle_JumpAttack` state machine:




    It would be most simple for me (I think) to access animations based primarily on whether I am inside this machine. How do I check for that?

    More info: Some animations can happen immediately after another ends; others need to be triggered manually (in the Update() loop) only after a Lerp() has completed. But I only want to test for these conditions while I am inside this state machine
     
  18. PeterPudeltreter

    PeterPudeltreter

    Joined:
    Apr 1, 2021
    Posts:
    9
    Fighting with the exact same problem right now and I really would like to avoid having to add Tags to every single state inside every single sub-statemachine. Is there still no easy/native way to check if the animator is in a specific sub-statemachine?
     
  19. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57

    Did you see @Baste's solution?

    https://github.com/Baste-RainGames/AnimatorFix
     
  20. PeterPudeltreter

    PeterPudeltreter

    Joined:
    Apr 1, 2021
    Posts:
    9
    Yeah, but I'd rather avoid doing it that way. I don't want to have to carry over this kind of inpsector-variable information into the runtime with a script that needs to run at editor-time. I do it manually now inside a StateMachineBehaviour that sits on the substatemachine by naming the sub-states that need to be monitored in a public string list variable... Out of all the inconvenient solutions I prefer the "do it manually" one I guess... Next time I'm going to avoid the Animator component altogether.
     
    Last edited: May 21, 2021
  21. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57

    That's totally fair. However, if you set all that up, couldn't you generate them?

    Also, out of curiosity, how would you avoid it? Is there another animation method you think would be better in Unity? I'd love to know honestly lol
     
  22. PeterPudeltreter

    PeterPudeltreter

    Joined:
    Apr 1, 2021
    Posts:
    9
    It's true generating the names would probably be saving a bit of time in the long run. But I fear that managing that code could end up being more work in the end then just typing in the names. I usually don't like to be too dependent on unsupported code that could stop working after a Unity update. I read that there is an issue in the script (the one that you linked) in that you have to select a component in the GUI each time after changing the Controller.
    One advantage of typing in the names of the monitored states is that I can monitor a certain subset of states that are inside such a substatemachine and trigger events when entering/exiting those subsets.
    I have been thinking about using Animancer and writing a MonoBehaviour based state machine from scratch to manage animations and transitions. The amount of time I have spent researching workarounds for problems related to StateMachineBehavriours and the Animator is adding up constantly.
     
    Eluem likes this.
  23. Eluem

    Eluem

    Joined:
    Apr 13, 2013
    Posts:
    57
    You're not wrong. I wish unity had a state machine system that was designed to be entirely generic but capable of supporting the animation system.

    Then, we could implement it with the built in animators.. Or use any other animation system more openly... And we could use the state machines for other gameplay logic without it feeling like a work around.

    Maybe I should just start making assets like this before I try to finish a game lol :p
     
  24. Sanctus2099

    Sanctus2099

    Joined:
    Dec 11, 2013
    Posts:
    90
    I have the same issue at the moment. I need to know when a controller enters and exists a sub state machine.

    So far the behaviours have been horrible. OnStateMachineEnter/Exit works fine but you can only get an Animator as a parameter which is basically useless. In my case I don't really use MonoBehaviours that much so I can't just get a component from a sibling. I figured, hey, I can initialize the behaviours when I first create the animator and then I'll have some stuff to callback to. Yeah, no, the behaviours will be enabled disabled a random amount of times, without any explanation.

    I started playing with AnimatorStateInfo and AnimatorTransitionInfo, monitoring them for changes to call certain callbacks but all this does not seem to work with sub state machines.

    I switched to Mecanim from the Legacy system a couple of days ago thinking the 6 years since I last used should've been enough time for it to mature but now I regret the move.
     
unityunity