Released 2020-01-28
Highlights
- The main public API has been entirely restructured:
- The
Play
,CrossFade
,CrossFadeFromStart
, andTransition
methods have all been unified asPlay
with fewer overall parameter combinations. - Layers are now treated as a proper collection. So instead of
animancer.LayerCount
,animancer.GetLayer(...)
, oranimancer.SetLayerAdditive(...)
, you now useanimancer.Layers.Count
,animancer.Layers[...]
, oranimancer.Layers.SetAdditive(...)
. - Same for states. So instead of
animancer.GetState(...)
you now useanimancer.States[...]
andanimancer.CurrentState
is nowanimancer.States.Current
. - Serializables are now called Transitions (i.e. you now use
ClipTransition
instead ofClipState.Serializable
).
- The
- [Pro-Only] New Animancer Event system for general events without needing to use Unity's Animation Events:
- You can specify events per-state instead of per-clip.
- You can add events and set callback delegates directly in code without needing to hook up magic strings to public methods.
- The
AnimancerState.OnEnd
callback has moved toAnimancerState.Events.OnEnd
and you can optionally specify a time for it instead of always being at the end of the clip.
- New Transition Preview Window allows you to preview your transitions on your character without entering Play Mode.
- Implemented Mixer Time Synchronization.
- New
PlayableAssetState
allows you to play Timeline assets in Animancer. - All transition types now have a corresponding Transition Asset type.
- Added support for Unity 2019.3 (most upgrades are fine, but that one broke a lot of things).
- Added Weapons example as well as instructions for downloading animations from Mixamo and configure their Import settings.
- Added a C# in Unity section to explain the fundamentals of programming in Unity for beginners. #7
Upgrade Guide
The main public API has been significantly restructured in several ways which will affect all users, so this section will help you fix the errors you get when upgrading a project from an earlier version.
Remember to always delete any older version of Animancer before upgrading.
Serialized Data
Some of the changes to serialized data structures will unfortunately cause certain values to be lost when upgrading so if you were using any of the following things you will need to set them again manually:
- The
AnimancerComponent.StopOnDisable
bool was previously serialized by theAnimator
component itself, but it has now been replaced by theAnimancerComponent.DisableAction
enum which is serialized in theAnimancerComponent
itself (and accessable via theActionOnDisable
property).Stop
andPause
correspond to the previoustrue
andfalse
, but there are now several other values too. ClipTransition.StartTime
(formerlyClipState.Serializable.StartTime
) is now always serialized as a normalized time value since the Inspector shows the value as both normalized time and seconds. So if you previously had the value set to seconds, it will now be incorrect.- Mixer Time Synchronization is now enabled by default for all mixers so they will give different results to before it was implemented (likely better results).
Playing and Fading
The AnimancerComponent.Play
, CrossFade
, CrossFadeFromStart
, and Transition
methods are now all called Play
. The Playing Animations page explains their differences.
In v3.1, AnimancerComponent
had several overloads each of Play
/CrossFade
/Transition
which were made even more complicated by the presence of default parameters for fadeDuration
and layerIndex
:
// Old Methods from v3.1:
Play(AnimationClip clip, int layerIndex = 0)
Play(AnimancerState state)
Play(object key)
// Note: replaced "DefaultFadeDuration" with just "Default" to fit everything on one line.
CrossFade(AnimationClip clip, float fadeDuration = Default, int layerIndex = 0)
CrossFade(AnimancerState state, float fadeDuration = Default)
CrossFade(object key, float fadeDuration = Default)
CrossFadeFromStart(AnimationClip clip, float fadeDuration = Default, int layerIndex = 0)
CrossFadeFromStart(AnimancerState state, float fadeDuration = Default, int layerIndex = 0)
CrossFadeFromStart(object key, float fadeDuration = Default, int layerIndex = 0)
Transition(ITransition transition, int layerIndex = 0)
The various default parameters meant that those methods had a total of 22 parameter combinations, making them rather unwieldy and confusing for new users.
This has been improved in several ways by v4.0:
- All of those methods are now called
Play
. - The Collections change allowed the
layerIndex
parameter to be removed (soPlay(clip, 1)
is nowLayers[1].Play(clip)
). - The new
FadeMode
enum controls how a fade actually works, which includes the oldCrossFadeFromStart
functionality and the ability to use the specifiedfadeDuration
as a portion of the clip length rather than raw seconds. See theFadeMode
API documentation for the details of each value. - This takes it down to only 12 parameter combinations:
// New Methods in v4.0:
// Play.
Play(AnimationClip clip)
Play(AnimancerState state)
Play(object key)
// CrossFade and CrossFadeFromStart.
Play(AnimationClip clip, float fadeDuration, FadeMode mode = FadeMode.FixedSpeed)
Play(AnimancerState state, float fadeDuration, FadeMode mode = FadeMode.FixedSpeed)
Play(object key, float fadeDuration, FadeMode mode = FadeMode.FixedSpeed)
// Transition.
Play(ITransition transition)
// New method allows you to override the fade details of the transition.
Play(ITransition transition, float fadeDuration, FadeMode mode = FadeMode.FixedSpeed)
Unfortunately this means it is no longer possible to have a default value for the fadeDuration
parameter because skipping that parameter would just use the instant Play(clip)
method instead of Play(clip, defaultFadeDuration)
. The AnimancerPlayable.DefaultFadeDuration
constant still exists though, since it is used in several places such as the default value to use for a ClipTransition
. Also note that the value is now 0.25
seconds to match the default Mecanim transition settings (it used to be 0.3
as the default used by the Legacy animation system).
Collections
All Layer functionality in AnimancerComponent
has been moved into the new Layers
property.
Old (v3.1) | New (v4.0) |
---|---|
animancer.Play(clip, 1) |
animancer.Layers[1].Play(clip) |
animancer.LayerCount |
animancer.Layers.Count |
animancer.GetLayer(1) |
animancer.Layers[1] |
animancer.SetLayerAdditive(1, true) |
animancer.Layers.SetAdditive(1, true) animancer.Layers[1].IsAdditive = true |
animancer.SetLayerMask(1, mask) |
animancer.Layers.SetMask(mask) animancer.Layers[1].SetMask(mask) |
AnimancerPlayable.maxLayerCount = 8 |
AnimancerPlayable.LayerList.defaultCapacity = 8 AnimancerPlayable.LayerList.SetMinDefaultCapacity(8) |
In earlier versions the AnimancerComponent
class was the only one with access to its GetKey(AnimationClip)
method, meaning that it could have a Play(AnimationClip)
method where other classes (AnimancerPlayable
and AnimancerLayer
) could not because they would not be able to determine what key to look up the state with in the internal dictionary (usually the clip is its own key, but NamedAnimancerComponent
uses the clip's name so you can call Play("Name")
). But Animancer v4.0 gives the AnimancerPlayable
a reference to its component, so now you can call animancer.Layers[1].Play(clip)
as shown above. Also note that this changes the meaning of the default animancer.Play(clip)
so that instead of playing the animation on layer 0 it will now leave it on whatever layer it is currently on.
All State functionality in AnimancerComponent
has been moved into the new States
property.
Old (v3.1) | New (v4.0) |
---|---|
animancer.CurrentState |
animancer.States.Current |
animancer.StateCount |
animancer.States.Count |
animancer.CreateState(clip) |
animancer.Layers[0].CreateState(clip) |
animancer.GetState(clip) animancer.GetState("Name") |
animancer.States[clip] animancer.States["Name"] |
animancer.GetOrCreateState(clip) |
animancer.States.GetOrCreate(clip) |
animancer.Dispose(clip) |
animancer.States.Destroy(clip) |
Renaming
Old Name (v3.1) | New Name (v4.0) and Reason |
---|---|
All Serializable classes such as ClipState.Serializable |
Transition A more descriptive name. They encapsulate the fade duration, start time, etc. of an animation in much the same way as transitions in an Animator Controller. The fact that they are serializable is less significant. |
IAnimancerTransition IAnimancerTransitionDetailed |
ITransition ITransitionDetailed They are in the Animancer namespace anyway. |
FloatControllerState Vector2ControllerState Vector3ControllerState |
Float1ControllerState Float2ControllerState Float3ControllerState They each wrap a specific number of float parameters, even if they happen to also allow those parameters to be accessed as a Vector2 or Vector3 . |
Most Dispose methods |
Destroy Removed IDisposable from everything that does not follow regular disposal patterns. It makes no sense to put an AnimancerState in a using statement and if you declare a new ClipState locally, you do not need to dispose it because it will be cleaned up when the graph is destroyed. |
All of the AnimancerPlayable.StateDictionary.Destroy methods that take collections |
AnimancerPlayable.StateDictionary.DestroyAll To avoid ambiguity. |
AnimancerNode.PortIndex |
AnimancerNode.Index A simpler name since referring to "ports" was just confusing people anyway. |
AnimancerLayer.CurrentStateID AnimancerPlayable.CurrentStateID |
AnimancerLayer.CommandCount AnimancerPlayable.CommandCount A more descriptive name. |
IEarlyUpdate |
IUpdatable Now contains both EarlyUpdate and LateUpdate methods. |
MixerState.AreWeightsDirty |
MixerState.WeightsAreDirty Better phrasing. |
Features
Improved Transition Inspector
As mentioned above, AnimancerState.Serializable
and all its derived classes have been renamed to Transition
(see Transitions for details). But that's not all, they have also received a major upgrade to their Inspector interface:
Old (v3.1) | New (v4.0) |
---|---|
[SerializeField] private ClipState.Serializable _Walk; |
[SerializeField] private ClipTransition _Walk; |
There are quite a few improvements here:
- The "eye" button in the top right opens a new window for previewing the transition.
- Rather than giving the
Start Time
aNormalized
toggle to swap between normalized time and raw seconds, it now simply shows both values side by side so you can edit whichever one you want. This has been applied to the other fields as well. - All relevant fields now display an appropriate suffix to indicate the units ("x" indicates normalized time while "s" indicates raw seconds).
Speed
now has a toggle to determine if it is actually applied (otherwise the state simply retains whatever speed it had previously).- The new Animancer Event system allows the
OnEnd
callback to have a custom time instead of always being at the exact end of the animation, so that value is made available in the Inspector with a toggle to show aUnityEvent
that lets you configure the callback as well.- Note that when the
End Time
toggle is disabled, the value will actually be calculated based on theSpeed
. When playing forwards the animation will end atNormalizedTime == 1
, but when playing backwards it will end atNormalizedTime == 0
.
- Note that when the
- Down the bottom is a visual timeline display of the main parameters:
- The labels show key times (in seconds, rounded off).
- The blue highlighted area represents the fading in and out.
- The grey bar down the bottom represents the actual length of the animation.
- The button on the right adds an Animancer Event which will also be shown in this area.
There are also a few changes on the code side:
- Removed
StartTimeIsNormalized
and renamedStartTime
toNormalizedStartTime
. It always saves the normalized time value regardless of which one you set in the Inspector. Speed
can now be set toNaN
to prevent it from changing the existing value (this is what disabling the Inspector toggle does to any of the fields).
Transition Previews
The "eye" button in the top right of each Transition in the Inspector opens a window for previewing the transition so you can fine tune its details and see what your model looks like without needing to enter Play Mode.
Transition Assets
All transition types now have a corresponding Transition Asset (a ScriptableObject
with a single field for that transition type):
AnimancerTransition
is now the non-generic base class for transition assets.- Added transition assets for all transition types using the naming convention that
XXXTransition
has aXXXTransition
(which will create aXXXState
when played). For example, aClipTransition
holds aClipTransition
. - Any references to
AnimancerTransition
from previous versions are equivalent to the newClipTransition
, however you may wish to leave fields as they are so that any transition asset can be assigned if you aren't doing anything specific toClipTransition
s. Any previously created assets will be automatically changed to the new type. AnimancerTransition
no longer exposes the properties of theTransition
(except for those required byITransition
) so instead oftransitionAsset.Clip
you now need to usetransitionAsset.Transition.Clip
. This greatly simplifies its implementation as well as the implementation of all derived classes and makes it clearer that modifications are being applied to an object which may be shared.AnimancerTransition.Transition
now has a comment warning that thetransition.State
can only hold one value even though multiple states could have been created on different objects from that same transition.
Animancer Events
Animancer has always supported Unity's inbuilt Animation Events, but they have several notable drawbacks which are avoided by the new event system:
- The Events page explains the differences between the two systems.
- Animancer Events are primarily configured in the Inspector as part of Transitions to make use of the new Transition Preview system:
- They can also be configured in code:
// MeleeAttack.cs:
[SerializeField] private ClipTransition _Animation;
protected virtual void Awake()
{
// Make sure it has the expected number of events.
Debug.Assert(_Animation.Events.Count == 2, "Expected 2 events for the hit start and end");
// AnimancerEvent.Sequence always sorts itself so we know the start will be before the end.
_Animation.Events.Set(0, OnHitStart);// Set the callback for event 0.
_Animation.Events.Set(1, OnHitEnd);// Set the callback for event 1.
_Animation.Events.OnEnd = Character.EnterIdleState;
}
public void Attack()
{
Character.Animancer.Play(_Animation);
}
- Every event sequence has a separate End Event which takes the place of the old
AnimancerState.OnEnd
callback and allows a custom time to be specified instead of always occuring at the very end of the animation. - End Events are included in Animancer Lite, but the ability to set a custom end time and use other events is only available in the Unity Editor unless you purchase Animancer Pro.
- As with End Events prior to Animancer v4.0, all events are cleared (and returned to the
ObjectPool
) whenever a new animation is played. See Clear Automatically for details. - By default, this system uses
UnityEvent
s to define the event callbacks in the Inspector. However, it can be modified to use any other similar type of events. In particular, changing it to use UltEvents only takes a few simple steps.
Mixer Time Synchronization
- Mixer States can now synchronise the times of their children.
- It's not quite as advanced as the proper Foot Phase Synchronization used in Blend Trees which analyses the strides the character makes so that it can better synchronise animations with non-uniform timings such as when walking with a limp or an animation that includes multiple walk cycles.
- But it does have one major advantage: you actually get to control it so you can choose which animations are synchronised.
- It's on by default and can be disabled for individual children using the
SynchroniseChildren
array. - This advantage can be seen in the Linear Mixers example. Enabling synchronization on all animations gives the same result as the Blend Tree, meaning that the blending between Idle and Walk gives a much slower shuffle than it should. But disabling synchronization on the Idle gives a much better result because there's no need for consistency between the timing of those two animations.
MixerState.IsLooping
now returns true if any child state is looping.
Timeline
- Added
PlayableAssetState
for playingPlayableAsset
s. - Added an introduction sequence to the
Platformerexample. This allows the sequence of animations to be configured using the Timeline window and then played as if it were a single animation.
Changes
- Replaced
AnimancerComponent.StopOnDisable
withActionOnDisable
which is aAnimancerComponent.DisableAction
enum withStop
andPause
corresponding to the previoustrue
andfalse
as well as several new values. AnimancerTransition.State
is now the state most recently passed intoApply
(backed by the un-castBaseState
) so they can be more easily used on multiple objects.- Overrides of
CreateState
no longer need to manually set theState
.
- Overrides of
- Changed
HybridAnimancerController.PlayController
to return itsControllerState
. ControllerTransition
now uses itself as the key instead of the controller in case something else happens to use the same controller with a different set of parameters.AnimancerLayer.CreateState
now properly sets theAnimancerState.Key
.- Added a
Validate
class for all the validation methods and Lite restrictions.Validate.FadeDuration
now allows 0 in Animancer Lite.- All general validation is now conditional based on the
UNITY_ASSERTIONS
symbol (in the Unity Editor, Development Builds, and Animancer Lite).
- Changed
AnimancerState.IsPlayingAndNotEnding
to not try to look ahead one frame because it was only using the delta time from the previous frame so it was unreliable at best and wouldn't even be using the right type of delta time forAnimatePhysics
orUnscaledTime
. But it does now account for the new End Event time. - Changed the Inspector display of
"Dirty Early Nodes"
to"Updatables"
. - Moved
AnimancerNode.IsPlaying
toAnimancerState
since layers do not need it. - Added
AnimancerState.NewTime
which only gets called when theTime
is actually changed and is virtual.- Added a minor optimisation in the setter to only cast the value to
double
once. - Moved time caching from
ClipState
to the baseAnimancerState
so it can be used by all states. - Added a non-NaN assertion to the
AnimancerState.Time
setter. ManualMixerState
overridesNewTime
to access the weighted averageTime
of all child states.ControllerState
overridesNewTime
to access theStateInfo.normalizedTime
.
- Added a minor optimisation in the setter to only cast the value to
- Removed
AnimancerState.NormalizedSpeed
because it was not really that useful and got in the way of auto-correct suggestingNormalizedTime
. The getter was simplySpeed / Length
and the setterSpeed = value * Length
. - Refactored the system for checking if an
AnimationClip
has an Animation Event with a particular name:- Moved the static
ClipState.HasEvent
toAnimancerUtilities
. - Added an overload that takes an
IAnimationClipCollection
. - Removed the abstract
AnimancerState.HasEvent
. AnimationEventReceiver
now usesAnimancerUtilities.HasEvent(IAnimationClipCollection, string)
so that each state doesn't need to manually iterate through all its clips.
- Moved the static
- Changed
StateBehaviour.Reset
toOnValidate
so it always enforces its rule. - Replaced the custom transition context menus with the standard serialized property context menu:
- It now displays the size of the serialized Animancer Event arrays.
- Made several
AnimancerState
members virtual instead of abstract:AverageVelocity
,ApplyAnimatorIK
,ApplyFootIK
. - Added Assembly Definitions for
Animancer.FSM
andAnimancer.Examples
to make sure theFSM
system is entirely separate. - Removed null checks from
AnimancerPlayable.Play(animator, playable, component)
so it will now throw exceptions if the parameters are null. BoolPref
can now take a custom key prefix.- Added prefixes to all prefs.
Improvements
AnimancerComponent.InitializePlayable
will now try usingGetComponent
if it has noAnimator
reference and throw an exception if one still isn't found.NamedAnimancerComponent
now avoids initializing itsAnimancerPlayable
inAwake
if it has no animations.- Improved the output setup of
AnimancerPlayable
:- Removed the exception for initializing without an
Animator
. - Renamed the static
Play
methods toSetOutput
and made them non-static. - Calling
SetOutput
multiple times will now destroy the oldPlayableOutput
so it does not cause errors in Unity 2019.3+ and you can change theAnimator
properly.
- Removed the exception for initializing without an
- Improved
ITransition
:- It now implements a
FadeMode
directly instead ofbool CrossFadeFromStart
. Play(transition)
no longer tries to calculate the fade out duration. If you want to do that, you need to callAnimancePlayable.GetFadeOutDuration
and pass it intoPlay(transition, duration, mode)
.- Moved the main part of
AnimancerPlayable.GetFadeOutDuration
toAnimancerEvent
, leaving behind only the part specific to Animation Events with the function name "End".
- It now implements a
ClipTransition.Apply
now applies a default start time based on the speed if thestate.Weight == 0
. Same forPlayableAssetState
transitions.AnimancerState.NormalizedTime
now returns 0 ifLength
is 0.AnimancerState.Duration
now sets the speed to infinity if the value is set to 0.- The
AnimancerNode.Speed
andWeight
setters now assert that the value is not NaN. - Added
Restore Bind Pose
context menu function toAnimator
components. - The "Threshold" header in the Mixer Inspector is now a dropdown menu which lists all the threshold calculation functions. #12
- Adding a
HybridAnimancerComponent
to an object with anAnimatorController
assigned to itsAnimator
will now assign that controller to the animancer instead of only clearing it. - Removed unnecessary calls to
SetInputCount
andSetInputWeight
duringAnimancerPlayable.OnPlayableCreate
. - Minor optimisation in
AnimancerNode.ApplyWeight
. - Added Asset Labels to most assets.
- Added
IAnimationClipCollection
which takes anICollection
instead of aList
so it can useHashSet
s to efficiently avoid duplicates.- All
Transition
s now implementIAnimationClipCollection
. - Added various
Gather
methods toAnimancerUtilities
. - Moved the reflection based clip gathering system from
AnimancerEditorUtilities
into a dedicatedAnimationGatherer
class and improved its reliability. - It now finds the character's root object using the prefab root or by counting the number of
Animator
s below each parent. An object with moreAnimator
s is assumed to be the parent of multiple characters, so the previous object is the root. Once it finds the root, it gathers animations from the child components of that object. - Added
ICharacterRoot
for components to manually specify which object is the root.
- All
- Added
AnimancerStateDictionary.Destroy
methods for collections andIAnimationClipSource
. - The
Find Animations
context menu function forDirectionalAnimationSet
s now properly supports undo commands. - Added
AnimancerUtilities.Wrap01
extension method as a more efficient implementation ofMathf.Repeat(value, 1)
. - Reorganised the Inspector context menus.
- Removed
AnimancerState.HasLength
. All states must now return a validLength
(even if it is 0).- Added
ManualMixerState.Length
which is calculated as the weighted average of the lengths of each of its children.
- Added
- Added
ControllerState.StateInfo
to return either the current or next state depending on whether a transition is active.Length
andIsLooping
now use theStateInfo
.- Removed
ControllerState.Drawer.DisplayStateInfo
,DisplayTime
,DisplayLength
, andSetTime
since they are now unnecessary.
- Added
[<see cref="SerializeField"/>]
tags to the start of comments for all properties that directly wrap serialized fields. StateMachine.CanSetState
now returns true if the parameter isnull
since the other methods support nulls.- The
ReadMe
now includes the Animancer Version in its name to better detect if the user did not delete a previous version before updating (since Unity's package importer will overwrite old files but not rename them).
Fixes
- Fixed various issues in Unity 2019.3:
- Fixed the preview icon to use a different texture since the old one seems to be missing.
- Fixed
AnimancerGUI.DoOptionalTimeField
. - Fixed the event drawer foldout.
- Fixed Inspector Error on the
NamedAnimancerComponent
. - Fixed import warnings from the Spider Bot model due to multiple objects having the same name.
- Added a workaround so the base
TransitionDrawer
does not take proprity over its more specific children (only happens in a DLL).
- Added
DummyObjectDrawer
as a fallback custom Inspector for anyObject
... which does nothing (the class literally just inherits fromUnityEditor.Editor
and has no members). For some reason Unity executesPropertyDrawer
s differently in the default Inspector than it does in a custom Inspector (even an empty one) and that difference causes theTimeRuler
to not display properly without a custom Inspector. Since it is set as a fallback, any other custom Inspector should automatically override it, but if not you can simply deleteAnimancer/Internal/Editor Utilities/Inspector/DummyObjectEditor.cs
. - Fixed
FadeMode.FromStart
to work properly with thefadeDuration
set to 0. - Fading now accounts for the speed of the parent nodes.
- Fixed
ControllerState.GatherDefaultStates
to properly gather the state for layer 0. - Fixed transitions to use the correct label for the main property in Unity 2018.3+.
- Fixed
ManualMixerTransition.CreateState
to properly callInitialize
to create its states. - Removed the functionality to update animations in Edit Mode from Unity 2018.3+ because Unity now does it automatically.
- Fixed the Edit Mode update loop to not throw exceptions when an object is destroyed.
- Calling
AnimancerState.SetParent
with an already occupied port will now leave the state properly disconnected as it fails. - Fixed
AnimancerPlayable.KeepChildrenConnected = true
to work properly. - Fixed the
AnimancerStateDrawer
progress bars to be properly visible in the Dark Theme and changed the colors to be a bit stronger overall. - The
AnimancerPlayable
finalizer will no longer destroy the graph automatically while in Play Mode since that would mean a runtime warning anyway. AnimancerState.Duration
now returnsPositiveInfinity
from the getter ifSpeed
is 0 and throws anArgumentException
is setting the value to 0.AnimancerState.RemainingDuration
now respects looping/not and custom end times.- Fixed the 2D mixer states to round children with
weight < 0.01f
to 0. Otherwise they often get very small weights and still trigger Animation Events. PlayableGraph
s created in Edit Mode are now destroyed properly if the target Animator is destroyed.- Added comments explaining that when
OnAnimatorIK
is called the layer index parameter will always be zero (a limitation of the Playables API). - Replaced all usage of
EditorStyles.label
withGUI.skin.label
since they are slightly different in some Unity versions and the latter is the default used byGUI.Label
. - Fixed the
End Event/Clear
context menu function to be disabled when the time is not set. Ctrl + Click
on a state in the Inspector now unpauses the graph as well as fading to that state.- Fixed
Float3ControllerState
to show all of its parameters in the Inspector rather than only the first two.
Examples
- Added Weapons which uses the new instructions for downloading animations from Mixamo and configure their Import settings.
- Improved the
ReadMe
:- It now lists all example scenes for easy navigation.
- Improved the Inspector layout and added descriptions of each of the support links.
- It now includes the Animancer Version in its name to better detect if the user did not delete a previous version before updating (since Unity's package importer will overwrite old files but not rename them).
- Renamed
Simple Playing
to Quick Play. - Added
Hybrid Basicsto demonstrate theHybridAnimancerComponent
in a simple situation without the complexity of a full state machine inHybrid Mini Game. - Improved
Sequence Coroutine:- It now uses the new custom end time system rather than needing a
ClipTransition
subclass with its ownPlayDuration
field. - Added assertions for reliability.
- It now uses the new custom end time system rather than needing a
- Improved
Speed and TimeandDirectional Blending:- They now use a shared
SpiderBot
base class and demonstrate polymorphism. SpiderBotAdvanced
now follows the mouse cursor so it can truly move in any direction rather than being limited to 8 directions with WASD.- Cleaned up the animation names to match the same convention as others.
- They now use a shared
- Improved
RootMotion:- It now overrides
Transition.Apply
to set the root motion flag so the caller doesn't need to do it. - It now has some extra fields to specify another object to apply the root motion to.
- It now overrides
Linear Blendingnow uses Transition Assets.- Directional Basics now uses a serialized field so its initial facing direction can be set in Edit Mode and it now has a dedicated Play method which takes a
DirectionalAnimationSet
instead of callingGetClip
in each location it wants to play something. - Renamed the "Animation Events" group to Events (since they now demonstrate Animancer Events as well).
- Renamed "Simple and End Events" to Golf Events and updated it to demonstrate regularAnimation Events, a
SimpleEventReceiver
, Animancer Events defined in the Inspector, and Animancer Events with their times se in the Inspector and callbacks set in code. - Renamed "Other Events" to Footstep Events and reordered it to come before "Golf Events".
- It now includes Animancer Events and much more detail about how to set everything up.
Brain Transplantsnow enables and disables the brains in code when swapping them instead of using theUnityEvent
s on the UI Buttons. #10- Improved
Platformer:- Added an introduction sequence using Timeline.
- Jumping now uses a specific target height rather than an arbitrary amount of force.
- It now allows the player to jump higher by holding the button longer.
- Reviving the character now plays the death animation backwards.
- Improved the Inverse Kinematics examples:
- Changed
StartingPositions
toTransformResetter
and it now resets rotations as well. - Improved
RaycastFootIK
to account for the foot rotation when calculating the raycast diration.
- Changed
Hybrid Mini Gamenow has the character walk into and out of the mini game rather than teleporting.- Improved 3D Game Kit:
- It is now based on the 3D Game Kit Lite since the full version is a massive pain to download and import. #11
- It now shows which system (Animancer or Mecanim) is active and lets you swap between them with keyboard controls instead of UI Buttons.
- It now uses custom end times as part of each transition rather than End Animation Events or separate end time fields.
- The root object is now separate from the model with
RootMotionRedirect
passing on the root motion. AirborneState
andLandingState
now use Mixers instead of Blend Trees since they are more convenient to use and can give the same result now that time synchronization has been implemented.- Added
FlinchState
andDieState
. - Attacks can how kill enemies and destroy objects and do not use a custom transition class.
- Removed the copy of
RandomAudioPlayer
and usedUnityEvent
s to access the existing script. - Removed the copy of
AttackTrail
and usedUnityEvent
s to access the existingTimeEffect
script.
- Added
[DefaultExecutionOrder]
attributes to allCharacter
examples as well as comments inAwake
to reinforce its importance.
Internal
- Added 150+ unit tests using the Unity Test Framework. The tests are not planned for release so they will not directly matter to users, but they will help reduce the possibility of bugs making it to release.
- Changed
AnimancerNode.Stop
fromabstract
tovirtual
so it can setWeight = 0
by default since bothAnimancerLayer
andAnimancerState
did so. - Moved the functionality to constantly repaint in Edit Mode from the manual update loop to
AnimancerPlayableEditor.RequiresConstantRepaint
. - Split
AnimancerPlayableEditor
intoBaseAnimancerComponentEditor
andAnimancerPlayableDrawer
to the preview window can draw itsAnimancerPlayable
without actually having anAnimancerComponent
. - Moved
FastComparer
out ofAnimancerPlayable
. - Changed
AnimancerLayer.DestroyStates
andManualMixerState.DestroyChildren
to iterate in reverse order. - Moved
AnimancerEditorUtilities.GUIStyles
out toAnimancerGUI
and moved all GUI utilities there.- Renamed
GetLayoutRect
toLayoutSingleLineRect
. - Added
padding
parameter toStealFromLeft
andStealFromRight
.
- Renamed
- Changed parameter references in comments to use the `grave accent` instead of 'single quotes'.
- Added
ConversionCache
to replace various other caching systems throughout Animancer. - Added
TemporarySettings
for storing information between assembly reloads without needing to save it when Unity closes.- Currently it is used to store details about which Animancer Events are selected in the Inspector.
- Added
ITransitionDetailed : ITransition
to expose additional details for previewing.
- Added
Key
andKey.KeyedList
:- Changed
AnimancerNode
to inherit fromKey
and replaced the dirty node update list with a keyed list which greatly cleans up that part of the system. - Changed
IEarlyUpdate
intoIUpdatable
which implementsIKeyHolder
and replaced its list with a keyed list as well. - Removed the
needsMoreUpdates
parameter fromIUpdatable.Update
since they can be immediately removed at any time byAnimancerPlayable.CancelUpdate
.
- Changed
- Added a simple
ObjectPool
system to allow easy reuse of objects. If you want a more powerful general purpose system, check out Weaver. - Refactored the
AppendDescription
system in the core classes to be cleaner and produce better descriptions. - Added
Serialization
class which contains various utilities relating to serialization:Serialization.PropertyAccessor
allows access to the underlying object of aSerializedProperty
.Serialization.ObjectReference
acts as a stronger serializable reference to aUnityEngine.Object
. A simpleObject
field can lose its value under certain circumstances even if the referenced object still exists, for example when entering Play Mode.Serialization.PropertyReference
is a serializable reference to aSerializedProperty
.
- Moved the custom GUI for the
Start Time
andSpeed
fields to the baseTransitionDrawer
. - All calls to
EditorGUI.Foldout
now setEditorGUIUtility.hierarchyMode = true
to ensure that the arrow gets the correct indentation.