Animancer v8.0 is now available for Alpha Testing

Animancer v8.0

This page was last updated 2024-07-21

Estimated Release 2024-??-??

Currently available for testing.

Upgrade Guide

See the Animancer v7.0 Upgrade Guide if you're upgrading from a version older than that, then follow the new Upgrade Guide for this version.

For the first time ever, Animancer v8.0 will be a paid upgrade.

Purchases after 2024-05-01 can upgrade for free.

Older purchasers will receive a 50% discount.

See the Upgrade Guide page for details.

Major Features

Transition Libraries

Transition Libraries are a new feature which allows you to look up transitions by name and modify what specific transitions look like depending on the character's previous state. Unlike Animator Controllers, libraries don't contain any logic for managing what a character can do, you still tell Animancer to play something and it will still play, but a library might modify the transition's fade duration. Libraries are also fully open and modifiable at runtime.

There are 3 main library classes:

Class Purpose
TransitionLibraryDefinition The serializable form of a library which is used to create a TransitionLibrary at runtime.
TransitionLibrary The runtime form of a library which is optimised for efficiently looking up transitions.
TransitionLibraryAsset A ScriptableObject which stores a TransitionLibraryDefinition and creates a TransitionLibrary from it.

  • AnimancerComponents have a new Transitions field to put it in so anything you try to play will check the library for modifications:

  • The window keeps its own copy of the library asset being edited. The buttons in the top right allow you to Revert your changes, Apply your changes to the target asset, or Automatically apply any changes as soon as you make them.
  • The main view is a table of transitions where each cell contains the fade duration of a particular combination (from row to column).
  • Cells with fade duration modifiers are shown in Bold. Otherwise, the fade duration for that combination will default to whatever is specified in the Transition Asset as if you had played it without the library.
  • You can drag and drop any Transition Asset into the window to add it to the library or use the Create Transition button to make a new one.
  • You can drag transitions in the window to rearrange them.
  • Selecting a cell highlights its row and column in blue and hovering over a cell highlights them in green.
  • Selecting a cell also shows its details in the Inspector with an interactive preview of that particular transition combination:

  • In the top left of the window is a dropdown menu to select a different page to view.
  • Currently, the only other page is Transition Aliases where you can specify additional names which can be used to look up transitions.

  • The Serialization Sample demonstrates an additional feature of libraries:
    • Having all your animations registered in a centralised location means they can each be represented by an int index which can be easily serialized.
    • The sample uses that to save the character's current animation details to a file and load them back later.
    • But the real use case for this would be for networking, which Animancer's flexible decentralised structure otherwise makes difficult.

Weighted Mask Layers

The experimental Weighted Mask Layers system has been turned into a proper feature. It allows layers to be masked so they control some bones but not others just like the standard AvatarMask system, but with more detail because you can control the Weight of each individual bone instead of only turning them on or off. It also supports fading between different sets of Weights over time.

  1. Add a WeightedMaskLayers Component:

  1. Click its Edit button to open a window where you can configure it.

  1. Use the ? column to select the objects you want to include in the mask.
  2. Use the Add Group button down the bottom to add as many groups as you want.
  3. For each object and group, enter the Weight you want the object to have when that group is active.
  • 1 is the same as including the object in an AvatarMask, i.e. Layer 1 will fully control the object.
  • 0 is the same as excluding the object from an AvatarMask, i.e. Layer 0 will fully control the object.
  • Values in between will interpolate between both layers.
  1. In code if you want to change the current Weight group you can get a reference to the WeightedMaskLayers component and call SetWeights(groupIndex) or FadeWeights(groupIndex, fadeDuration).

#154 and #328

Known Limitations:

  • It only supports 2 layers (Base + 1).
  • It only supports override blending (not additive).
  • These limitations could be removed with further development if enough users request it.

String References and Assets

strings are often a very convenient type which can make systems easy to use, but also have notable downsides such as being inefficient to compare and hard to refactor.

  • The Event Names system used to be based on strings and the new Event Binding and Parameter Binding systems would have been as well, so a new system has been implemented to avoid those downsides.
  • StringReference is a simple class which contains a string and is kept in a dictionary so that everything which calls StringReference.Get for a given string will be given the exact same reference.
    • This allows the system to check if two references are equal much faster by using a single equality instruction instead of potentially needing to check if every individual character is equal in two strings.
    • StringReference has an implicit conversion from string, meaning that any method which takes a StringReference parameter can also be given a regular string. That's less efficient though, because it needs to look up the reference in the dictionary every time, so it's much more efficient to cache the StringReference yourself beforehand, for example:
