123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /******************************************************************************
- * Spine Runtimes License Agreement
- * Last updated January 1, 2020. Replaces all prior versions.
- *
- * Copyright (c) 2013-2020, Esoteric Software LLC
- *
- * Integration of the Spine Runtimes into software or otherwise creating
- * derivative works of the Spine Runtimes is permitted under the terms and
- * conditions of Section 2 of the Spine Editor License Agreement:
- * http://esotericsoftware.com/spine-editor-license
- *
- * Otherwise, it is permitted to integrate the Spine Runtimes into software
- * or otherwise create derivative works of the Spine Runtimes (collectively,
- * "Products"), provided that each user of the Products must obtain their own
- * Spine Editor license and redistribution of the Products in any form must
- * include this license and copyright notice.
- *
- * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
- * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- using UnityEngine;
- using System.Collections.Generic;
- namespace Spine.Unity {
- [RequireComponent(typeof(Animator))]
- [HelpURL("http://esotericsoftware.com/spine-unity#SkeletonMecanim-Component")]
- public class SkeletonMecanim : SkeletonRenderer, ISkeletonAnimation {
- [SerializeField] protected MecanimTranslator translator;
- public MecanimTranslator Translator { get { return translator; } }
- private bool wasUpdatedAfterInit = true;
- #region Bone Callbacks (ISkeletonAnimation)
- protected event UpdateBonesDelegate _BeforeApply;
- protected event UpdateBonesDelegate _UpdateLocal;
- protected event UpdateBonesDelegate _UpdateWorld;
- protected event UpdateBonesDelegate _UpdateComplete;
- /// <summary>
- /// Occurs before the animations are applied.
- /// Use this callback when you want to change the skeleton state before animations are applied on top.
- /// </summary>
- public event UpdateBonesDelegate BeforeApply { add { _BeforeApply += value; } remove { _BeforeApply -= value; } }
- /// <summary>
- /// Occurs after the animations are applied and before world space values are resolved.
- /// Use this callback when you want to set bone local values.</summary>
- public event UpdateBonesDelegate UpdateLocal { add { _UpdateLocal += value; } remove { _UpdateLocal -= value; } }
- /// <summary>
- /// Occurs after the Skeleton's bone world space values are resolved (including all constraints).
- /// Using this callback will cause the world space values to be solved an extra time.
- /// Use this callback if want to use bone world space values, and also set bone local values.</summary>
- public event UpdateBonesDelegate UpdateWorld { add { _UpdateWorld += value; } remove { _UpdateWorld -= value; } }
- /// <summary>
- /// Occurs after the Skeleton's bone world space values are resolved (including all constraints).
- /// Use this callback if you want to use bone world space values, but don't intend to modify bone local values.
- /// This callback can also be used when setting world position and the bone matrix.</summary>
- public event UpdateBonesDelegate UpdateComplete { add { _UpdateComplete += value; } remove { _UpdateComplete -= value; } }
- #endregion
- public override void Initialize (bool overwrite, bool quiet = false) {
- if (valid && !overwrite)
- return;
- base.Initialize(overwrite, quiet);
- if (!valid)
- return;
- if (translator == null) translator = new MecanimTranslator();
- translator.Initialize(GetComponent<Animator>(), this.skeletonDataAsset);
- wasUpdatedAfterInit = false;
- }
- public void Update () {
- if (!valid) return;
- wasUpdatedAfterInit = true;
- // animation status is kept by Mecanim Animator component
- if (updateMode <= UpdateMode.OnlyAnimationStatus)
- return;
- ApplyAnimation();
- }
- protected void ApplyAnimation () {
- if (_BeforeApply != null)
- _BeforeApply(this);
- #if UNITY_EDITOR
- var translatorAnimator = translator.Animator;
- if (translatorAnimator != null && !translatorAnimator.isInitialized)
- translatorAnimator.Rebind();
- if (Application.isPlaying) {
- translator.Apply(skeleton);
- }
- else {
- if (translatorAnimator != null && translatorAnimator.isInitialized &&
- translatorAnimator.isActiveAndEnabled && translatorAnimator.runtimeAnimatorController != null) {
- // Note: Rebind is required to prevent warning "Animator is not playing an AnimatorController" with prefabs
- translatorAnimator.Rebind();
- translator.Apply(skeleton);
- }
- }
- #else
- translator.Apply(skeleton);
- #endif
- // UpdateWorldTransform and Bone Callbacks
- {
- if (_UpdateLocal != null)
- _UpdateLocal(this);
- skeleton.UpdateWorldTransform();
- if (_UpdateWorld != null) {
- _UpdateWorld(this);
- skeleton.UpdateWorldTransform();
- }
- if (_UpdateComplete != null)
- _UpdateComplete(this);
- }
- }
- public override void LateUpdate () {
- // instantiation can happen from Update() after this component, leading to a missing Update() call.
- if (!wasUpdatedAfterInit) Update();
- base.LateUpdate();
- }
- [System.Serializable]
- public class MecanimTranslator {
- const float WeightEpsilon = 0.0001f;
- #region Inspector
- public bool autoReset = true;
- public bool useCustomMixMode = true;
- public MixMode[] layerMixModes = new MixMode[0];
- public MixBlend[] layerBlendModes = new MixBlend[0];
- #endregion
- public delegate void OnClipAppliedDelegate (Spine.Animation clip, int layerIndex, float weight,
- float time, float lastTime, bool playsBackward);
- protected event OnClipAppliedDelegate _OnClipApplied;
- public event OnClipAppliedDelegate OnClipApplied { add { _OnClipApplied += value; } remove { _OnClipApplied -= value; } }
- public enum MixMode { AlwaysMix, MixNext, Hard }
- readonly Dictionary<int, Spine.Animation> animationTable = new Dictionary<int, Spine.Animation>(IntEqualityComparer.Instance);
- readonly Dictionary<AnimationClip, int> clipNameHashCodeTable = new Dictionary<AnimationClip, int>(AnimationClipEqualityComparer.Instance);
- readonly List<Animation> previousAnimations = new List<Animation>();
- protected class ClipInfos {
- public bool isInterruptionActive = false;
- public bool isLastFrameOfInterruption = false;
- public int clipInfoCount = 0;
- public int nextClipInfoCount = 0;
- public int interruptingClipInfoCount = 0;
- public readonly List<AnimatorClipInfo> clipInfos = new List<AnimatorClipInfo>();
- public readonly List<AnimatorClipInfo> nextClipInfos = new List<AnimatorClipInfo>();
- public readonly List<AnimatorClipInfo> interruptingClipInfos = new List<AnimatorClipInfo>();
- public AnimatorStateInfo stateInfo;
- public AnimatorStateInfo nextStateInfo;
- public AnimatorStateInfo interruptingStateInfo;
- public float interruptingClipTimeAddition = 0;
- }
- protected ClipInfos[] layerClipInfos = new ClipInfos[0];
- Animator animator;
- public Animator Animator { get { return this.animator; } }
- public int MecanimLayerCount {
- get {
- if (!animator)
- return 0;
- return animator.layerCount;
- }
- }
- public string[] MecanimLayerNames {
- get {
- if (!animator)
- return new string[0];
- string[] layerNames = new string[animator.layerCount];
- for (int i = 0; i < animator.layerCount; ++i) {
- layerNames[i] = animator.GetLayerName(i);
- }
- return layerNames;
- }
- }
- public void Initialize(Animator animator, SkeletonDataAsset skeletonDataAsset) {
- this.animator = animator;
- previousAnimations.Clear();
- animationTable.Clear();
- var data = skeletonDataAsset.GetSkeletonData(true);
- foreach (var a in data.Animations)
- animationTable.Add(a.Name.GetHashCode(), a);
- clipNameHashCodeTable.Clear();
- ClearClipInfosForLayers();
- }
- private bool ApplyAnimation (Skeleton skeleton, AnimatorClipInfo info, AnimatorStateInfo stateInfo,
- int layerIndex, float layerWeight, MixBlend layerBlendMode, bool useClipWeight1 = false) {
- float weight = info.weight * layerWeight;
- if (weight < WeightEpsilon)
- return false;
- var clip = GetAnimation(info.clip);
- if (clip == null)
- return false;
- var time = AnimationTime(stateInfo.normalizedTime, info.clip.length,
- info.clip.isLooping, stateInfo.speed < 0);
- weight = useClipWeight1 ? layerWeight : weight;
- clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
- weight, layerBlendMode, MixDirection.In);
- if (_OnClipApplied != null)
- OnClipAppliedCallback(clip, stateInfo, layerIndex, time, info.clip.isLooping, weight);
- return true;
- }
- private bool ApplyInterruptionAnimation (Skeleton skeleton,
- bool interpolateWeightTo1, AnimatorClipInfo info, AnimatorStateInfo stateInfo,
- int layerIndex, float layerWeight, MixBlend layerBlendMode, float interruptingClipTimeAddition,
- bool useClipWeight1 = false) {
- float clipWeight = interpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
- float weight = clipWeight * layerWeight;
- if (weight < WeightEpsilon)
- return false;
- var clip = GetAnimation(info.clip);
- if (clip == null)
- return false;
- var time = AnimationTime(stateInfo.normalizedTime + interruptingClipTimeAddition,
- info.clip.length, stateInfo.speed < 0);
- weight = useClipWeight1 ? layerWeight : weight;
- clip.Apply(skeleton, 0, time, info.clip.isLooping, null,
- weight, layerBlendMode, MixDirection.In);
- if (_OnClipApplied != null) {
- OnClipAppliedCallback(clip, stateInfo, layerIndex, time, info.clip.isLooping, weight);
- }
- return true;
- }
- private void OnClipAppliedCallback (Spine.Animation clip, AnimatorStateInfo stateInfo,
- int layerIndex, float time, bool isLooping, float weight) {
- float speedFactor = stateInfo.speedMultiplier * stateInfo.speed;
- float lastTime = time - (Time.deltaTime * speedFactor);
- if (isLooping && clip.duration != 0) {
- time %= clip.duration;
- lastTime %= clip.duration;
- }
- _OnClipApplied(clip, layerIndex, weight, time, lastTime, speedFactor < 0);
- }
- public void Apply (Skeleton skeleton) {
- #if UNITY_EDITOR
- if (!Application.isPlaying) {
- GetLayerBlendModes();
- }
- #endif
- if (layerMixModes.Length < animator.layerCount) {
- int oldSize = layerMixModes.Length;
- System.Array.Resize<MixMode>(ref layerMixModes, animator.layerCount);
- for (int layer = oldSize; layer < animator.layerCount; ++layer) {
- bool isAdditiveLayer = false;
- if (layer < layerBlendModes.Length)
- isAdditiveLayer = layerBlendModes[layer] == MixBlend.Add;
- layerMixModes[layer] = isAdditiveLayer ? MixMode.AlwaysMix : MixMode.MixNext;
- }
- }
- InitClipInfosForLayers();
- for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
- GetStateUpdatesFromAnimator(layer);
- }
- // Clear Previous
- if (autoReset) {
- var previousAnimations = this.previousAnimations;
- for (int i = 0, n = previousAnimations.Count; i < n; i++)
- previousAnimations[i].SetKeyedItemsToSetupPose(skeleton);
- previousAnimations.Clear();
- for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
- float layerWeight = (layer == 0) ? 1 : animator.GetLayerWeight(layer); // Animator.GetLayerWeight always returns 0 on the first layer. Should be interpreted as 1.
- if (layerWeight <= 0) continue;
- AnimatorStateInfo nextStateInfo = animator.GetNextAnimatorStateInfo(layer);
- bool hasNext = nextStateInfo.fullPathHash != 0;
- int clipInfoCount, nextClipInfoCount, interruptingClipInfoCount;
- IList<AnimatorClipInfo> clipInfo, nextClipInfo, interruptingClipInfo;
- bool isInterruptionActive, shallInterpolateWeightTo1;
- GetAnimatorClipInfos(layer, out isInterruptionActive, out clipInfoCount, out nextClipInfoCount, out interruptingClipInfoCount,
- out clipInfo, out nextClipInfo, out interruptingClipInfo, out shallInterpolateWeightTo1);
- for (int c = 0; c < clipInfoCount; c++) {
- var info = clipInfo[c];
- float weight = info.weight * layerWeight; if (weight < WeightEpsilon) continue;
- var clip = GetAnimation(info.clip);
- if (clip != null)
- previousAnimations.Add(clip);
- }
- if (hasNext) {
- for (int c = 0; c < nextClipInfoCount; c++) {
- var info = nextClipInfo[c];
- float weight = info.weight * layerWeight; if (weight < WeightEpsilon) continue;
- var clip = GetAnimation(info.clip);
- if (clip != null)
- previousAnimations.Add(clip);
- }
- }
- if (isInterruptionActive) {
- for (int c = 0; c < interruptingClipInfoCount; c++)
- {
- var info = interruptingClipInfo[c];
- float clipWeight = shallInterpolateWeightTo1 ? (info.weight + 1.0f) * 0.5f : info.weight;
- float weight = clipWeight * layerWeight; if (weight < WeightEpsilon) continue;
- var clip = GetAnimation(info.clip);
- if (clip != null)
- previousAnimations.Add(clip);
- }
- }
- }
- }
- // Apply
- for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
- float layerWeight = (layer == 0) ? 1 : animator.GetLayerWeight(layer); // Animator.GetLayerWeight always returns 0 on the first layer. Should be interpreted as 1.
- bool isInterruptionActive;
- AnimatorStateInfo stateInfo;
- AnimatorStateInfo nextStateInfo;
- AnimatorStateInfo interruptingStateInfo;
- float interruptingClipTimeAddition;
- GetAnimatorStateInfos(layer, out isInterruptionActive, out stateInfo, out nextStateInfo, out interruptingStateInfo, out interruptingClipTimeAddition);
- bool hasNext = nextStateInfo.fullPathHash != 0;
- int clipInfoCount, nextClipInfoCount, interruptingClipInfoCount;
- IList<AnimatorClipInfo> clipInfo, nextClipInfo, interruptingClipInfo;
- bool interpolateWeightTo1;
- GetAnimatorClipInfos(layer, out isInterruptionActive, out clipInfoCount, out nextClipInfoCount, out interruptingClipInfoCount,
- out clipInfo, out nextClipInfo, out interruptingClipInfo, out interpolateWeightTo1);
- MixBlend layerBlendMode = (layer < layerBlendModes.Length) ? layerBlendModes[layer] : MixBlend.Replace;
- MixMode mode = GetMixMode(layer, layerBlendMode);
- if (mode == MixMode.AlwaysMix) {
- // Always use Mix instead of Applying the first non-zero weighted clip.
- for (int c = 0; c < clipInfoCount; c++) {
- ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode);
- }
- if (hasNext) {
- for (int c = 0; c < nextClipInfoCount; c++) {
- ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode);
- }
- }
- if (isInterruptionActive) {
- for (int c = 0; c < interruptingClipInfoCount; c++)
- {
- ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
- interruptingClipInfo[c], interruptingStateInfo,
- layer, layerWeight, layerBlendMode, interruptingClipTimeAddition);
- }
- }
- } else { // case MixNext || Hard
- // Apply first non-zero weighted clip
- int c = 0;
- for (; c < clipInfoCount; c++) {
- if (!ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode, useClipWeight1:true))
- continue;
- ++c; break;
- }
- // Mix the rest
- for (; c < clipInfoCount; c++) {
- ApplyAnimation(skeleton, clipInfo[c], stateInfo, layer, layerWeight, layerBlendMode);
- }
- c = 0;
- if (hasNext) {
- // Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
- if (mode == MixMode.Hard) {
- for (; c < nextClipInfoCount; c++) {
- if (!ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode, useClipWeight1:true))
- continue;
- ++c; break;
- }
- }
- // Mix the rest
- for (; c < nextClipInfoCount; c++) {
- if (!ApplyAnimation(skeleton, nextClipInfo[c], nextStateInfo, layer, layerWeight, layerBlendMode))
- continue;
- }
- }
- c = 0;
- if (isInterruptionActive) {
- // Apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
- if (mode == MixMode.Hard) {
- for (; c < interruptingClipInfoCount; c++) {
- if (ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
- interruptingClipInfo[c], interruptingStateInfo,
- layer, layerWeight, layerBlendMode, interruptingClipTimeAddition, useClipWeight1:true)) {
- ++c; break;
- }
- }
- }
- // Mix the rest
- for (; c < interruptingClipInfoCount; c++) {
- ApplyInterruptionAnimation(skeleton, interpolateWeightTo1,
- interruptingClipInfo[c], interruptingStateInfo,
- layer, layerWeight, layerBlendMode, interruptingClipTimeAddition);
- }
- }
- }
- }
- }
- public KeyValuePair<Spine.Animation, float> GetActiveAnimationAndTime (int layer) {
- if (layer >= layerClipInfos.Length)
- return new KeyValuePair<Spine.Animation, float>(null, 0);
- var layerInfos = layerClipInfos[layer];
- bool isInterruptionActive = layerInfos.isInterruptionActive;
- AnimationClip clip = null;
- Spine.Animation animation = null;
- AnimatorStateInfo stateInfo;
- if (isInterruptionActive && layerInfos.interruptingClipInfoCount > 0) {
- clip = layerInfos.interruptingClipInfos[0].clip;
- stateInfo = layerInfos.interruptingStateInfo;
- }
- else {
- clip = layerInfos.clipInfos[0].clip;
- stateInfo = layerInfos.stateInfo;
- }
- animation = GetAnimation(clip);
- float time = AnimationTime(stateInfo.normalizedTime, clip.length,
- clip.isLooping, stateInfo.speed < 0);
- return new KeyValuePair<Animation, float>(animation, time);
- }
- static float AnimationTime (float normalizedTime, float clipLength, bool loop, bool reversed) {
- float time = AnimationTime(normalizedTime, clipLength, reversed);
- if (loop) return time;
- const float EndSnapEpsilon = 1f / 30f; // Workaround for end-duration keys not being applied.
- return (clipLength - time < EndSnapEpsilon) ? clipLength : time; // return a time snapped to clipLength;
- }
- static float AnimationTime (float normalizedTime, float clipLength, bool reversed) {
- if (reversed)
- normalizedTime = (1 - normalizedTime);
- if (normalizedTime < 0.0f)
- normalizedTime = (normalizedTime % 1.0f) + 1.0f;
- return normalizedTime * clipLength;
- }
- void InitClipInfosForLayers () {
- if (layerClipInfos.Length < animator.layerCount) {
- System.Array.Resize<ClipInfos>(ref layerClipInfos, animator.layerCount);
- for (int layer = 0, n = animator.layerCount; layer < n; ++layer) {
- if (layerClipInfos[layer] == null)
- layerClipInfos[layer] = new ClipInfos();
- }
- }
- }
- void ClearClipInfosForLayers () {
- for (int layer = 0, n = layerClipInfos.Length; layer < n; ++layer) {
- if (layerClipInfos[layer] == null)
- layerClipInfos[layer] = new ClipInfos();
- else {
- layerClipInfos[layer].isInterruptionActive = false;
- layerClipInfos[layer].isLastFrameOfInterruption = false;
- layerClipInfos[layer].clipInfos.Clear();
- layerClipInfos[layer].nextClipInfos.Clear();
- layerClipInfos[layer].interruptingClipInfos.Clear();
- }
- }
- }
- private MixMode GetMixMode (int layer, MixBlend layerBlendMode) {
- if (useCustomMixMode) {
- MixMode mode = layerMixModes[layer];
- // Note: at additive blending it makes no sense to use constant weight 1 at a fadeout anim add1 as
- // with override layers, so we use AlwaysMix instead to use the proper weights.
- // AlwaysMix leads to the expected result = lower_layer + lerp(add1, add2, transition_weight).
- if (layerBlendMode == MixBlend.Add && mode == MixMode.MixNext) {
- mode = MixMode.AlwaysMix;
- layerMixModes[layer] = mode;
- }
- return mode;
- }
- else {
- return layerBlendMode == MixBlend.Add ? MixMode.AlwaysMix : MixMode.MixNext;
- }
- }
- #if UNITY_EDITOR
- void GetLayerBlendModes() {
- if (layerBlendModes.Length < animator.layerCount) {
- System.Array.Resize<MixBlend>(ref layerBlendModes, animator.layerCount);
- }
- for (int layer = 0, n = animator.layerCount; layer < n; ++layer) {
- var controller = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
- if (controller != null) {
- layerBlendModes[layer] = MixBlend.First;
- if (layer > 0) {
- layerBlendModes[layer] = controller.layers[layer].blendingMode == UnityEditor.Animations.AnimatorLayerBlendingMode.Additive ?
- MixBlend.Add : MixBlend.Replace;
- }
- }
- }
- }
- #endif
- void GetStateUpdatesFromAnimator (int layer) {
- var layerInfos = layerClipInfos[layer];
- int clipInfoCount = animator.GetCurrentAnimatorClipInfoCount(layer);
- int nextClipInfoCount = animator.GetNextAnimatorClipInfoCount(layer);
- var clipInfos = layerInfos.clipInfos;
- var nextClipInfos = layerInfos.nextClipInfos;
- var interruptingClipInfos = layerInfos.interruptingClipInfos;
- layerInfos.isInterruptionActive = (clipInfoCount == 0 && clipInfos.Count != 0 &&
- nextClipInfoCount == 0 && nextClipInfos.Count != 0);
- // Note: during interruption, GetCurrentAnimatorClipInfoCount and GetNextAnimatorClipInfoCount
- // are returning 0 in calls above. Therefore we keep previous clipInfos and nextClipInfos
- // until the interruption is over.
- if (layerInfos.isInterruptionActive) {
- // Note: The last frame of a transition interruption
- // will have fullPathHash set to 0, therefore we have to use previous
- // frame's infos about interruption clips and correct some values
- // accordingly (normalizedTime and weight).
- var interruptingStateInfo = animator.GetNextAnimatorStateInfo(layer);
- layerInfos.isLastFrameOfInterruption = interruptingStateInfo.fullPathHash == 0;
- if (!layerInfos.isLastFrameOfInterruption) {
- animator.GetNextAnimatorClipInfo(layer, interruptingClipInfos);
- layerInfos.interruptingClipInfoCount = interruptingClipInfos.Count;
- float oldTime = layerInfos.interruptingStateInfo.normalizedTime;
- float newTime = interruptingStateInfo.normalizedTime;
- layerInfos.interruptingClipTimeAddition = newTime - oldTime;
- layerInfos.interruptingStateInfo = interruptingStateInfo;
- }
- } else {
- layerInfos.clipInfoCount = clipInfoCount;
- layerInfos.nextClipInfoCount = nextClipInfoCount;
- layerInfos.interruptingClipInfoCount = 0;
- layerInfos.isLastFrameOfInterruption = false;
- if (clipInfos.Capacity < clipInfoCount) clipInfos.Capacity = clipInfoCount;
- if (nextClipInfos.Capacity < nextClipInfoCount) nextClipInfos.Capacity = nextClipInfoCount;
- animator.GetCurrentAnimatorClipInfo(layer, clipInfos);
- animator.GetNextAnimatorClipInfo(layer, nextClipInfos);
- layerInfos.stateInfo = animator.GetCurrentAnimatorStateInfo(layer);
- layerInfos.nextStateInfo = animator.GetNextAnimatorStateInfo(layer);
- }
- }
- void GetAnimatorClipInfos (
- int layer,
- out bool isInterruptionActive,
- out int clipInfoCount,
- out int nextClipInfoCount,
- out int interruptingClipInfoCount,
- out IList<AnimatorClipInfo> clipInfo,
- out IList<AnimatorClipInfo> nextClipInfo,
- out IList<AnimatorClipInfo> interruptingClipInfo,
- out bool shallInterpolateWeightTo1) {
- var layerInfos = layerClipInfos[layer];
- isInterruptionActive = layerInfos.isInterruptionActive;
- clipInfoCount = layerInfos.clipInfoCount;
- nextClipInfoCount = layerInfos.nextClipInfoCount;
- interruptingClipInfoCount = layerInfos.interruptingClipInfoCount;
- clipInfo = layerInfos.clipInfos;
- nextClipInfo = layerInfos.nextClipInfos;
- interruptingClipInfo = isInterruptionActive ? layerInfos.interruptingClipInfos : null;
- shallInterpolateWeightTo1 = layerInfos.isLastFrameOfInterruption;
- }
- void GetAnimatorStateInfos (
- int layer,
- out bool isInterruptionActive,
- out AnimatorStateInfo stateInfo,
- out AnimatorStateInfo nextStateInfo,
- out AnimatorStateInfo interruptingStateInfo,
- out float interruptingClipTimeAddition) {
- var layerInfos = layerClipInfos[layer];
- isInterruptionActive = layerInfos.isInterruptionActive;
- stateInfo = layerInfos.stateInfo;
- nextStateInfo = layerInfos.nextStateInfo;
- interruptingStateInfo = layerInfos.interruptingStateInfo;
- interruptingClipTimeAddition = layerInfos.isLastFrameOfInterruption ? layerInfos.interruptingClipTimeAddition : 0;
- }
- Spine.Animation GetAnimation (AnimationClip clip) {
- int clipNameHashCode;
- if (!clipNameHashCodeTable.TryGetValue(clip, out clipNameHashCode)) {
- clipNameHashCode = clip.name.GetHashCode();
- clipNameHashCodeTable.Add(clip, clipNameHashCode);
- }
- Spine.Animation animation;
- animationTable.TryGetValue(clipNameHashCode, out animation);
- return animation;
- }
- class AnimationClipEqualityComparer : IEqualityComparer<AnimationClip> {
- internal static readonly IEqualityComparer<AnimationClip> Instance = new AnimationClipEqualityComparer();
- public bool Equals (AnimationClip x, AnimationClip y) { return x.GetInstanceID() == y.GetInstanceID(); }
- public int GetHashCode (AnimationClip o) { return o.GetInstanceID(); }
- }
- class IntEqualityComparer : IEqualityComparer<int> {
- internal static readonly IEqualityComparer<int> Instance = new IntEqualityComparer();
- public bool Equals (int x, int y) { return x == y; }
- public int GetHashCode(int o) { return o; }
- }
- }
- }
- }
|