02-01 Named Animations

Location: Assets/Plugins/Animancer/Examples/02 Fine Control/01 Named Animations

Recommended After: Quick Play

Learning Outcomes: in this example you will learn:

How to use a NamedAnimancerComponent.

How to play animations by name (rather than using direct references).

The recommended way of using Animancer in most situations is to directly specify the AnimationClip (or Transition) you want to play as the previous examples have demonstrated. However, Animancer does also support the ability to play animations by name so this example explains how you can do that. It also explains how you can actually use any type of Key (including enums) to identify your animations instead of only their names.

Summary

  • You can register an animation with a Key and later refer to it using that Key.
  • An AnimancerComponent will normally use an AnimationClip as the Key of its state.
  • A NamedAnimancerComponent will instead use the name of the clip as its Key so you can play it using animancer.TryPlay("Clip Name").

Here is a quick overview of what is happening in the above video:

  1. The NamedAnimancerComponent is set up with the Humanoid-Idle animation in its Animations list and Play Automatically disabled.
  2. After entering Play Mode, you can see in the Inspector that it creates a state for that animation but it is not playing and its Weight is at 0. Since the character is using a Humanoid Rig, having no animations with any weight puts it into a "compressed" or "hunched over" pose according to the muscle limits defined in the Avatar configuration.
  3. The TryPlay("Humanoid-Idle") button calls _Animancer.TryPlay("Humanoid-Idle"); to play the state with that name.
  4. The TryPlay("Humanoid-Walk") button tries to do the same thing with "Humanoid-Walk" but fails because no state has yet been created for that animation so it logs an error.
  5. The Create "Humanoid-Walk" State button creates a state for the Humanoid-Walk animation.
  6. Now that the state exists, the TryPlay("Humanoid-Walk") button can play it by name.
  7. The Play(_Run) button passes the Humanoid-Run AnimationClip into the Play method to show that names and direct references can both be used on the same object.

Overview

The NamedAnimations script contains all the example code and looks like this:

using Animancer;
using UnityEngine;

public sealed class NamedAnimations : MonoBehaviour
{
    [SerializeField] private NamedAnimancerComponent _Animancer;
    [SerializeField] private AnimationClip _Walk;
    [SerializeField] private AnimationClip _Run;

    public void PlayIdle()
    {
        _Animancer.TryPlay("Humanoid-Idle");
    }

    public void PlayWalk()
    {
        var state = _Animancer.TryPlay("Humanoid-Walk");

        if (state == null)
            Debug.LogWarning("No state has been registered with 'Humanoid-Walk' as its key yet.");
    }

    public void InitializeWalkState()
    {
        _Animancer.States.Create(_Walk);
        Debug.Log("Created a state to play " + _Walk, this);
    }

    public void PlayRun()
    {
        _Animancer.Play(_Run);
    }
}

The code structure is a bit different from the other examples because the Idle and Walk animations are referenced by the NamedAnimancerComponent instead of by the script that actually tells them to play:

Recommendations

This example demonstrates what can be done with Animancer, but using string names as Keys to identify animations is not the recommended way of using Animancer for most situations. The following table summarises the main advantages and disadvantages of using names compared to using AnimationClips directly (or Transitions).

Advantages Disadvantages
  • The logic for playing animations can be entirely separate from the place you define which animations the character has. Though you can easily organize your code to achieve the same thing without using strings.
  • You can serialize a name string to store it in a save file or send it over a network.
  • Strings are a tiny bit less efficient than direct references (don't be afraid to use them, but that's why they aren't used internally by default).
  • If you rename an animation, you need to also update anywhere you have used its name in your code.
  • You can make spelling mistakes.

Setup

We start with the Basic Scene Setup, but without a ground plane because the initial "compressed" pose centers the character around the origin so he would be halfway into the ground at that point and we would rather show the full pose.

The first thing the script needs is a reference to the AnimancerComponent we want it to control. The component we will be using in the scene is actually a NamedAnimancerComponent which Inherits from the base AnimancerComponent. Inheritance means that a NamedAnimancerComponent is an AnimancerComponent so we could actually use either type for our field:

Animancer Component Named Animancer Component
[SerializeField]
private AnimancerComponent _Animancer;
[SerializeField]
private NamedAnimancerComponent _Animancer;
Can hold an AnimancerComponent. Can't hold an AnimancerComponent.
Can hold an NamedAnimancerComponent. Can hold an NamedAnimancerComponent.

In this example, we don't need to use any of the members of NamedAnimancerComponent in our script so either one would work fine, but we are relying on the fact that it will register animations by name so it is better to prevent a base AnimancerComponent from being assigned. The Component Types page explains the differences between them in more detail.

Startup

The NamedAnimancerComponent is set up with the Humanoid-Idle animation in its Animations list and Play Automatically disabled. This means that when enter Play Mode you can see in the Inspector that it creates a state for that animation but it isn't playing and its Weight is at 0. Since the character is using a Humanoid Rig, having no animations with any weight puts it into a "compressed" or "hunched over" pose according to the muscle limits defined in the Avatar configuration.

Idle

public void PlayIdle()
{
    _Animancer.TryPlay("Humanoid-Idle");
}

This method and all the others in this example are set up to be called by UI Buttons.

Since the Humanoid-Idle animation already has a state created for it (because it is in the Animations list), we are able to immediately play it using its name without our example script needing an actual reference to that AnimationClip.

Walk

public void PlayWalk()
{
    var state = _Animancer.TryPlay("Humanoid-Walk");

    if (state == null)
        Debug.LogWarning("No state has been registered with 'Humanoid-Walk' as its key yet.");
}

The Humanoid-Walk animation isn't in the Animations list, meaning that if we try to play it by name it can't know what we actually want it to play so the TryPlay method will return null.

To actually get it to work, the script needs a reference to the animation (AnimationClip _Walk) so it can create a state for it:

public void InitializeWalkState()
{
    _Animancer.States.Create(_Walk);
    Debug.Log("Created a state to play " + _Walk, this);
}

We could specify a custom Key when calling Create, but since we aren't it will determine the key using the GetKey method (which uses the animation's name because it's a NamedAnimancerComponent).

This would allow you to register your animations in one script and play by name in others.

Creating the state doesn't immediately do anything to the character, but once it is created we can play it by name just like we did with the Humanoid-Idle.

Run

public void PlayRun()
{
    _Animancer.Play(_Run);
}

The Humanoid-Run animation isn't in the Animations list either, but we have a reference to it (AnimationClip _Run) so we can just call _Animancer.Play(_Run); to show that we can still use direct references in a NamedAnimancerComponent where we have been using string names so far.

Inspector

You can see in the Inspector that despite being created in different ways, all of the states have been registered using their names as Keys where they would normally just show their AnimationClip because it is being used as its own key.

Name Keys Regular AnimationClip Keys