uGUI, Uncategorized, Unity3D

Animating Multiple UI Elements with One Animator Controller

Have you ever wanted to animate multiple UI elements at once in Unity? Unity3D 4.6 brought with it the long-awaited Unity GUI (or uGUI) system, and with that, a lot of potential for creating great in-game UIs. When building your game’s UI, you will probably want to animate different aspects of it, whether that’s sliding a menu in from off-screen, fading in text, or any of a number of other effects. One option is to create separate animator controllers for every element, but that can quickly get out of hand: the number of assets to keep track of increases for every UI element you want to animate, not to mention the possible performance implications of running many separate animators at the same time.

A better solution is clearly to use a single animator controller to manage animations for multiple parts of your in-game UI, but there are some caveats. Animating an element implies having multiple states per element: fading in and out “Game Paused” text, sliding a panel on and off screen, and so on. Trying to manage all of these with a single state machine will result in a combinatorial explosion of required states… GamePausedPanelShown, GameUnpausingPanelHidden, GameUnpausedPanelShown, GameUnpausedPanelHidden are an incomplete list of states that you might require for just two animated elements!

The answer is in animation layers. You might be familiar with layers as allowing you to do facial animation in addition to action animations for your 3D models, but we can apply them here by creating one layer for each element you want to animate and change at runtime.

Animating UI Components with Layers
Animating UI Components with Layers

In this example, I’m demonstrating the scenario I mentioned before: I want to fade in and out a “Pause” text in response to the user pausing the game, and I also want to be able to slide a panel on-screen to display some non-critical information to the player upon request.

For the pause text, I have a simple 3-state state machine, and transition between them by setting a boolean isPaused animator parameter in response to user input. I’m doing something similar to animate the panel, with an isPanelVisible parameter. The Base layer is empty. All told, it took me five or ten minutes to set up.

However, if you repeat my setup and try to pause the game, you may be dismayed to find that your UI isn’t animating at all. That’s because there’s one additional step, the “secret sauce” to making this work: setting the layer weights. Unity defaults the weight of a new layer to 0, meaning it won’t contribute to the overall animation at all. You’ll want to set the weight of all your UI animator layers to 1, meaning the animations played by the layers’ states fully contribute to the final animation. This setting is found in the cog menu of the layer in the Animator window, as demonstrated in the gif below:

Setting Layer Weight
Setting Layer Weight

For a 3D model, you would tune layer weights based on how much that layer should reasonably contribute to the model’s animation, and is in general a more complex process, but for UI animation, each layer is basically independent of the others, and you want to make sure that all layers get to run their full animation. Setting all layer weights to 1 enables this.

One final thing to note is that if you have already begun animating a UI element on the Base Layer of your animator controller, and would like to move it to a new layer, leaving the default layer uncluttered, you can accomplish this by adding a new empty layer, then dragging that empty layer to the top of the layer list. Layers cannot be copied (so far as I know), but Unity treats the top layer as the default layer, giving it a forced layer weight of 1, and letting you set up multiple layers to control discrete UI components.

You can download the example Unity project.