07-01 Basic Layers

Location: Assets/Plugins/Animancer/Examples/07 Layers/01 Basic Layers

Recommended After: Simple Character

Learning Outcomes: in this example you will learn:

How to play multiple animations at the same time on different body parts.

How to use Layers.

How to use Avatar Masks.

This example implements similar behaviour to the Simple Character example, except that it uses Layers and Avatar Masks to play multiple animations at the same time on different body parts:

  • Idle and Walk are played on Layer 0 (the "Base Layer") which controls the whole body.
  • Action is played on Layer 1 (the "Upper Body Layer") which has an Avatar Mask to make it only affect the character's upper body. So while it's active, it takes precedence over whatever is playing on Layer 0 (but only affects the upper body).

That allows the character to perform the action while walking without needing to actually make a separate ActionWhileWalking animation.

Layers are a Pro-Only Feature. You can try them out in the Unity Editor with Animancer Lite, but they're not available in runtime builds unless you purchase Animancer Pro.

Note how the Layered character only plays the Action on the upper body, even if the lower body is Idle. The Dynamic Layers example demonstrates how you can make the Action control the full body for some animations and only the upper body for others.

Summary

  • You can access layers via animancerComponent.Layers[x].
  • Layers are automatically created when you first access them.
  • Layers have a StartFade method which is often useful for fading out a layer once an animation is finished so that the other layers can resume controlling the character.
  • Layers have a SetMask method to assign an Avatar Mask.

Overview

This example contains two characters:

Character Script Description
Simple SimpleCharacterAnimations The same character as the Simple Character example.
Layered LayeredCharacterAnimations Similar behaviour, but implemented using Layers.

The general code structure of LayeredCharacterAnimations is fairly similar to SimpleCharacterAnimations, but its setup and the way it plays its animations is a bit different:

using Animancer;
using Animancer.Units;
using UnityEngine;

public sealed class LayeredCharacterAnimations : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private ClipTransition _Idle;
    [SerializeField] private ClipTransition _Move;
    [SerializeField] private ClipTransition _Action;
    [SerializeField] private AvatarMask _ActionMask;
    [SerializeField, Seconds] private float _ActionFadeOutDuration = AnimancerPlayable.DefaultFadeDuration;
    
    private AnimancerLayer _BaseLayer;
    private AnimancerLayer _ActionLayer;

    private void Awake()
    {
        _BaseLayer = _Animancer.Layers[0];
        _ActionLayer = _Animancer.Layers[1];// First access to a layer creates it.

        _ActionLayer.SetMask(_ActionMask);
        _ActionLayer.SetDebugName("Action Layer");

        _Action.Events.OnEnd = OnActionEnd;
    }

    private void Update()
    {
        UpdateMovement();
        UpdateAction();
    }

    private void UpdateMovement()
    {
        float forward = ExampleInput.WASD.y;
        if (forward > 0)
        {
            _BaseLayer.Play(_Move);
        }
        else
        {
            _BaseLayer.Play(_Idle);
        }
    }

    private void UpdateAction()
    {
        if (ExampleInput.LeftMouseUp)
        {
            _ActionLayer.Play(_Action);
        }
    }

    private void OnActionEnd()
    {
        _ActionLayer.StartFade(0, _ActionFadeOutDuration);
    }
}

General Structure

The general structure of LayeredCharacterAnimations is basically the same as SimpleCharacterAnimations, but the specifics are a bit different.

private void Awake()
{
    // Initialize Layers (explained later).

    _Action.Events.OnEnd = OnActionEnd;
}

private void Update()
{
    UpdateMovement();
    UpdateAction();
}

private void UpdateMovement()
{
    float forward = ExampleInput.WASD.y;
    if (forward > 0)
    {
        // Play Move.
    }
    else
    {
        // Play Idle.
    }
}

private void UpdateAction()
{
    if (ExampleInput.LeftMouseUp)
    {
        // Play the Action.
    }
}

private void OnActionEnd()
{
    // Return to Idle.
}

Playing Layered Animations

By default, all animations are played on Layer 0. If you want to play an animation on a different layer, all you have to do is access it via AnimancerComponent.Layers like so:

private AnimancerLayer _BaseLayer;
private AnimancerLayer _ActionLayer;

private void Awake()
{
    _BaseLayer = _Animancer.Layers[0];
    _ActionLayer = _Animancer.Layers[1];// First access to a layer creates it.

    ...
}

Then you can tell a specific layer to play an animation instead of calling _Animancer.Play:

private void UpdateMovement()
{
    float forward = ExampleInput.WASD.y;
    if (forward > 0)
    {
        _BaseLayer.Play(_Move);
    }
    else
    {
        _BaseLayer.Play(_Idle);
    }
}

private void UpdateAction()
{
    if (ExampleInput.LeftMouseUp)
    {
        _ActionLayer.Play(_Action);
    }
}

You could skip the _BaseLayer field and just use _Animancer.Layers[0].Play(_Idle); every time, but getting the layer upfront saves a tiny bit of performance and makes the code a bit neater.

Note how the Inspector shows that the Layered character's Walk animation is still playing during the Action even though the Action is fully controlling the actual character model.

Interruptions

Note how during the Action, the Inspector for the Layered character shows that their Idle or Walk animation is still playing even though the character's pose is entirely defined by the Action animation.

While it wasn't the goal of using layers, in this case they actually make the code quite a bit simpler than SimpleCharacterAnimations because it doesn't need to keep track of the character's state at all. The Idle and Move animations will never interrupt the Action because it's on a higher layer and they can continue playing in the background until that layer fades out.

Here's the code that this example gets to skip:

class SimpleCharacterAnimations
{
    ...

    private enum State
    {
        NotActing,
        Acting,
    }

    private State _CurrentState;

    ...

    private void Update()
    {
        switch (_CurrentState)
        {
            case State.NotActing:
                UpdateMovement();
                UpdateAction();
                break;

            case State.Acting:
                UpdateAction();
                break;
        }
    }

    ...
}

Fade Out

When the Action ends in SimpleCharacterAnimations it plays the Idle animation, but that would be wrong here because we don't want to play Idle on the Action Layer. Instead, the script simply tells the Action Layer itself to fade out:

private void OnActionEnd()
{
    _ActionLayer.StartFade(0, _ActionFadeOutDuration);
}

0 is the target Weight it will fade towards.

Avatar Mask

Layers that simply override each other can be useful, but one of their most powerful features is the ability to use Avatar Masks to determine which body parts each layer affects.

You can create a mask via the Assets/Create/Avatar Mask menu function. The Upper Body mask used in this example has its Humanoid values set to only include the upper body.

The script references that mask using a Serialized Field to assign it in the Inspector:

[SerializeField] private AvatarMask _ActionMask;

And it tells the ActionLayer to use that mask on startup:

private void Awake()
{
    ...
    _ActionLayer.SetMask(_ActionMask);

With a mask set, the layer would use the name of the mask in the Inspector by default. But you can also replace it with a custom name:

    _ActionLayer.SetDebugName("Action Layer");
}

Either way, layer names are only used in the Inspector and any calls to SetDebugName will be compiled out of runtime builds so they have no effect on performance (because that method has a [Conditional] attribute applied to it). You can also set the name of a state in the same way.

The official Character Animation tutorial has a section which explains how to create Avatar Masks in more detail.

Conclusion

The layers and AvatarMask allow the character to perform the Action on with their upper body while still playing the Idle or Walk animation with their lower body:

What Next?

Example Topic
Dynamic Layers Allowing the character to play the Action using their whole body if they would be Idle and using the upper body only while they are Walking.