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

This commit is contained in:
Harald Csaszar 2021-12-07 19:13:03 +01:00
parent 8a89b7399a
commit 7e765c1b5b
2 changed files with 74 additions and 4 deletions

View File

@ -202,6 +202,8 @@ namespace Spine.Unity {
return Vector2.zero;
TranslateTimeline translateTimeline = animation.FindTranslateTimelineForBone(rootMotionBoneIndex);
TranslateXTimeline xTimeline = animation.FindTimelineForBone<TranslateXTimeline>(rootMotionBoneIndex);
TranslateYTimeline yTimeline = animation.FindTimelineForBone<TranslateYTimeline>(rootMotionBoneIndex);
// Non-looped base
Vector2 endPos = Vector2.zero;
@ -209,6 +211,9 @@ namespace Spine.Unity {
if (translateTimeline != null) {
endPos = translateTimeline.Evaluate(endTime);
startPos = translateTimeline.Evaluate(startTime);
} else if (xTimeline != null || yTimeline != null) {
endPos = TimelineExtensions.Evaluate(xTimeline, yTimeline, endTime);
startPos = TimelineExtensions.Evaluate(xTimeline, yTimeline, startTime);
}
var transformConstraintsItems = skeletonComponent.Skeleton.TransformConstraints.Items;
foreach (int constraintIndex in this.transformConstraintIndices) {
@ -225,6 +230,9 @@ namespace Spine.Unity {
if (translateTimeline != null) {
loopPos = translateTimeline.Evaluate(animation.Duration);
zeroPos = translateTimeline.Evaluate(0);
} else if (xTimeline != null || yTimeline != null) {
loopPos = TimelineExtensions.Evaluate(xTimeline, yTimeline, animation.Duration);
zeroPos = TimelineExtensions.Evaluate(xTimeline, yTimeline, 0);
}
foreach (int constraintIndex in this.transformConstraintIndices) {
TransformConstraint constraint = transformConstraintsItems[constraintIndex];
@ -266,15 +274,25 @@ namespace Spine.Unity {
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;
}
@ -293,6 +311,24 @@ namespace Spine.Unity {
}
}
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;

View File

@ -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>Evaluates the resulting X and Y translate mix values of a
/// TransformConstraintTimeline at a given time.</summary>
public static Vector2 EvaluateTranslateXYMix (this TransformConstraintTimeline timeline, float time) {
@ -78,6 +99,19 @@ 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;
}
/// <summary>Gets the transform constraint timeline for a given boneIndex.
/// You can get the boneIndex using SkeletonData.FindBone().Index.
/// The root bone is always boneIndex 0.