// This is an implicit conversion from string to StringReference:
public static readonly StringReference EventName = "Fire";

// It actually does this internally:
public static readonly StringReference EventName = StringReference.Get("Fire");

// Or you can reference a StringAsset in a serialized field:
[SerializeField] private StringAsset _Name;
  • StringAsset is a ScriptableObject which contains a StringReference initialized from its asset name.
    • This allows values to be managed more reliably and consistently referenced in multiple places without risking spelling mistakes each time or making it hard to rename things.
    • StringAssets can be created via Assets/Create/Animancer/String Asset or by using the New button in the Inspector (see below).
    • StringAsset fields normally show up in the Inspector like regular string fields, but if you move your mouse over them they change to let you pick an asset or use several functions:
      • New - If the field is empty, this button will create a new StringAsset and ask where you want to save it.
      • C - If the field has a reference, this button will copy its name to the clipboard.
      • X - If the field has a reference, this button will remove it.
Normal Appearance Mouse Hover

Animancer Events

Animancer Events have been reworked in several different ways, some of which would result in data loss if you don't run the Serialized Data Migration tool explained in the Upgrade Guide.

Why Rework Event Sharing?

There are two common sources of conflicts that arise when using events:

  • Event ownership - when a Transition is shared by multiple characters.
  • State ownership - when multiple scripts on the same character try to use the same state without realising.

Animancer Events were originally designed to avoid those issues by being automatically cleared from a state whenever you played something else. That system was good for safety, but bad for efficiency because you had to either spend processing time re-configuring all the events every time you played an animation or spend development time configuring and storing the events separately so they could be assigned to the state every time you played it.

  • Transitions solved this by storing their own events which you can configure on startup so they can simply assign the events to the state when played.
  • But any transitions shared by multiple character instances (particularly Transition Assets) couldn't be used in that way because all characters would overwrite each other's changes to the same event sequence.
  • The UnShared transition system attempted to solve that, but it was confusing to new users and only usable in limited situations so it has now been removed.
  • OptionalWarning.DuplicateEvent and OverwriteEvent tried to at least detect cases where multiple characters were adding their own copy of the same callback, but even that had limited usefulness so they have been removed.
  • The old system was also confusing to many new users who did not expect their events to be cleared.

Persistent Owned Events

For the reasons explained above, the new system doesn't automatically clear events whenever anything is played, encourages users to configure their events when a state is first created, and discourages sharing states between scripts.

This was achieved by splitting the AnimancerState.Events property into 4 different members:


  1. bool Events(object owner, out AnimancerEvent.Sequence events)
  • The first time this method is called on a state, it will create a clone of whatever event sequence had already been assigned (or just a new sequence if none was assigned yet).
    • Then it returns true to indicate that the caller should now configure the given events as they see fit.
    • On subsequent calls the state already owns its events so this method will do nothing and return false.
  • It also calls AnimancerState.AssertOwnership which assigns the state's owner or throws an exception if it already had a different owner.

The recommended usage looks like this:

public static readonly StringReference EventName = "Event Name";

...

AnimancerState state = animancerComponent.Play(animation);
if (state.Events(this, out AnimancerEvent.Sequence events))
{
    events.SetCallback(EventName, OnAnimationEvent);
    events.OnEnd = OnAnimationEnded;
}

  1. AnimancerEvent.Sequence Events(object owner)
  • This method does exactly the same thing as the one above, except that it returns the event sequence and doesn't indicate whether ownership was only just claimed or not.
  • This allows for simpler usage in situations where you only need to set the End Event:
AnimancerState state = animancerComponent.Play(animation);
state.Events(this).OnEnd ??= OnAnimationEnded;
  • The ??= means it will only assign the callback if it was previously null which avoids the performance cost of allocating a new callback every time.
  • This is why the owner parameter to claim state ownership is so important, because without it you could run into a situation where one script assigns its callback then another script tries to use the same state but never ends up assigning its own callback.

  1. OwnedEvents
  • This property enforces event ownership like the above methods, but ignores state ownership so it should generally only be used in situations where you have already detected that multiple scripts are sharing the state.

  1. SharedEvents
  • This property gives direct access to whatever events have been assigned, meaning it will be null by default and doesn't have any of the safety restrictions of the other options.

  • These changes avoid the need for the UnShared transition system, so it has been removed because it was confusing to many users and didn't cover many common use-cases. #261
  • In order to reduce the chance of multiple scripts sharing the same state, each ClipTransition will now create its own state instead of having them share a state if they have the same AnimationClip.
  • In order to avoid overwriting the state's owned events on subsequent plays, Transitions will now only assign their Events when they first create a state instead of re-assigning them every time they are played (which was necessary when the events would have been automatically cleared from the state).
  • ExitEvents have also been reworked to be based around keeping the same instance in a field instead of clearing and object pooling instances.
  • One major difference between Animancer Events and Unity's inbuilt Animation Events is that Animancer Events aren't triggered on a state while it fades out.
    • The old system enforced this inherently because starting a fade out would have cleared the state's events.
    • The new system has the same behaviour by default, which can be disabled by setting the static AnimancerState.RaiseEventsDuringFadeOut = true;.

