The first time you play an AnimationClip
or Transition on each character, Animancer creates an AnimancerState
for it and registers it in an internal Dictionary using the object you used to play it as its AnimancerState.Key
so that it can reuse that same state later on if you play the same thing again.
void KeysExample(AnimancerComponent animancer, AnimationClip clip)
{
// Play something.
AnimancerState firstState = animancer.Play(clip);
// Play the same thing again later.
AnimancerState secondState = animancer.Play(clip);
// The same state is used both times.
Debug.Log(firstState == secondState);// True.
// The state's Key is the AnimationClip or Transition that created it.
Debug.Log(firstState.Key == clip);// True.
}
Custom Keys
You can assign any object
as a state's Key
when creating it or by simply setting its Key
property and then use AnimancerComponent.TryPlay
to play it with the Key
to potentially keep the system that creates the state separate from the system that plays it.
void KeysExample(AnimancerComponent animancer, AnimationClip clip)
{
// Trying to play an animation before registering it does nothing (and returns null).
animancer.TryPlay("Attack");
// But if you create a state with a key first, then you only need that key to play it later on.
animancer.States.Create("Attack", clip);
animancer.TryPlay("Attack");
// Or you can create the state and set its key manually:
ClipState state = new ClipState(clip);
state.Key = "Attack";
animancer.TryPlay("Attack");// This won't work because the state isn't connected to anything yet.
animancer.Layers[0].AddChild(state);// Now the state is connected and registered with its Key.
animancer.TryPlay("Attack");
}
- You don't need to set the
AnimancerState.Key
if you don't want to. You can simply create anew ClipState
(or whatever type of state you want) and keep a reference to it for when you want to use it. - The
NamedAnimancerComponent
overrides itsGetKey
method to use the clip'sname
instead of theAnimationClip
itself. So callinganimancer.Play(clip)
uses thename
to lookup the state, but you can also pre-register the clip on startup by adding it to theAnimations
array in the Inspector or callinganimancer.States.GetOrCreate(clip)
so that later on you can callanimancer.Play("Animation Name")
in any script without a direct reference to theAnimationClip
. - If you want to have multiple states playing the same clip you will need to register them all with different keys (or no keys).
FadeMode.FromStart
uses this to fade a clip out while fading another copy of it in at the same time.
Enum Keys
Unfortunately, since object
is a Reference Type, using a Value Type like an enum
in those methods implicitly creates a new object
to hold the value. This is called Boxing and has a notable impact on performance, particularly since the new object
is immediately discarded after the call and needs to be Garbage Collected. This doesn't mean enums shouldn't be used, just that you should be aware of the inefficiency.
Object Keys
Another approach is to use actual object
s as keys. Rather than an enum
you could make a class
like this:
public static class CharacterAction
{
public static readonly object Idle = new();
public static readonly object Walk = new();
public static readonly object Run = new();
}
Those object
s will not actually do anything on their own but can be used as keys in a similar fashion to an enum: animancer.States.Create(CharacterAction.Walk, _Walk);
.
Component Keys
If a script only has one animation that it will play, it could use itself as the key, so a Walk
script could create a state with animancer.States.Create(this, _Walk);
and play it with animancer.Play(this)
. That will not work if it is actually a Movement
script that handles both Walk and Run animations as separate states though.