Browse Source

[unity] Fixed root motion components ignoring split translate timelines. Closes #1997.

Harald Csaszar 3 years ago
parent
commit
bb7804ac9e

+ 38 - 5
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<TranslateXTimeline>(rootMotionBoneIndex);
+			TranslateYTimeline yTimeline = animation.FindTimelineForBone<TranslateYTimeline>(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<TranslateXTimeline>(rootMotionBoneIndex);
+			TranslateYTimeline yTimeline = animation.FindTimelineForBone<TranslateYTimeline>(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;

+ 34 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/TimelineExtensions.cs

@@ -52,6 +52,27 @@ namespace Spine.Unity.AnimationTools {
 			}
 		}
 
+		/// <summary>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.</summary>
+		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);
+			}
+		}
+
 		/// <summary>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;
 		}
+
+		/// <summary>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.</summary>
+		public static T FindTimelineForBone<T> (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;
+		}
 	}
 }