Event Names

Animancer Events can optionally be given names which can then be used to identify them in code. They previously used regular strings which made the system simple to use, but had several downsides such as being inefficient and hard to refactor.

Those strings have been replaced by String References and Assets (StringAssets in the serialized data and StringReferences in the runtime data).

Using the [EventNames] attribute now shows an info icon next to the name field with a tooltip listing all the expected names. If an unexpected name is selected, it will change to a warning icon.

This is one of the changes that would result in data loss if you don't run the Serialized Data Migration tool explained in the Upgrade Guide.

#264

Event Binding

In many cases, being able to set up event timings in the Inspector while previewing the animation and then assign callbacks to those events in code based on their names is a great workflow (and that's not changing). But in some cases that workflow isn't ideal or even viable, such as if you're playing an animation in a Transition Library by name which means you don't even know what's going to be played so you can't be sure what events you need to look for.

The solution to this is the new AnimancerComponent.Events property, which is a dictionary of String Reference names mapped to callbacks. Whenever an event with a name but no callback is triggered, it will look in the dictionary for a callback bound to its name. If an event has no callback in either location, it will still trigger OptionalWarning.UselessEvent to let you know that something is likely configured incorrectly. This is closer to the way Unity's inbuilt Animation Events work, except that it's still using delegates for flexibility instead of requiring a method name to match the event name in a component attached to the same GameObject as the Animator.

For example, here's a simple script that expects its transition to have events with the name "Footstep" set up in the Inspector:

public class FootstepWalkExample : MonoBehaviour
{
    public static readonly StringReference FootstepEvent = "Footstep";
    
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField, EventNames] private ClipTransition _Walk;
    
    protected virtual void OnEnable()
    {
        _Walk.Events.SetCallbacks(FootstepEvent, PlayFootstepSound);
    
        _Animancer.Play(_Walk);
    }
    
    private void PlayFootstepSound() { }
}

Note the [EventNames] attribute. Since it isn't being given any names explicitly, it will look for static fields in the class it's in.

That's a nice simple script which would work perfectly fine on its own, but what if you have other animations in other scripts that also want to have footstep events? Obviously you could connect all of them to a central script which manages the footsteps, but that sort of thing can start turning your code base into a tangled mess of interconnected dependencies. Instead, the new Event Binding system would let you split those responsibilities into two scripts like this:

public class FootstepManager : MonoBehaviour
{
    public static readonly StringReference FootstepEvent = "Footstep";
    
    [SerializeField] private AnimancerComponent _Animancer;
    
    protected virtual void OnEnable()
    {
        _Animancer.Events.Set(FootstepEvent, PlayFootstepSound);
    }
    
    private void PlayFootstepSound() { }
}

public class WalkExample : MonoBehaviour
{
    [SerializeField] private AnimancerComponent _Animancer;
    [SerializeField] private ClipTransition _Walk;
    
    protected virtual void OnEnable()
    {
        _Animancer.Play(_Walk);
    }
}

The FootstepManager script registers its PlayFootstepSound method to be called by any event with the name "Footstep" in any animation and the WalkExample script doesn't need to know anything about footsteps, it's simply responsible for playing its animation and managing the mechanics of walking. It took a bit more code, but the system is now more flexible and modular so it should be easier to extend and maintain as your systems grow in complexity.

The event binding dictionary is shown in the Live Inspector (unless you leave it empty):

Event Callbacks

On its own, the new Event Binding system would have had one major drawback compared to Unity's inbuilt Animation Events: the inability to specify parameters in the Inspector. In the above example, the "Footstep" events have no way to indicate which foot they're referring to. You could give each foot a different event name, but that's not very convenient and still doesn't allow other parameter types like floats or asset references.

