Initial animation states in Unity’s Mecanim
A while back at work I sat down to do something which should have been straightforward: create an animation controller for a door, who’s state (open or closed) persists in the player’s save. Had things gone according to plan, there wouldn’t have been any reason to write about it. But I stumbled upon some surprising engine bugs which are outlined here.
Presented in this article is the problem I was attempting to solve, a description of the bug, and a workaround for it. The issues encountered in this article were discovered on engine builds 5.5, and 5.6. It is unknown to me if the bugs persists on Unity 2017.
Part 1: The Setup
We have a door. It has two states, opened or closed, with animations that transition between the two. The door’s state is part of the save file. When we load the save, we don’t want to show the transition animation, the door should just be fully opened, or fully closed.
Without this in place, the first few seconds after loading a save would look something like the furniture fiasco at the end of “a spoon full of sugar”

The Graph
This was my first pass. Skip ahead to part II if you are just interested in why it doesn’t work.
From the entry node, Mecanim immediately transitions to one of the starting states, both of which contain a 1 frame, non-looping animation. These starting states put the door in it’s proper position when the save is loaded.
Transition animations only occur If the player changes the starting value of “Open”. Note that we never need to return to the initial open or closed states, we can just stop on the last frame of the transition animation.
I’ve used this for a door, but the controller illustrated above would work well for any animated object with a single toggleable state.
Setting the Initial State
Since the player will be leaving some doors open and some closed, the starting values of our animation parameters will have to be set via script. The animator component starts the state-machine as soon as it’s enabled. For this reason, anything with a configurable starting state will need to have their animator component disabled by default in the hierarchy.
Sounds simple, but there’s a gotcha — setting an animation parameter on a disabled GameObject generates a warning:

What does work, thankfully, is disabling the animator component while leaving the GameObject enabled. Initial values can then be set on the OnEnable() method of your class, like so:
class Door : MonoBehaviour
{
private void OnEnable()
{
var animator = GetComponent<Animator>();
animator.SetBool("Open", false);
animator.enabled = true;
}
}Hiding Animated Components
A common use case is to animate something disappearing and then disable it to stop it’s scripts from running.
Disabling GameObjects causes some additional complications for Mecanim. Doing so will reset the animator back to it’s original state. If you re-enable the GameObject, Mecanim will run its logic from the entry node all over again. Sometimes, this is exactly what you want and sometimes it’s not. Unfortunately, you don’t get a choice; it’s not configurable.
For most rendered GameObjects, there’s a simple workaround. Avoid disabling the GameObject, and just disable the renderer component (and others as needed). Sadly, this isn’t an option for Unity’s canvas based UI, as the canvas renderer component cannot be disabled directly.
I assume the engine team has a good reason for this, but this does make using Mecanim for UI quite a bit trickier. For UI, disabling the GameObject is the most direct (and least hacky) method of preventing rendering. So if you want to use Mecanim, you’ll just have to work around the state-reset issue as best you can.
Part 2: Bugs
I dropped a door in a scene with the animation graph displayed above. It did not work as expected. The door, which should have started ajar, instead started closed and swung open.
I coded up a quick debug StateMachineBehaviour to log a message whenever Mechanim enters or leaves a state, in order to figure out why my animation graph ended up in the wrong place. Here’s where things got interesting…
Transitions Out of the Entry Node Are Ignored
My test was run with the animation parameter “Open” set to true by default. The output from the state logger reveals what happened:
Entered state ‘Closed’
Exited state ‘Closed’
Entered state ‘ClosedToOpen’The engine has transitioned inappropriately to the closed state, Unity appears to have a bug where the default transition out of the entry node is the only one that’s honored.
The Hack
It seemed reasonable to think that this problem was unique to the starting node. I hadn’t noticed any issue with Mecanim choosing the wrong transition out of other nodes, so I wondered if I could solve the issue by pushing the decision point to a later time by inserting an “empty” node.
“Hack Empty State” contains no animation data, in order to prevent a potential 1-frame flicker where the door is in it’s default position. I set the transition values to exit the node as soon as possible by setting “has exit time” and “transition duration” equal to 0.
Now when I hit play, the door starts in its open position and stays that way! Problem solved — Or so I thought.
Something worse
The hack gets around the initial state issue, but the logs reveal a more sinister bug at play. The output for this session is:
Exited state ‘Hack Empty State’
Entered state ‘Open’Mecanim has exited the empty state without having entered it! I was so caught off-guard by this that I was sure the fault was mine at first. It took a few more tests to trust what I was seeing. After confirming the bug, I wasn’t sure I could trust StateMachineBehaviours to behave correctly.
But what was the cause?
My first guess was that it was related to there being a transition of zero duration. I’ll skip the details of that test. It suffices to say that I was able to verify that with a sufficiently small transition time (roughly < 0.2 seconds), Mecanim will skip the entered state of the node.
Was this bug unique to the starting node? Or could this happen anywhere in the graph? As a test, I set up a chain of states with transitions of zero duration.
The output for this test:
Exited state 'Start'
Entered state 'A'
Exited state 'A'
Entered state 'B'
Exited state 'B'
Entered state 'C'Only the “entered” event for state A is skipped. State B and C behave appropriately. This suggests that the problem is related to the default transition. However, this is hardly an exhaustive proof.
Developers relying on a pairs of “Entered” and “Exited” calls should be on the lookout for this bug.
