Best Practice For Different Stances?

I need to play different animations based on the current weapon the player (or enemy) is holding, for example if he uses a sword or a spear.

Now how would you setup this in mecanim? Would you use different sub-state machine in one layer and transit based on the current weapon? Or using multiple layers on top of the base layer and setting the layerweight of the unused weapons to zero?

I know that it is possible to create animator override controllers, and this would be my first solution, but I noticed it is only usable when the player starts with one kind of weapon and never changes it. Because changing the animator controller on runtime occurs in too abrupt motion and resetting the current animation.

Any hints?

2 Likes

I’ve built several multi-stance animator controllers with Mecanim. Here are my experiences:

If you have Unity Pro, you can use Sync Layers. They’re nice because you can manage a common template in the base layer, and then set the stance-specific animations in the sync layers. But you’re locked into the same state machine for all layers, and you get into timing issues if clips are different lengths for different stances.

You could also set up each state as a blend tree, where you blend on a float that specifies the stance (0=unarmed idle, 1=sword idle, 2=spear idle, etc.).This is pretty easy to set up, and as with sync layers you only need to manage one state machine (but it has the same structure for all stances).

The most flexible single-controller solution has been different sub-state machines as you described. This allows you to have different graphs and animation clip lengths for each stance. Use Animator.CrossFade() to switch between sub-state machines so you don’t have a mess of transitions between different stances.

Most recently, I used multiple runtime animator controllers, and it worked pretty well. Once I get a stance working, I can leave it alone. I don’t risk breaking an existing stance when adding a new stance, since they’re in separate controllers. And you can duplicate state names; they don’t need to be unique.

The key with runtime animator controllers is to sync the animations. In my case, when switching from pistol to rifle, I play a holster-pistol-to-idle clip that puts the character in the idle state. When I switch to the rifle animator controller, I play the idle-to-unholster-rifle clip.

3 Likes

Thank you very much for your reply, TonyLi!

I tried the blend tree method, but noticed that all animation events of every animation is played then (multiple footstep particles/sounds, etc.). I found a work a round for this but that wouldn’t work well to setup the different attack animations in one blendtree, because the times when an animation event should trigger weapon detection differs here.

Sub-State machines looks like a possible solution and thank you for the CrossFade() hint. Do you know how well the performance is with so many sub state machines? Especially if multiple enemies would using this setup?

Multiple runtime animator controllers look like a very good solution especially with your hint how to sync animations. But could the player move around while holstering the weapon or must he stay still to enable a smooth transition?

2 Likes

From my experience, the number of sub-state machines doesn’t matter, since it’s only in one state at a time. But the number of transitions matters a lot. Mecanim evaluates all potential transitions every frame. If you have a hundred transitions coming from Any State, for example, Mecanim has to evaluate the conditions on all of those transitions every frame, regardless of what state you’re in.

Once again, just need to find a way to sync the cut-over, or maybe mask it somehow, like a particle effect that covers the character for a few frames. (The old smoke and mirrors trick.)

2 Likes

And just using Animator.CrossFade() would skip this performance hit, right?

I was tinkering a bit with runtime animator controller to try to eliminate the hiccup which occurs when switching controllers. Saving the current animation, normalizedtime and animator parameters before the animator change and then resetting the saved data helped a lot. But now the animation is played without blending with my approuch. The problem is just that the animator resets everything and returns to the default state when changing controllers. And for me it is a bit difficult to draw the sword while crouching and cloak the hiccup.

I think I’ll settle with various sub state machines.

Thank you again Tony for your help!

1 Like

Happy to help! Yes, Animator.CrossFade() skips the performance hit.

3 Likes