Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
September 30, 2014
arrowPress Releases
September 30, 2014
PR Newswire
View All





If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
Creating fluid motion transitions with Unity and Mecanim.
by Heikki Tormala on 12/14/12 08:56:00 am   Expert Blogs   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

Introduction

Mecanim is Unity game engine's new animation technology introduced in Unity 4. When Unity 4 beta was first released, we decided to use it in our hot air balloon aerial combat game, AirBuccaneers, in part because of the new features it could offer us and new means to shorten and simplify common animation tasks.

This article is not meant to be a comprehensive guide to Mecanim. Understanding how Mecanim works or at the very least going through the Mecanim tutorial are minimum requirements for understanding this article. You should also view the AirBuccaneers trailer to better understand how the different animations are used in the game.

Hand placement is driven by IK when using a cannon

Due to the limitations in editing animation controllers, this article should not be taken as an overall 'how to do it with Mecanim' guide, but rather as individual guidelines. There are probably better ways to organize the overall animation state machine but since modifying it significantly is time consuming, some tricks were employed rather than fixing the overall state machine.

Characters are moved with physics, so root motion was not used. IK was used when moving the cannons to drive accurate hand placement.

 

Motions

The system needs to support fluid transitions between these different motions:

  • Idle (several different)
  • Moving to any direction (with strafing to left and right)
  • Jumping and other mid-air motions
  • Hanging from a rope, and climbing it up and down
  • Steering an airship
  • Using cannon
  • Using glider
  • Using the different weapons
  • Looking up and down
  • Additional gesture animations

Animation layers

The animation layers used in this article are not necessarily the best or even the proper way to do anything in Mecanim, since reordering the layers or easily copying states from one layer to the other is impossible at the moment.

  • Movement and steering
  • Rope
  • Mid-air
  • Right-arm gestures
  • Upper body gestures
  • Full body gestures 1
  • Full body gestures 2
  • Spine

Movement and steering

Movement animation state machine

We start with basic forward, backward, left and right movements, and idle. In addition to these cardinal directions, we want to have blended motion for all intermediate directions.

Each movement state is a Blend Tree with each blending 3 movement motions. For example the 'Run' state has 'RunLeft', 'Run' and 'RunRight' animations blended with 'SpeedHoriz' as Event Parameter. Notice we set the range from -2 to 2 even though the parameter only has real range of -1 to 1. This way at the limit we blend with equal strength the 'Run' animation and either the 'RunLeft' or 'RunRight' animations giving us a nice 'run forward and left' animation. We define similar Blend Tree for each of the cardinal directions, although in hindsight it would only be necessary for the 'Run' and 'RunBack' states.

Movement blend tree Movement blend tree details

4 parameters are used to achieve smooth and responsive blending between the animation states when moving. 'SpeedVert' is for moving backwards and forwards and 'SpeedHoriz' is for moving left and right. These are not dampened in code, as this allows for the animation to start playing as soon as the character moves even a little. If dampened, the animation will lag behind the actual movement. 'SpeedVertDamp' and 'SpeedHorizDamp' is used in the Blend Trees of the cardinal directions to allow for smooth blending when transitioning from cardinal direction to intermediate direction.

Animation state machine

animator.SetFloat("SpeedVert", v);
animator.SetFloat("SpeedHoriz", h);
animator.SetFloat("SpeedVertDamp", v, 0.15f, Time.deltaTime);
animator.SetFloat("SpeedHorizDamp", h, 0.15f, Time.deltaTime);

There are many additional animation states on this layer. For example 'RunToIdle' motion for when a character stops, or the various steering animations. Nearly all the states are connected to each other to make sure immediate transitions occur between the states as needed.

Rope

For the rope, we have idle-animation and climbing up and down the rope.

Hanging from an airship on a rope Rope state machine

Mid-air state machine

Mid-Air movement

For jumping, we have separate animations for jumping in-place and jumping while running. Jump animation is cut into three separate animations: JumpUp, JumpAir, JumpDown, to allow for jumps of undefined length and duration. JumpAir is also used while mid-air without jumping, for example when a character falls down from an airship. We have a transition from 'JumpAir' to 'Empty' to make sure that when user grabs a rope while falling, we don't play the 'JumpDown' animation as that would just look silly.

Also there is transition from 'JumpAir' to 'JumpDownIdle' so that if a character stops moving in the middle of the jump, we play the end for jumping in-place. 'FallDown' animation is played when character has been falling down for a specific amount of time to give the appearance of an out-of-control falling.

Right-arm state machine

Right-arm gestures

A BodyMask with only right arm activated is used for this layer. The gestures in this layer are played back when user is using his left hand to hang from the rope.

Upper body gestures