Instead of solving that issue by adding extra fields for several specific parameter types (like Animation Events do), it has been addressed by changing the serialized event callback field from a hard coded UnityEvent to a [SerializeReference] field which can hold anything that implements IInvokable (a simple interface with an Invoke() method).

  • Animancer includes its own UnityEvent class which simply inherits from Unity's regular one and implements IInvokable so it can be used for event callbacks exactly the same as before.
    • Since regular serialized fields store their data differently to [SerializeReference] fields, this is one of the changes that would result in data loss if you don't run the Serialized Data Migration tool explained in the Upgrade Guide.
    • It also supports UltEvents in the same way, which is much better than the old system where you could only use UnityEvents or UltEvents and swapping between them would lose all your event data.
  • The parameter issue is handled by AnimancerEvent.Parameter<T> which is an IInvokable that sets the static AnimancerEvent.CurrentParameter property then invokes the bound callback.
    • Any method can access the AnimancerEvent.CurrentParameter during an event (it's cleared afterwards).
    • There are also several methods in the Event Binding dictionary for binding callbacks with a parameter which can be used like this:
public static readonly StringReference FootstepEvent = "Footstep";

[SerializeField] private AnimancerComponent _Animancer;

protected virtual void OnEnable()
{
    _Animancer.Events.AddNew<AudioSource>(FootstepEvent, PlaySound);
}

public void PlaySound(AudioSource audioSource) { }
  • That method would be automatically given its value from the event's callback parameter set in the Inspector (or an error if it doesn't have a parameter).
  • Animancer includes several common parameter types: bool, double, float, int, long, Object, string.
  • You can easily add a new parameter type by creating a serializable class like this:
[Serializable] public class ParameterThing : Parameter<Thing> { }
// Inherit from ParameterBoxed<T> instead if Thing is a struct or enum.
  • Simply having that class in your project would make it selectable as a callback type.
  • You could also create a classs that implements IInvokable to direcly use it as the callback.

End Event Time

  • Animancer Lite now allows you to change the time of End Events. Most of the new features are Pro-Only so this restriction has been removed.

Parameters

Like with the Event Binding system, being able to directly control the parameters of a Mixer State or Controller State is often great, but can be really inconvenient if you don't have a strongly typed reference to the state such as if you're using Transition Libraries or even just Nested Mixers.

The solution is also quite similar: a new AnimancerComponent.Parameters property containing a dictionary of parameter values registered by name which other systems can get, set, and listen for changes to.

Mixer Parameters

  • The Inspector shows the Parameters dictionary below all the States:

  • You can then control the parameters in the dictionary like this (instead of directly on the state):
animancerComponent.Parameters.SetValue(SpeedParameter, value);
  • This is a one-way link. Directly changing the Mixer parameters will not affect the Animancer Parameter.
  • This is all completely optional. You can still directly set the mixerState.Parameter as before.

#257

Controller Parameters

Controller States and ControllerTransitions can also have their parameters bound to Animancer's parameters, though it's a bit more complicated than with Mixers.

  • When bound, any changes to the Animancer Parameter will update the corresponding parameter in the Animator Controller.
    • This is a one-way link. Changes to parameters inside an Animator Controller will not affect Animancer Parameters.
  • The simplest usage is to simply enable Bind All Parameters to have it bind every parameter in the Animator Controller to an Animancer Parameter with the same name and type.

  • Otherwise, if you put anything in the Bindings array the Bind All Parameters toggle becomes Rebind Names.
Rebind Names Disabled Rebind Names Enabled
Each name in the array will bind the Animator Controller parameter with that name to an Animancer Parameter with the same name. The array is split into two columns with the left specifying the name of a parameter in the Animator Controller and the right specifying the Animancer Parameter name you want to bind it to.
  • Note that the Bindings array contains String Assets (not regular strings).

Linear Blending Sample

The Linear Blending Sample previously contained two very similar scripts (LinearBlendTreeLocomotion and LinearMixerLocomotion) to demonstrate the same thing with both a Blend Tree inside an Animator Controller and with a Linear Mixer.

Being able to bind parameters in both types of states to the same Animancer Parameters means that they could now be handled by just one script, though it has still been split into two with separate responsibilities:

  • PlayTransitionAssetOnEnable does exactly what the name says.
  • FloatParameterWrapper is the real point of the sample. It demonstrates how to get and set an Animancer Parameter.

The sample still consists of two scripts, but they're now much more useful because they only have one responsibility each so they could potentially be used in other situations too.

Fade Groups

Previously when transitioning between states, every state would fade independently. You could have one state fading out and another fading in but they weren't explicitly linked to each other. The old CustomFade system had to be built around that by cancelling regular fades and managing them on its own as a group.

Those systems have been unified so all fades are managed as a FadeGroup (even if it only has one thing in it such as when fading out a layer).

  • This is slightly more efficient in most cases because it calculates and applies the weights of multiple states in one go instead of independently.
  • It also makes it easier to do things like check what animation is fading out, though that isn't a particularly common use case.
  • The FadeGroup.Easing property allows you to apply a custom curve to the fade progression like the old CustomFade system.
