Mecanim transitions sometimes don't work

I’m making a 2.5d platformer brawler in the style of super smash bros and I will need to use either the root motion in mecanim or something similar hacked onto the legacy system.
I have tried quite a few different ways of getting root motion to work with the legacy system, but none of them seemed to work particularly well. I’m using non kinematic rigidbody physics by the way. I’ve found that the mecanim animation system’s Root Motion works quite well, but the mecanim state machine seems mortally opposed to doing what its told.

What I’ve done is set up my animator controller with a single Int parameter (called State) so that every state has a single transition coming out of Any State under the condition that the State parameter is equal to a specific number. Instead of calling CrossFade(“animation”) like I used to, now I call SetInteger(stateParameterHash, index) where index is the number that will trigger that transition (then I set State back to -1 in LateUpdate).

My problem is that the animations don’t always play when I tell them to. I can be falling and touch the ground, but it will still be playing the falling animation. Or I can be standing idle and start moving but it won’t play the idle animation, no matter how much I start and stop moving until I jump and hit the ground again. Its definitely not a problem with my state machine because literally the only thing that has changed is the way I tell it what animation to play.

I’ve set all of the transitions to be non-atomic which should mean they can be interrupted, but I’m a little unclear on that. I read a post somewhere that it only lets them be interrupted by a transition higher in the list, which would make it entirely useless for what I want.

If I’m falling, land, start running, crouch and then jump all in quick succession, why can’t mecanim go falling->land->idle->run->crouch->jump exactly as I tell it to? Either I’m doing something astoundingly wrong or mecanim really is as bad as I make it out to be. I sincerely hope its the first option because I don’t fancy having to go back to the legacy system and dicking around to get root motion working, so can anyone think of what I might be doing wrong?

[16159-state+machine.png|16159]

In my case I first Draw the movement State machine diagram then apply it on mecanim

->FSM

http://www.voidinspace.com/2013/05/a-simple-finite-state-machine-with-c-delegates-in-unity/

http://jessewarden.com/2012/07/finite-state-machines-in-game-development.html

unitygems.com - unitygems Resources and Information.

You transitions are not set up correctly, looking at the picture. If your parameters are empty I’m assuming they all work on Exit Time. This will mean that the default time is played in the animation then it’ll jump back to Any State and most likely play again. Add new transitions from your animations to the next state and add parameters to control when this happens.

I’m also trying to do the same, but I went with bools for each animation.
it won’t play well between idle and walking if I keep hitting forward forward forward forward forward forward forward.
the mecanim will cease to blend to the next “while blending”.

now think I might need to put most of’em in different layers and manually control the blend by weight.

I know this doesn’t fix your exact problem, but I’m trying to do the same thing you are, and I fixed it.

I’ve built my statemachine using a trigger for each animation in it. Kind of like your “state” integer, but spread out. I found out that there is a problem with Mechanim, if you try to trigger the same animation that is already running. I don’t think it is built for that. It is a state-machine after all, so it makes sense that it should never trigger an animation that is already running.

You “simply” have to check if the animation you’re starting is already running.

I’ve done these steps to ease my life:

  1. Made one trigger for each of my animations, with the same name as the animation I want to trigger! (this is important, if you want to use the simple functions below)

  2. Made a transition from “Any State” to each of my animations, and the only condition for each transition, is the matching trigger.

  3. Then I made a PlayAnimation function, which checks if the animation is already running:
    u

    public void PlayAnimation(string animationName){
    if (!_animator.GetCurrentAnimatorStateInfo(0).IsName(animationName))
    _animator.SetTrigger(animationName);
    }

…and here’s one where you can control the layer you’re checking:

public void PlayAnimation(string animationName, int layer){
    if (!_animator.GetCurrentAnimatorStateInfo(layer).IsName(animationName))
        _animator.SetTrigger(animationName);
}

The IsName() function checks if the string you pass it, is the name of the currently playing animation. If it isn’t, I use the trigger with the same name. Simple.

This works for me.

The animations trigger instantly, though.

I don’t know if this interrupts non-atomic animations.

EDIT: I have to test one thing myself, though. We may be able to interrupt and force-play the animation from the beginning, if it is already running, by triggering another (idle?) animation first, and then immediately trigger the animation again.

public void PlayAnimation(string animationName, int layer, bool forceRestart){
    if(_animator.GetCurrentAnimatorStateInfo(layer).IsName(animationName)){
        if(forceRestart){
            _animator.SetTrigger("Idle");
            _animator.SetTrigger(animationName);
        }
    }
    else
        _animator.SetTrigger(animationName);
}

I’m going to try it out.

EDIT: Tried it. It plays a bit of the Idle animation, before changing to the other animation :frowning:
No go. Maybe if you add an animation with just 1 frame?

Perhaps I should just buy 2Dtoolkit…

LAST EDIT:
Since doing this, I somehow got my Animator working normally, so now I can just do:

_animator.Play(animationName);

It doesn’t screw up anymore, and I don’t need to use triggers at all.
And also, I can do this to restart the running animation from scratch, even if it is the same animation:

_animator.Play(animationName, 0, layer, 0.0f);

I don’t know why, but this wasn’t working yesterday. _animator.Play() just didn’t do anything.