A BodyMask with only the upper body activated is used for this layer. This layer is for gestures that do not require full body movements, but only the upper body such as the SupportStaff. A special upper body idle animation is used when a character equips the Musket (Blocker in-game) so that we can have both hands on the weapon. It requires a few additional transitions to work, but nothing complicated.

Upper body state machine

Notice that there are two states for SupportStaff. This allows for the animation to interrupt itself and restart from the beginning while blending with itself. This is useful if you have an animation that should be repeated with an arbitrary interval.

Here we run into a complication that seems at the time of writing of this article to be impossible to solve. The 'ArmedMusket' needs to be synced to the running and idle animations, but that does not seem to be possible (syncing two layers does not sync their timing, animation timing can't be controlled from script). Because of this, character's hands can start wildly swinging out-of-sync with the running animation at times.

Full body gestures 1 and 2

Two synced layers are used for full body gestures such as swinging the sword. First layer has a full BodyMask and is used when the character is not moving. The second layer has BodyMask for upper body and is used when the character is moving. Layer weights between the two layers are blended in code based on the character movement.

Full body gestures state machine

float fullBodyGestures = moving ? 0 : 1;
float velocity = 0;
fullBodyGestures = Mathf.Clamp01(Mathf.SmoothDamp(animator.GetLayerWeight(5), fullBodyGestures, ref velocity, 0.08f));
animator.SetLayerWeight(5, fullBodyGestures);
animator.SetLayerWeight(6, 1 - fullBodyGestures);
 

Spine

Spine-layer is used for all additive animations. These animations are generally used to move the characters spine so that it either looks up or down. Separate animations for looking up and down while holding a musket are provided to make the character look better while holding the musket. 'CannonPose' is used to move the lower body so that the character can better reach the IK targets in the cannons.

Spine state machine Spine blend tree

Conclusions

Unity's Mecanim animation technology allowed us to implement many advanced features with modest effort in reasonably short time. It significantly reduces code lines and complexity. Inablility to affect the state machine and transitions from script and overall inability to properly modify the state machine at runtime are its biggest flaws.


Related Jobs

Raven Software / Activision
Raven Software / Activision — Madison, Wisconsin, United States
[09.30.14]

Sr. Gameplay Engineer - Raven
Raven Software / Activision
Raven Software / Activision — Madison, Wisconsin, United States
[09.30.14]

Lead Engineer - Raven
Square Enix Co., Ltd.
Square Enix Co., Ltd. — Tokyo, Japan
[09.29.14]

Programmers
Harmonix Music Systems
Harmonix Music Systems — Cambridge, Massachusetts, United States
[09.29.14]

Client-Server Network Engineer






Comments


Ian Morrison
profile image
That movement and steering FSM is terrifying! What have you done to manage the complexity of that? It looks like a gigantic pain to work with. The animation setup I'm currently using is a single layer with not even half the complexity of that, and it's already a fair amount to keep track of!

I'm hoping that Unity will add some sort of transition sharing functionality to their animation controllers in the future, whether it's adding functionality to support HFSMs or allowing behaviour trees as an alternative. FSMs just can't scale up without turning into a mass of spaghetti... sure, they're straightforward to wrap your head around, but when every transition has to be specified manually the work just increases quadratically to add new animation states.

Apologies for the rant: this is a really helpful article! I appreciate seeing your approach for managing a very big animation set. I'll need to look into layers more, because I really like what you're doing with them for managing complexity and dealing with distinct game-states.

Heikki Tormala
profile image
The terrifying thing is that I didn't develop any special means to manage it. Like bad spaghetti code, it started simple enough but grew into the monstrosity as more animations were added.

It is not quite as bad as it looks though, you just need to be careful and meticulous when editing it. I wish I could have moved some of the movement animations to another layer, but Unity won't allow you to insert new animation layers, only add them at the end.

HFSMs I think would be great addition to Unity and would have solved a lot of the complexity.

Ian Morrison
profile image
One solution I've come up with to try and share some of my transitions is a hacked together "event" system. An event was fired on the code side by flipping a boolean property from 0 to 1 for one frame, and then back to 0 the next (done using a yield to keep it simple). These events were then safe to use in transitions from the "any state" node, since they'd only fire for one tick and not every single tick thereafter. I was able to keep a number of state machines almost entirely unconnected on a single layer, with discrete graphs for jumping, grounded animation, and clinging to ledges being managed by "EventGrounded", "EventJumping", "EventRelease", and "EventCling" properties.

A proper event system would be awesome, but in lieu of that hacking one in hasn't caused me any issues yet.

rocki rolling
profile image
@Heiki. Thank you for the great article, very informative.


@Ian. Interesting event system idea, how does it work? Can you give some code examples or screen shots to show how it's implemented.

Cheers.

Igor Levochkin
profile image
which unity version do you use? i have 4.0.1f2, here Layer-> sync not work at all, nothing happens if you change Weight on synced layer

also couldn't found any samples where it used.


none
 
Comment: