diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs index 6b344f7bd..34072190c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/RootMotion/SkeletonRootMotionBase.cs @@ -196,24 +196,39 @@ namespace Spine.Unity { public Vector2 GetAnimationRootMotion (float startTime, float endTime, Animation animation) { - var timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex); + TranslateTimeline timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex); if (timeline != null) { return GetTimelineMovementDelta(startTime, endTime, timeline, animation); } + TranslateXTimeline xTimeline = animation.FindTimelineForBone(rootMotionBoneIndex); + TranslateYTimeline yTimeline = animation.FindTimelineForBone(rootMotionBoneIndex); + if (xTimeline != null || yTimeline != null) { + return GetTimelineMovementDelta(startTime, endTime, xTimeline, yTimeline, animation); + } return Vector2.zero; } public RootMotionInfo GetAnimationRootMotionInfo (Animation animation, float currentTime) { RootMotionInfo rootMotion = new RootMotionInfo(); - var timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex); + float duration = animation.Duration; + float mid = duration * 0.5f; + rootMotion.timeIsPastMid = currentTime > mid; + TranslateTimeline timeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex); if (timeline != null) { - float duration = animation.Duration; - float mid = duration * 0.5f; rootMotion.start = timeline.Evaluate(0); rootMotion.current = timeline.Evaluate(currentTime); rootMotion.mid = timeline.Evaluate(mid); rootMotion.end = timeline.Evaluate(duration); - rootMotion.timeIsPastMid = currentTime > mid; + return rootMotion; + } + TranslateXTimeline xTimeline = animation.FindTimelineForBone(rootMotionBoneIndex); + TranslateYTimeline yTimeline = animation.FindTimelineForBone(rootMotionBoneIndex); + if (xTimeline != null || yTimeline != null) { + rootMotion.start = TimelineExtensions.Evaluate(xTimeline, yTimeline, 0); + rootMotion.current = TimelineExtensions.Evaluate(xTimeline, yTimeline, currentTime); + rootMotion.mid = TimelineExtensions.Evaluate(xTimeline, yTimeline, mid); + rootMotion.end = TimelineExtensions.Evaluate(xTimeline, yTimeline, duration); + return rootMotion; } return rootMotion; } @@ -232,6 +247,24 @@ namespace Spine.Unity { return currentDelta; } + Vector2 GetTimelineMovementDelta (float startTime, float endTime, + TranslateXTimeline xTimeline, TranslateYTimeline yTimeline, Animation animation) { + + Vector2 currentDelta; + if (startTime > endTime) // Looped + currentDelta = + (TimelineExtensions.Evaluate(xTimeline, yTimeline, animation.Duration) + - TimelineExtensions.Evaluate(xTimeline, yTimeline, startTime)) + + (TimelineExtensions.Evaluate(xTimeline, yTimeline, endTime) + - TimelineExtensions.Evaluate(xTimeline, yTimeline, 0)); + else if (startTime != endTime) // Non-looped + currentDelta = TimelineExtensions.Evaluate(xTimeline, yTimeline, endTime) + - TimelineExtensions.Evaluate(xTimeline, yTimeline, startTime); + else + currentDelta = Vector2.zero; + return currentDelta; + } + void GatherTopLevelBones () { topLevelBones.Clear(); var skeleton = skeletonComponent.Skeleton; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/TimelineExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/TimelineExtensions.cs index 9d9b60093..39a806e93 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/TimelineExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/TimelineExtensions.cs @@ -52,6 +52,27 @@ namespace Spine.Unity.AnimationTools { } } + /// Evaluates the resulting value of a pair of split translate timelines at a given time. + /// SkeletonData can be accessed from Skeleton.Data or from SkeletonDataAsset.GetSkeletonData. + /// If no SkeletonData is given, values are returned as difference to setup pose + /// instead of absolute values. + public static Vector2 Evaluate (TranslateXTimeline xTimeline, TranslateYTimeline yTimeline, + float time, SkeletonData skeletonData = null) { + + float x = 0, y = 0; + if (xTimeline != null && time > xTimeline.Frames[0]) x = xTimeline.GetCurveValue(time); + if (yTimeline != null && time > yTimeline.Frames[0]) y = yTimeline.GetCurveValue(time); + + if (skeletonData == null) { + return new Vector2(x, y); + } else { + var bonesItems = skeletonData.Bones.Items; + BoneData boneDataX = bonesItems[xTimeline.BoneIndex]; + BoneData boneDataY = bonesItems[yTimeline.BoneIndex]; + return new Vector2(boneDataX.X + x, boneDataY.Y + y); + } + } + /// Gets the translate timeline for a given boneIndex. /// You can get the boneIndex using SkeletonData.FindBoneIndex. /// The root bone is always boneIndex 0. @@ -67,5 +88,18 @@ namespace Spine.Unity.AnimationTools { } return null; } + + /// Gets the IBoneTimeline timeline of a given type for a given boneIndex. + /// You can get the boneIndex using SkeletonData.FindBoneIndex. + /// The root bone is always boneIndex 0. + /// This will return null if a timeline of the given type is not found. + public static T FindTimelineForBone (this Animation a, int boneIndex) where T : class, IBoneTimeline { + foreach (var timeline in a.Timelines) { + T translateTimeline = timeline as T; + if (translateTimeline != null && translateTimeline.BoneIndex == boneIndex) + return translateTimeline; + } + return null; + } } }