state = animancerClone.Play(animation, 0.25f);
state.FadeGroup.SetEasing(Easing.Function.SineInOut);
  • SetEasing is an extension method which will do nothing if the FadeGroup is null (such as if the animation was already faded in so it didn't start another fade) and it also accepts the Easing.Function enum as a parameter instead of only a Func<float, float> delegate.
  • Active FadeGroups are shown in the Inspector if you have the Show Internal Details Display Option enabled.

Live Inspector

The AnimancerComponent Inspector in Play Mode has been given quite a few improvements to its visuals and rendering performance.

Old Inspector New Inspector
  • The Live Inspector has been moved out of the AnimancerComponent's Inspector panel to an interactive preview at the bottom of the Inspector which can be resized, hidden, or even popped out to a separate window.

  • The header object field of each state is now just a flat box instead of an actual object field to reduce the unnecessary visual noise.
  • While a state is fading, its time bar shows a diagonal line indicating where its Weight will go over time.
  • Changed the Weight labels and time lines to be coloured based on their effective weight instead of just the raw weight, meaning that a - Mixers no longer show their children unless the mixer's details are expanded.
  • Added the ability to Alt + Click a state to expand/collapse all of its siblings as well.
  • Added event time indicators to states in the Inspector for Animancer Events and Animation Events.
  • Added the ability to ping states in the Inspector by clicking on fields that reference them.
  • Changed states to not show their Key in the header unless the same MainObject is used by multiple states.
  • Added a hover highlight to the animation binding warning icon so it looks more like a button.
  • Changed Mixers to ignore the "Auto Normalize Weights" Display Option since they're usually used for things that don't require the weights to add up to 1.
  • Added a "Repaint Every Frame" toggle to the AnimancerComponent Inspector when there are 10 or more Components on the GameObject because Unity won't do it by default to save performance.
  • Added null reference detection to the Animation Type warning system to identify animations with missing Sprites.

Transition Inspector

Many new users have trouble figuring out how to get animations to restart when you play them instead of continuing from their current time (despite the topic being covered many times in the documentation and code comments and tooltips). So the Inspector for Transitions has been changed to make it clearer. When the Speed or Start Time toggle is disabled, the regular fields will be replaced with a text box saying that it will continue at the current value which should hopefully make it obvious that you can tell it not to do that using the toggle.

Shared References

The Polymorphic Drawer system now lets you properly view and manage references that are shared by multiple fields.

For example, say you have 3 [SerializeReference] ClipTransition fields A, B, and C:

If A already has a value and you go to create an object for B, the menu will have a Shared Reference sub-menu where you can give it the same reference as A:

While A and B are referencing the same object, they will show a link toggle:

  • It has a randomly generated colour for the object so if other fields have shared references to other objects they will hopefully have a different colour.
  • It has a tooltip listing all the fields sharing that object.
  • Clicking it will show connection lines between the fields sharing that object.

Tools

Several of the Animancer Tools have been improved:

  • Pack Textures:
    • Fixed compile errors if Unity's Built-in Image Conversion module isn't present. Now the tool will simply display an error message.
  • Rename Sprites:
    • Merged the Sprites and Names into a single column.
    • Added thumbnails so you can see what you're working with.
    • Added a First Index field so you can choose to start numbering at 0 or 1 or whatever number you want. #316
    • Removed the New Names field.
    • Instead, anything you enter in a Sprite's name field will apply to it and all following Sprites until the next name you enter. For example:
Walk Down Walk Down and Left

First you type Mage-Walk-Down- for the first Sprite's name.

The First Index number is automatically added to the end and every Sprite after that is given the same name with the next number.

Because there are more than 10 Sprites (see the scroll bar) it uses 2 digits for all the numbers (i.e. starting at "01" instead of just "1").

Then you go to the 5th Sprite and call it Mage-Walk-Left-.

Now everything after it is using that name while the first 4 continue using Mage-Walk-Down- with a 1 digit suffix because there's only 4 of them now (and the Minimum Digits is 1).

The two names you've entered are shown in bold while the others which are following your naming convention are in italics.

  • Generate Sprite Animations:
    • Added fields to customize the animation being generated (if you want to animate something other than a SpriteRenderer): #283
      • Hierarchy Path: the name of each object in the Hierarchy below the Animator down to the object with the component you want to animate.
      • Target Type: the Assembly Qualified Name of the Component type on that object.
      • Property Name: the name of the field on that Component.
    • Added thumbnails and animation previews.

Animation Rigging

Unity's Animation Rigging package has always worked with Animancer but has several limitations which are explained on that page.

The Resetting Properties issue now has a new workaround which is much more usable than the previous workarounds. The PlayableOutputRefresher page explains how to use it.

Samples

The Samples are currently being worked on as explained in the Release Timeline

Now that Animancer has become a package, the Examples have been re-branded as Samples and reorganised to follow Unity's guidelines for package samples. That means they are hidden by default and can be imported into your project as explained on the Samples page.

General Changes:

  • Replaced the old DefaultHumanoid character model with AnimancerHumanoid.
  • Changed the coding conventions for sample scripts:
    • Classes are no longer sealed.
    • MonoBehaviour messages are protected virtual instead of private to encourage good practices in users as explained here.
    • Scripts use explicit variable types.

Specific Changes:

Minor Features

  • Added AnimancerLayer.ActiveStates to efficiently track states that are playing or have any Weight or TargetWeight.
    • Changed AnimancerState.IsActive to include the current Weight so it corresponds to the state's presence in the ActiveStates list.
    • Added AnimancerState.IsCurrent with the old behaviour of IsActive (just IsPlaying and TargetWeight > 0).
    • Optimized various operations which previously iterated through all states in a layer to now only go through the active states. For example, playing a new animation only needs to stop or fade out the other animations which were actually playing instead of wasting time stopping states which were alreay stopped.
  • Added a reflection based system for associating CustomGUI drawers with their target objects.
    • Added support for custom CustomGUI on internal details (visible in the AnimancerComponent Inspector when the "Show Internal Details" display setting is on).
    • Added FadeGroup.Drawer.
    • Added EventDispatcherDrawer for drawing event dispatchers in the Post-Updatables list.
  • Added AnimancerEvent.Sequence.SetCallbacks, AddCallbacks, and RemoveCallbacks for controlling all events with the given name instead of only the first one. #263
  • Added AnimancerEvent.Dispatcher.MaximumFullLoopCount to prevent a short and fast looping animation from invoking all its events too many times every frame. It's still unlikely that you'll get useful behaviour from invoking so many events, but this should help limit how badly it can lock up the app at least.
  • Added MixerState.NormalizedParameter for treating the parameter as a value between 0 and 1 regardless of the actual thresholds assigned.
  • Added IParametizedState to simplify parameter drawing in the Inspector for Mixers and ControllerStates.
  • Added AnimancerGraph.DestroyPlayable in case you want to destroy it without destroying the whole graph (in case the graph was owned by another system).
  • Added [AnimancerHelpUrl] attribute which uses a type reference to generate the URL instead of needing to hard code the string.
  • Added ClipTransitionSequence.TryGetCumulativeTime.
  • Added oldValue as a parameter to IPolymorphicReset.Reset so it can potentially copy over things based on specifically known previous types.
  • Added Normalized Start Time field to SoloAnimation.
  • Added OptionalWarning.EventPlayMismatch to help detect event registration issues with shared Transitions.
  • Added OptionalWarning.DynamicAnimation which warns if you try to play an animation that isn't saved as an asset because animations can't be created dynamically at runtime (except Legacy animations which Animancer can't use).
  • Added OptionalWarning.ExpectFade which warns if a state created by a transition with a fade is then played without a fade. This usually happens for beginners who don't realise that Play(state) won't have any fade and they should use Play(transition).
  • Added CloneContext system for cloning complex object trees and translating their internal references to the corresponding clones.
  • Added TimeSynchronizer to replace the old TimeSynchronizationGroup. #250

Improvements

  • Improved Polymorphic Drawer to be able to properly draw objects with custom drawers for their type.
  • Improved Object Pool logging to log the contents of all pools when the Play Mode state changes.
  • Improved ManualMixerState.ToString to put the mixer type first and be cached separately from the DebugName so it doesn't appear as a string label in the Inspector.
  • Improved SimpleTimer:
    • Changed it to track long ticks instead of double seconds.
    • Added an optional format string in case more or less than 3 decimal places of precision is needed. Can also set it to null for it to use the ticks in its strings instead of seconds.
  • Improved the animation bindings warning icons:
    • Optimized their drawing to be more efficient.
    • Removed the loading icons while the bindings are being checked since they will usually not need to show a warning anyway.
    • Removed the ITransition interfaces nested inside each state type because they're no longer necessary.
  • Improved the AppendDescription methods:
    • Added IHasDescription with standard extension methods.
    • Added IUpdatable and IDisposable descriptions to the text if they implement IHasDescription. This is used by FadeGroups.
    • Added AnimancerUtilities.AppendField for easily appending a named value.
    • Pulled AnimancerState.GetPath up to AnimancerNode.
    • Changed various inter-node references to use GetPath to make it easier to tell what it's referring to.
    • Improved AnimancerGraph.AppendDescription to include Orphan States, i.e. states registered in the dictionary but with no parent.
  • Improved various icon usages. In particular, replaced all "x" buttons with an eraser icon.
  • Optimized ClipState.Length and IsLooping to be retrieved from the AnimationClip in the constructor and cached because getting them from the AnimationClip allocaes some garbage every time.
  • Optimized Animancer Events by adding AnimancerState.GetEventDispatchInfo to get all the required details from the state in one call, which is much more efficient (especially for Mixers).
  • Optimized Mixers to cache their IsLooping property instead of checking if any child is looping every frame (which would have been recursive for nested Mixers).
  • Optimized the AnimancerState.NormalizedTimeD getter to only get the Length once.
  • Optimized Object.name usage by adding ObjectNameCache since it allocates garbage every time it's accessed.
    • You can define ANIMANCER_DISABLE_NAME_CACHE as a compilation symbol to disable this system.

Changes

  • Changed the "total Weight of all states in this layer does not equal 1" Inspector warning to appear on all layers instead of only the Base Layer. If you want to smoothly stop a layer you need to fade out the layer itself, not its states.
  • Changed all states to stay at Time = 0 after their first frame so that the first time they're played is consistent with subsequent re-plays.
  • Changed InputBuffer to replace the state machine's ForceSetDefaultState delegate to try to enter the buffered state first.
    • Changed the Weapons example's AttackState to use this feature for attack combos so it doesn't need to return to Idle for one frame between attacks.
  • Changed AnimancerLayers to use a list-like Capacity which doubles whenever it needs to increase instead of simply incrementing.
  • Changed the AnimancerLayer.MaxCloneCount setter to public.
  • Changed ITransition<T> to support covariance.
  • Changed ManagedReference handling to use the managedReferenceValue property.
  • Changed AnimancerEvent.Sequence.CopyFrom to not resize the Names array if it's already larger than necessary.
  • Changed AnimancerSettings to use dynamic [SerializeReference] fields so it's more modular.
  • Changed ICloneable to be generic.
  • Changed ControllerState.ActionsOnStop to not call GatherDefaultStates so it only gets called by CreatePlayable.
  • Changed AnimancerTransition.Events to virtual.
  • Changed AnimancerGraph.KeepChildrenConnected to always default to false instead of true for Generic Rigs because it no longer seems to give them better performance.
  • Changed OptionalWarning.UnusedNode to not log for nodes with a parent.
  • Changed AnimancerNode.CopyFrom and all inherited overloads to public.
  • Renamed ValidateAssertNotLegacy to AssertAnimationClip and added a null check to give a better exception.
  • Moved the default AnimancerSettings location to the root Assets folder and added an Inspector message explaining that you can move it anywhere but should keep it outside the Animancer folder so you keep your settings if you ever delete and update Animancer.
  • Moved the Speed field from child transition classes up to the base AnimancerTransition since all states now support it (ControllerState didn't previously).
    • Removed OptionalWarning.UnsupportedSpeed for the same reason.
  • Simplified the AnimancerState parenting system.
    • AnimancerState.SetParent no longer takes a manually specified index. Both Layers and Mixers will add new states to the end of their list.
    • Removed AnimancerNode.AddChild since it's now unnecessary. Just use child.SetParent.
  • Split AnimancerReflection out of AnimancerUtilities and AnimancerEditorUtilities.
  • Split AnimancerLayerMixerList out of AnimancerLayerList.

Removals

  • Removed the classes derived from AnimancerTransitionAssetBase for each individual transition type except TransitionAsset since its [SerializeReference] can hold any of them without changing the asset type.
  • Removed FastEnumerator members which modified the list because they exposed unexpected vulnerabilities since enumerators aren't expected to allow modifications.
  • Removed the Inspector warning "A state is playing at weight 0" because that's actually supported now.
  • Removed AnimancerState.DelayedPause and integrated its functionality into ControllerState directly since that's the only place it was used.
  • Removed AnimancerGUI.GetNarrowText since it wasn't really useful and added unnecessary complexity.
  • Removed FastComparer and FastEqualityComperer because they weren't notably faster and were sometimes slower.
  • Removed OptionalWarning.LockedEvents since you would need to explicitly access state.SharedEvents to run into the issues it warns about.
  • Removed IValidatable and replaced its usage with AnimancerReflection.TryInvoke.
  • Removed LazyStack and replaced its usage with manual list management since there weren't many uses.

Fixes

  • Fixed the ReadMe to only log that a new version is available once per Unity Editor session instead of logging again every domain reload.
  • Fixed fading to include the root AnimancerGraph.Speed in the fade time progression.
  • Fixed AnimancerEditorUtilities.PlayModeState to be properly initialized in Edit Mode.
  • Fixed AnimancerStateDictionary.GetEquivalentNode to connect a newly cloned state to the correct layer.
  • Fixed incorrect comment on AnimancerState.MoveTime and added more detail. It previously claimed that Animancer Events would be skipped, but that isn't true.
  • Fixed several incorrect usages of the component name in HybridAnimancerComponent. #297
  • Fixed Animancer Events to not start triggering every frame if you used one to re-play the animation that triggered it. #298
  • Fixed AnimancerStateDrawer to not break GUI control IDs after it.
  • Fixed the Live Inspector state foldout to properly clear the hot control when clicked.
  • Fixed TransitionDrawer indentation in Unity 2022.
  • Fixed TransitionDrawer to still show its foldout arrow in array fields even if thats the only field in the declaring type. #307
  • Fixed TransitionDrawer to still show its foldout arrow if the target Transition is in a serializable class.
  • Fixed TimeScale to do nothing when disabled.
  • Fixed AnimancerLayer.Mask to allow null to be assigned without allocating any garbage in case you want to set it from an unassigned serialized field or copy from another layer which has no mask. #303
  • Fixed IUpdatable usage to continue enumerating properly if an item is removed during an update before it has been updated.
  • Fixed AnimancerNode.MarkAsUsed to be properly Assert-Conditional.
  • Fixed SampleInput.WASD to work properly with the Play Mode Domain Reload disabled.
  • Fixed AnimancerGraph.InsertOutputPlayable to connect the correct playable.
  • Fixed AnimancerState.RecreatePlayable to retain its IK flags and connect the Playable to the parent if necessary.
  • Fixed AnimancerNodeDrawer to allow fades to be manually started in the Inspector.
  • Fixed the SpriteDataEditor.SpriteCount setter to initialize all the sprites instead of leaving them null.
  • Fixed the dummy event callback drawer to automatically expand a newly created item.
  • Moved the IPolymorphic implementation from ITransition to AnimancerTransition so it doesn't interfere with custom Object Field drawers (from Inspector Gadgets or any other system) on Transition Asset references.
  • Fixed PolymorphicDrawer to not draw the header line twice if it can't find another drawer for the target object type.
  • Fixed Mixer child weight calculation errors.
  • Fixed Mixer Time Synchronization to calculate the speed properly for nested Mixers.
  • Fixed Ctrl + Click on a Mixer child in the Inspector causing it to re-parent under the layer and play directly. Instead it will now just play the Mixer.
  • Fixed the Mixer Transition Inspector to not show a toggles on the Speed fields to disable them. #258
  • Fixed LinearMixerTransitionDrawer to not lose the text field being edited when a sorting warning appears or disappears. #343
  • Fixed PlayableAssetTransitionDrawer error when changing the Bindings count to 0.
  • Fixed ControllerState.GetStateInfo to return a default uninitialized state instead of giving an error if called before the Playable is initialized.
  • Fixed the Inspector for states with 0 length to show the time highlight bar across their whole area.
  • Fixed AnimancerGraph.CopyFrom to properly copy custom fades and do nothing if called on itself.
  • Fixed AnimancerLayer.CopyStatesFrom to reuse existing states instead of destroying and recreating them all.
  • Fixed AnimancerState cloning into a new graph uses the same Key.
  • Fixed AnimancerUtilities.TryGetIsLooping and TryGetLength to not cause exceptions if the given object is a destroyed AnimationClip. #342
  • Fixed Real Speed field in the Inspector to not cause drag events to be lost when it appears or disappears.
  • Fixed AnimancerGraphCleanup to work properly when the Play Mode Domain Reload is disabled.
    • Replaced OptionalWarning.CreateGraphWhileDisabled with a warning when AnimancerGraphCleanup is forced to clean up a graph that wasn't destroyed in Play Mode.
  • Fixed scripts to support API changes in Unity 6.
    • Rigidbody.velocity renamed to linearVelocity.
  • Fixed UnityVersionChecker.ExpectedAssemblyTarget used by Animancer Lite to warn if the wrong DLL is being used (meaning the user needs to re-download the correct version of Animancer for their version of Unity).
  • Fixed [EventNames(typeof(Something))] to include names in classes that Something inherits from. #353
  • Fixed various exceptions caused by having a Transition Assets without its Transition assigned.
  • Fixed TransitionDrawer to be able to draw object fields for Transition Assets.