123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Text;
- using UnityEngine;
- using UnityEngine.Animations;
- using UnityEngine.Playables;
- namespace Animancer
- {
-
-
-
-
-
-
-
-
-
-
-
-
- public sealed class AnimancerLayer : AnimancerNode, IAnimationClipCollection
- {
-
- #region Fields and Properties
-
-
- internal AnimancerLayer(AnimancerPlayable root, int index)
- {
- #if UNITY_ASSERTIONS
- GC.SuppressFinalize(this);
- #endif
- Root = root;
- Index = index;
- CreatePlayable();
- if (ApplyParentAnimatorIK)
- _ApplyAnimatorIK = root.ApplyAnimatorIK;
- if (ApplyParentFootIK)
- _ApplyFootIK = root.ApplyFootIK;
- }
-
-
- protected override void CreatePlayable(out Playable playable)
- => playable = AnimationMixerPlayable.Create(Root._Graph);
-
-
- public override AnimancerLayer Layer => this;
-
- public override IPlayableWrapper Parent => Root;
-
- public override bool KeepChildrenConnected => Root.KeepChildrenConnected;
-
-
- private readonly List<AnimancerState> States = new List<AnimancerState>();
-
- private AnimancerState _CurrentState;
-
-
-
-
-
-
-
-
- public AnimancerState CurrentState
- {
- get => _CurrentState;
- private set
- {
- _CurrentState = value;
- CommandCount++;
- }
- }
-
-
-
-
-
- public int CommandCount { get; private set; }
- #if UNITY_EDITOR
-
- internal void IncrementCommandCount() => CommandCount++;
- #endif
-
-
-
-
- public bool IsAdditive
- {
- get => Root.Layers.IsAdditive(Index);
- set => Root.Layers.SetAdditive(Index, value);
- }
-
-
-
-
- public void SetMask(AvatarMask mask)
- {
- Root.Layers.SetMask(Index, mask);
- }
- #if UNITY_ASSERTIONS
-
- internal AvatarMask _Mask;
- #endif
-
-
-
-
-
- public Vector3 AverageVelocity
- {
- get
- {
- var velocity = default(Vector3);
- for (int i = States.Count - 1; i >= 0; i--)
- {
- var state = States[i];
- velocity += state.AverageVelocity * state.Weight;
- }
- return velocity;
- }
- }
-
- #endregion
-
- #region Child States
-
-
- public override int ChildCount => States.Count;
-
-
- public override AnimancerState GetChild(int index) => States[index];
-
-
- public AnimancerState this[int index] => States[index];
-
-
- public void AddChild(AnimancerState state)
- {
- if (state.Parent == this)
- return;
-
- state.SetRoot(Root);
- var index = States.Count;
- States.Add(null);
- _Playable.SetInputCount(index + 1);
- state.SetParent(this, index);
- }
-
-
- protected internal override void OnAddChild(AnimancerState state) => OnAddChild(States, state);
-
-
- protected internal override void OnRemoveChild(AnimancerState state)
- {
- var index = state.Index;
- Validate.AssertCanRemoveChild(state, States);
- if (_Playable.GetInput(index).IsValid())
- Root._Graph.Disconnect(_Playable, index);
-
- var last = States.Count - 1;
- if (index < last)
- {
- state = States[last];
- state.DisconnectFromGraph();
- States[index] = state;
- state.Index = index;
- if (state.Weight != 0 || Root.KeepChildrenConnected)
- state.ConnectToGraph();
- }
- States.RemoveAt(last);
- _Playable.SetInputCount(last);
- }
-
-
- public override FastEnumerator<AnimancerState> GetEnumerator()
- => new FastEnumerator<AnimancerState>(States);
-
- #endregion
-
- #region Create State
-
-
-
-
-
- public ClipState CreateState(AnimationClip clip) => CreateState(Root.GetKey(clip), clip);
-
-
-
- public ClipState CreateState(object key, AnimationClip clip)
- {
- var state = new ClipState(clip)
- {
- _Key = key,
- };
- AddChild(state);
- return state;
- }
-
-
-
-
-
-
- public void CreateIfNew(AnimationClip clip0, AnimationClip clip1)
- {
- GetOrCreateState(clip0);
- GetOrCreateState(clip1);
- }
-
-
-
-
-
- public void CreateIfNew(AnimationClip clip0, AnimationClip clip1, AnimationClip clip2)
- {
- GetOrCreateState(clip0);
- GetOrCreateState(clip1);
- GetOrCreateState(clip2);
- }
-
-
-
-
-
- public void CreateIfNew(AnimationClip clip0, AnimationClip clip1, AnimationClip clip2, AnimationClip clip3)
- {
- GetOrCreateState(clip0);
- GetOrCreateState(clip1);
- GetOrCreateState(clip2);
- GetOrCreateState(clip3);
- }
-
-
-
-
-
- public void CreateIfNew(params AnimationClip[] clips)
- {
- if (clips == null)
- return;
- var count = clips.Length;
- for (int i = 0; i < count; i++)
- {
- var clip = clips[i];
- if (clip != null)
- GetOrCreateState(clip);
- }
- }
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState GetOrCreateState(AnimationClip clip, bool allowSetClip = false)
- {
- return GetOrCreateState(Root.GetKey(clip), clip, allowSetClip);
- }
-
-
-
-
-
- public AnimancerState GetOrCreateState(ITransition transition)
- {
- var state = Root.States.GetOrCreate(transition);
- state.LayerIndex = Index;
- return state;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState GetOrCreateState(object key, AnimationClip clip, bool allowSetClip = false)
- {
- if (key == null)
- throw new ArgumentNullException(nameof(key));
- if (Root.States.TryGet(key, out var state))
- {
-
- if (!ReferenceEquals(state.Clip, clip))
- {
- if (allowSetClip)
- {
- state.Clip = clip;
- }
- else
- {
- throw new ArgumentException(AnimancerPlayable.StateDictionary.GetClipMismatchError(key, state.Clip, clip));
- }
- }
- else
- {
- AddChild(state);
- }
- }
- else
- {
- state = CreateState(key, clip);
- }
- return state;
- }
-
-
- public void DestroyStates()
- {
- for (int i = States.Count - 1; i >= 0; i--)
- {
- States[i].Destroy();
- }
- States.Clear();
- }
-
- #endregion
-
- #region Play Management
-
-
- protected internal override void OnStartFade()
- {
- for (int i = States.Count - 1; i >= 0; i--)
- States[i].OnStartFade();
- }
-
-
-
-
-
-
-
-
-
-
- public AnimancerState Play(AnimationClip clip)
- => Play(GetOrCreateState(clip));
-
-
-
-
-
-
-
- public AnimancerState Play(AnimancerState state)
- {
- if (Weight == 0 && TargetWeight == 0)
- Weight = 1;
- AddChild(state);
- CurrentState = state;
- state.Play();
- for (int i = States.Count - 1; i >= 0; i--)
- {
- var otherState = States[i];
- if (otherState != state)
- otherState.Stop();
- }
- return state;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState Play(AnimationClip clip, float fadeDuration, FadeMode mode = default)
- => Play(Root.States.GetOrCreate(clip), fadeDuration, mode);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState Play(AnimancerState state, float fadeDuration, FadeMode mode = default)
- {
-
- if (fadeDuration <= 0 ||
- (Root.SkipFirstFade && Index == 0 && Weight == 0))
- {
- if (mode == FadeMode.FromStart || mode == FadeMode.NormalizedFromStart)
- state.Time = 0;
- Weight = 1;
- return Play(state);
- }
- EvaluateFadeMode(mode, ref state, ref fadeDuration, out var layerFadeDuration);
- StartFade(1, layerFadeDuration);
- if (Weight == 0)
- return Play(state);
- AddChild(state);
- CurrentState = state;
-
-
- if (state.IsPlaying && state.TargetWeight == 1 &&
- (state.Weight == 1 || state.FadeSpeed * fadeDuration > Math.Abs(1 - state.Weight)))
- {
- OnStartFade();
- }
- else
- {
- state.IsPlaying = true;
- state.StartFade(1, fadeDuration);
- for (int i = States.Count - 1; i >= 0; i--)
- {
- var otherState = States[i];
- if (otherState != state)
- otherState.StartFade(0, fadeDuration);
- }
- }
- return state;
- }
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState Play(ITransition transition)
- => Play(transition, transition.FadeDuration, transition.FadeMode);
-
-
-
-
-
-
-
-
- public AnimancerState Play(ITransition transition, float fadeDuration, FadeMode mode = default)
- {
- var state = Root.States.GetOrCreate(transition);
- state = Play(state, fadeDuration, mode);
- transition.Apply(state);
- return state;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState TryPlay(object key)
- => Root.States.TryGet(key, out var state) ? Play(state) : null;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public AnimancerState TryPlay(object key, float fadeDuration, FadeMode mode = default)
- => Root.States.TryGet(key, out var state) ? Play(state, fadeDuration, mode) : null;
-
-
-
-
-
-
- private void EvaluateFadeMode(FadeMode mode, ref AnimancerState state, ref float fadeDuration, out float layerFadeDuration)
- {
- layerFadeDuration = fadeDuration;
- switch (mode)
- {
- case FadeMode.FixedSpeed:
- fadeDuration *= Math.Abs(1 - state.Weight);
- layerFadeDuration *= Math.Abs(1 - Weight);
- break;
- case FadeMode.FixedDuration:
- break;
- case FadeMode.FromStart:
- #if UNITY_ASSERTIONS
- if (!(state is ClipState))
- throw new ArgumentException(
- $"{nameof(FadeMode)}.{nameof(FadeMode.FromStart)} can only be used on {nameof(ClipState)}s." +
- $" State = {state}");
- #endif
- state = GetOrCreateWeightlessState(state);
- break;
- case FadeMode.NormalizedSpeed:
- {
- var length = state.Length;
- fadeDuration *= Math.Abs(1 - state.Weight) * length;
- layerFadeDuration *= Math.Abs(1 - Weight) * length;
- }
- break;
- case FadeMode.NormalizedDuration:
- {
- var length = state.Length;
- fadeDuration *= length;
- layerFadeDuration *= length;
- }
- break;
- case FadeMode.NormalizedFromStart:
- {
- #if UNITY_ASSERTIONS
- if (!(state is ClipState))
- throw new ArgumentException(
- $"{nameof(FadeMode)}.{nameof(FadeMode.NormalizedFromStart)} can only be used on {nameof(ClipState)}s." +
- $" State = {state}");
- #endif
- state = GetOrCreateWeightlessState(state);
- var length = state.Length;
- fadeDuration *= length;
- layerFadeDuration *= length;
- }
- break;
- default:
- throw AnimancerUtilities.CreateUnsupportedArgumentException(mode);
- }
- }
-
- #if UNITY_ASSERTIONS
-
-
-
-
-
- public static int MaxStateDepth { get; private set; } = 5;
- #endif
-
-
- [System.Diagnostics.Conditional(Strings.Assertions)]
- public static void SetMaxStateDepth(int depth)
- {
- #if UNITY_ASSERTIONS
- MaxStateDepth = depth;
- #endif
- }
-
-
-
-
-
-
- public static float WeightlessThreshold { get; set; } = 0.01f;
-
-
-
-
-
-
-
- public AnimancerState GetOrCreateWeightlessState(AnimancerState state)
- {
- if (state.Weight > WeightlessThreshold)
- {
- var clip = state.Clip;
- if (clip == null)
- {
-
-
- throw new InvalidOperationException(
- $"{nameof(GetOrCreateWeightlessState)} can only be used on {nameof(ClipState)}s. State = " + state);
- }
-
- var keyState = state;
- while (true)
- {
- keyState = keyState.Key as AnimancerState;
- if (keyState == null)
- {
- break;
- }
- else if (keyState.Weight <= WeightlessThreshold)
- {
- state = keyState;
- goto GotWeightlessState;
- }
- }
- #if UNITY_ASSERTIONS
- int depth = 0;
- #endif
-
-
- do
- {
-
- state = Root.States.GetOrCreate((object)state, clip);
- #if UNITY_ASSERTIONS
- if (++depth == MaxStateDepth)
- {
- OptionalWarning.MaxStateDepth.Log(
- $"{nameof(AnimancerLayer)}.{nameof(GetOrCreateWeightlessState)}" +
- $" has created {MaxStateDepth} states for a single clip." +
- $" This is most likely a result of repeated calls on consecutive frames." +
- $" This can be avoided by using a different {nameof(FadeMode)}," +
- $" having the Start Time toggle disabled on a Transition," +
- $" or by calling {nameof(AnimancerLayer)}.{nameof(SetMaxStateDepth)}" +
- $" to increase the threshold for this warning.",
- Root?.Component);
- }
- #endif
- }
- while (state.Weight > WeightlessThreshold);
- }
- GotWeightlessState:
-
- AddChild(state);
- state.Time = 0;
- state.Weight = 0;
- return state;
- }
-
-
-
-
-
-
-
- public override void Stop()
- {
- base.Stop();
- CurrentState = null;
- for (int i = States.Count - 1; i >= 0; i--)
- States[i].Stop();
- }
-
-
-
-
-
-
- public bool IsPlayingClip(AnimationClip clip)
- {
- for (int i = States.Count - 1; i >= 0; i--)
- {
- var state = States[i];
- if (state.Clip == clip && state.IsPlaying)
- return true;
- }
- return false;
- }
-
-
-
- public bool IsAnyStatePlaying()
- {
- for (int i = States.Count - 1; i >= 0; i--)
- {
- if (States[i].IsPlaying)
- return true;
- }
- return false;
- }
-
-
-
-
-
-
- protected internal override bool IsPlayingAndNotEnding() => _CurrentState != null && _CurrentState.IsPlayingAndNotEnding();
-
-
-
-
- public float GetTotalWeight()
- {
- float weight = 0;
- for (int i = States.Count - 1; i >= 0; i--)
- {
- weight += States[i].Weight;
- }
- return weight;
- }
-
- #endregion
-
- #region Inverse Kinematics
-
- private bool _ApplyAnimatorIK;
-
- public override bool ApplyAnimatorIK
- {
- get => _ApplyAnimatorIK;
- set => base.ApplyAnimatorIK = _ApplyAnimatorIK = value;
- }
-
- private bool _ApplyFootIK;
-
- public override bool ApplyFootIK
- {
- get => _ApplyFootIK;
- set => base.ApplyFootIK = _ApplyFootIK = value;
- }
-
- #endregion
-
- #region Inspector
-
-
-
-
- public void GatherAnimationClips(ICollection<AnimationClip> clips) => clips.GatherFromSource(States);
-
-
- public override string ToString()
- {
- #if UNITY_ASSERTIONS
- if (string.IsNullOrEmpty(DebugName))
- {
- if (_Mask != null)
- return _Mask.name;
- SetDebugName(Index == 0 ? "Base Layer" : "Layer " + Index);
- }
- return base.ToString();
- #else
- return "Layer " + Index;
- #endif
- }
-
-
- protected override void AppendDetails(StringBuilder text, string separator)
- {
- base.AppendDetails(text, separator);
- text.Append(separator).Append($"{nameof(CurrentState)}: ").Append(CurrentState);
- text.Append(separator).Append($"{nameof(CommandCount)}: ").Append(CommandCount);
- text.Append(separator).Append($"{nameof(IsAdditive)}: ").Append(IsAdditive);
- #if UNITY_ASSERTIONS
- text.Append(separator).Append($"{nameof(AvatarMask)}: ").Append(AnimancerUtilities.ToStringOrNull(_Mask));
- #endif
- }
-
- #endregion
-
- }
- }
|