03 Linear Blending

Difficulty: Intermediate

Location: Assets/Plugins/Animancer/Examples/03 Locomotion/03 Linear Blending

Namespace: Animancer.Examples.Locomotion

This example demonstrates how you can blend between Idle, Walk, and Run animations based on an arbitrary parameter to move the character at any desired speed using either a Blend Tree in a Controller State or a Mixer State as well as how Transition Assets allow you to share animation details throughout your project.

Pro-Only Features are used in this example: Controller States and Mixer States. Animancer Lite allows you to try try out these features in the Unity Editor, but they are not available in runtime builds unless you purchase Animancer Pro.

Blend Tree

This example uses an Animator Controller containing a Blend Tree which blends between Idle, Walk, and Run animations:

Controller States are used to play Animator Controllers inside Animancer. Rather than using a RuntimeAnimatorController field to assign the Animator Controller and then creating a new ControllerState manually, we can just use a Transition (specifically a ControllerState.Transition) which will handle that all for us:

using Animancer;
using UnityEngine;

public sealed class LinearBlendTreeLocomotion : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private ControllerState.Transition _Controller;
    
    private void OnEnable()
    {
        _Animancer.Play(_Controller);
    }
}

Parameter Controller

In this case, the only thing in the Animator Controller is a Blend Tree controlled by a float parameter, so rather than hard coding the script to use ...SetFloat("Speed", value) to control it we can instead use a Float1ControllerState.Transition to wrap that parameter for us:

Note the new Parameter Name field which gives us a dropdown menu to select the name of any float parameter in the assigned Controller. This allows us to get and set that parameter using _Controller.State.Parameter. For this example, we want to control it using a UI Slider so we need a public property (or method) for it:

public float Speed
{
    get { return _Controller.State.Parameter; }
    set { _Controller.State.Parameter = value; }
}

This gives us a character who can move at any speed:

You may notice that while blending between Walk and Run works well, the blending between Idle and Walk gives a much slower result than you might expect (the character barely moves at all when under 50% speed). This is due to the way Blend Trees synchronise the timing of all their states which is useful for cases like Walk and Run where you want both animations to always be at the same point in their walk cycle to get a good result, however it is detrimental in cases where it does not make sense for timings to be synchronised such as between Idle and Walk where there is no correspondance between their cycles and therefore no point in synchronising them. Unfortunately, Blend Trees do not allow you to control or disable this feature, however Animancer's Mixer States serve a similar purpose to Blend Trees and allow you to determine which of their states are synchronised.

Transition Asset

Since we want to have multiple characters using the exact same setup we can give them all references to the same Transition Asset rather than each one having its own transition. This requires a few modifications to the script.

First we change the _Controller field type:

[SerializeField] private Float1ControllerTransition _Controller;

The State property will only hold the state that was most recently played from that transition. Previously each object had its own transition so it was not a problem, but now that they are all sharing the same one we cannot rely on that property anymore. Instead, we can just store the state in another field right after it is played:

private Float1ControllerState _State;

private void OnEnable()
{
    _Animancer.Play(_Controller);
    _State = _Controller.Transition.State;
}

public float Speed
{
    get { return _State.Parameter; }
    set { _State.Parameter = value; }
}

Note that a Float1ControllerState is just a ScriptableObject with a Float1ControllerState.Transition field, so we now need to use _Controller.Transition.State rather than just _Controller.State.

The final script looks like this:

using Animancer;
using UnityEngine;

public sealed class LinearBlendTreeLocomotion : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private Float1ControllerTransition _Controller;

    private Float1ControllerState _State;

    private void OnEnable()
    {
        _Animancer.Play(_Controller);
        _State = _Controller.Transition.State;
    }

    public float Speed
    {
        get { return _State.Parameter; }
        set { _State.Parameter = value; }
    }
}

Now we can set up the actual Transition Asset itself:

  1. Right Click in the Project window and use Create -> Animancer -> Controller Transition -> Float 1.
  2. Assign the desired Animator Controller to the newly created asset and select the Parameter Name you want it to wrap.
  3. Assign that asset to the Controller field in the LinearBlendTreeLocomotion script.

This means that the character's Inspector now only has a single field to reference the asset while the asset itself contains the details that will be used to create a state at runtime:

Character Inspector Transition Asset

If you have Inspector Gadgets Pro, you can use its Nested Object Drawers feature (by clicking on the foldout arrows) to see and modify the details of the referenced asset without needing to actually go and select that asset:

Mixer State

Mixer States are essentially just Blend Trees which are constructed using code at runtime instead of being configured in the Unity Editor as part of an Animator Controller. Specifically, they can be constructed using code and you can access their internal details even though in this example we are just using a Transition.

They are so similar that the script to use a mixer looks almost identical to the one using an Animator Controller:

The only differences are the class name and the change from Float1ControllerTransition _Controller to LinearMixerTransition _Mixer.

using Animancer;
using UnityEngine;

public sealed class LinearMixerLocomotion : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private LinearMixerTransition _Mixer;

    private LinearMixerState _State;

    private void OnEnable()
    {
        _Animancer.Play(_Mixer);
        _State = _Mixer.Transition.State;
    }

    public float Speed
    {
        get { return _State.Parameter; }
        set { _State.Parameter = value; }
    }
}

The Inspector configuration is also very similar to the Blend Tree (except that Time Synchronisation is disabled for the Idle animation):

Slider

The blending parameters in this example are controlled by a UI Slider which works like a UI Button except that instead of an On Click event like Buttons have, it has an On Value Changed event with a float parameter to indicate what value it was set to. This means that when selecting what you want it to call, the Speed property will appear twice:

Dynamic Float Static Parameters
This is the one we want because it will pass the value of the Slider component into the property. This one shows a float field in the event itself and will pass that value into the method, regardless of the state of the Slider component.