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.
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.
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
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
- Right-arm gestures
- Upper body gestures
- Full body gestures 1
- Full body gestures 2
Movement and steering
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.
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.
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.
For the rope, we have idle-animation and climbing up and down the rope.
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.
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.
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.
float fullBodyGestures = moving ? 0 : 1;
float velocity = 0;
fullBodyGestures = Mathf.Clamp01(Mathf.SmoothDamp(animator.GetLayerWeight(5), fullBodyGestures, ref velocity, 0.08f));
animator.SetLayerWeight(6, 1 - fullBodyGestures);
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.
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.