mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
[unity] Fixed RootMotion scripts in combination with Rigidbody components. Now works smoothly. Closes #1880.
This commit is contained in:
parent
692eed3a75
commit
e425d64d2c
@ -48,7 +48,9 @@ namespace Spine.Unity {
|
|||||||
|
|
||||||
public float rootMotionScaleX = 1;
|
public float rootMotionScaleX = 1;
|
||||||
public float rootMotionScaleY = 1;
|
public float rootMotionScaleY = 1;
|
||||||
|
/// <summary>Skeleton space X translation per skeleton space Y translation root motion.</summary>
|
||||||
public float rootMotionTranslateXPerY = 0;
|
public float rootMotionTranslateXPerY = 0;
|
||||||
|
/// <summary>Skeleton space Y translation per skeleton space X translation root motion.</summary>
|
||||||
public float rootMotionTranslateYPerX = 0;
|
public float rootMotionTranslateYPerX = 0;
|
||||||
|
|
||||||
[Header("Optional")]
|
[Header("Optional")]
|
||||||
@ -65,6 +67,7 @@ namespace Spine.Unity {
|
|||||||
protected int rootMotionBoneIndex;
|
protected int rootMotionBoneIndex;
|
||||||
protected List<Bone> topLevelBones = new List<Bone>();
|
protected List<Bone> topLevelBones = new List<Bone>();
|
||||||
protected Vector2 initialOffset = Vector2.zero;
|
protected Vector2 initialOffset = Vector2.zero;
|
||||||
|
protected Vector2 tempSkeletonDisplacement;
|
||||||
protected Vector2 rigidbodyDisplacement;
|
protected Vector2 rigidbodyDisplacement;
|
||||||
|
|
||||||
protected virtual void Reset () {
|
protected virtual void Reset () {
|
||||||
@ -97,11 +100,16 @@ namespace Spine.Unity {
|
|||||||
rigidBody.MovePosition(transform.position
|
rigidBody.MovePosition(transform.position
|
||||||
+ new Vector3(rigidbodyDisplacement.x, rigidbodyDisplacement.y, 0));
|
+ new Vector3(rigidbodyDisplacement.x, rigidbodyDisplacement.y, 0));
|
||||||
}
|
}
|
||||||
|
Vector2 parentBoneScale;
|
||||||
|
GetScaleAffectingRootMotion(out parentBoneScale);
|
||||||
|
ClearEffectiveBoneOffsets(parentBoneScale);
|
||||||
rigidbodyDisplacement = Vector2.zero;
|
rigidbodyDisplacement = Vector2.zero;
|
||||||
|
tempSkeletonDisplacement = Vector2.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnDisable () {
|
protected virtual void OnDisable () {
|
||||||
rigidbodyDisplacement = Vector2.zero;
|
rigidbodyDisplacement = Vector2.zero;
|
||||||
|
tempSkeletonDisplacement = Vector2.zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void FindRigidbodyComponent () {
|
protected void FindRigidbodyComponent () {
|
||||||
@ -147,26 +155,27 @@ namespace Spine.Unity {
|
|||||||
float minX = 0, float maxX = float.MaxValue, float minY = 0, float maxY = float.MaxValue,
|
float minX = 0, float maxX = float.MaxValue, float minY = 0, float maxY = float.MaxValue,
|
||||||
bool allowXTranslation = false, bool allowYTranslation = false) {
|
bool allowXTranslation = false, bool allowYTranslation = false) {
|
||||||
|
|
||||||
distanceToTarget = (Vector2)transform.InverseTransformVector(distanceToTarget);
|
Vector2 distanceToTargetSkeletonSpace = (Vector2)transform.InverseTransformVector(distanceToTarget);
|
||||||
|
|
||||||
Vector2 scaleAffectingRootMotion = GetScaleAffectingRootMotion();
|
Vector2 scaleAffectingRootMotion = GetScaleAffectingRootMotion();
|
||||||
distanceToTarget.Scale(new Vector2(1f / scaleAffectingRootMotion.x, 1f / scaleAffectingRootMotion.y));
|
if (UsesRigidbody)
|
||||||
|
distanceToTargetSkeletonSpace -= tempSkeletonDisplacement;
|
||||||
|
|
||||||
Vector2 remainingRootMotion = GetRemainingRootMotion(trackIndex);
|
Vector2 remainingRootMotionSkeletonSpace = GetRemainingRootMotion(trackIndex);
|
||||||
if (remainingRootMotion.x == 0)
|
remainingRootMotionSkeletonSpace.Scale(scaleAffectingRootMotion);
|
||||||
remainingRootMotion.x = 0.0001f;
|
if (remainingRootMotionSkeletonSpace.x == 0)
|
||||||
if (remainingRootMotion.y == 0)
|
remainingRootMotionSkeletonSpace.x = 0.0001f;
|
||||||
remainingRootMotion.y = 0.0001f;
|
if (remainingRootMotionSkeletonSpace.y == 0)
|
||||||
|
remainingRootMotionSkeletonSpace.y = 0.0001f;
|
||||||
if (allowXTranslation)
|
|
||||||
rootMotionTranslateXPerY = (distanceToTarget.x - remainingRootMotion.x) / Math.Abs(remainingRootMotion.y);
|
|
||||||
if (allowYTranslation)
|
|
||||||
rootMotionTranslateYPerX = (distanceToTarget.y - remainingRootMotion.y) / Math.Abs(remainingRootMotion.x);
|
|
||||||
|
|
||||||
if (adjustX)
|
if (adjustX)
|
||||||
rootMotionScaleX = Math.Min(maxX, Math.Max(minX, distanceToTarget.x / remainingRootMotion.x));
|
rootMotionScaleX = Math.Min(maxX, Math.Max(minX, distanceToTargetSkeletonSpace.x / remainingRootMotionSkeletonSpace.x));
|
||||||
if (adjustY)
|
if (adjustY)
|
||||||
rootMotionScaleY = Math.Min(maxY, Math.Max(minY, distanceToTarget.y / remainingRootMotion.y));
|
rootMotionScaleY = Math.Min(maxY, Math.Max(minY, distanceToTargetSkeletonSpace.y / remainingRootMotionSkeletonSpace.y));
|
||||||
|
|
||||||
|
if (allowXTranslation)
|
||||||
|
rootMotionTranslateXPerY = (distanceToTargetSkeletonSpace.x - remainingRootMotionSkeletonSpace.x * rootMotionScaleX) / remainingRootMotionSkeletonSpace.y;
|
||||||
|
if (allowYTranslation)
|
||||||
|
rootMotionTranslateYPerX = (distanceToTargetSkeletonSpace.y - remainingRootMotionSkeletonSpace.y * rootMotionScaleY) / remainingRootMotionSkeletonSpace.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 GetAnimationRootMotion (Animation animation) {
|
public Vector2 GetAnimationRootMotion (Animation animation) {
|
||||||
@ -225,10 +234,27 @@ namespace Spine.Unity {
|
|||||||
if (!this.isActiveAndEnabled)
|
if (!this.isActiveAndEnabled)
|
||||||
return; // Root motion is only applied when component is enabled.
|
return; // Root motion is only applied when component is enabled.
|
||||||
|
|
||||||
var movementDelta = CalculateAnimationsMovementDelta();
|
var boneLocalDelta = CalculateAnimationsMovementDelta();
|
||||||
Vector2 parentBoneScale;
|
Vector2 parentBoneScale;
|
||||||
AdjustMovementDeltaToConfiguration(ref movementDelta, out parentBoneScale, animatedSkeletonComponent.Skeleton);
|
Vector2 skeletonDelta = GetSkeletonSpaceMovementDelta(boneLocalDelta, out parentBoneScale);
|
||||||
ApplyRootMotion(movementDelta, parentBoneScale);
|
ApplyRootMotion(skeletonDelta, parentBoneScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyRootMotion (Vector2 skeletonDelta, Vector2 parentBoneScale) {
|
||||||
|
// Apply root motion to Transform or RigidBody;
|
||||||
|
if (UsesRigidbody) {
|
||||||
|
rigidbodyDisplacement += (Vector2)transform.TransformVector(skeletonDelta);
|
||||||
|
|
||||||
|
// Accumulated displacement is applied on the next Physics update in FixedUpdate.
|
||||||
|
// Until the next Physics update, tempBoneDisplacement is offsetting bone locations
|
||||||
|
// to prevent stutter which would otherwise occur if we don't move every Update.
|
||||||
|
tempSkeletonDisplacement += skeletonDelta;
|
||||||
|
SetEffectiveBoneOffsetsTo(tempSkeletonDisplacement, parentBoneScale);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
transform.position += transform.TransformVector(skeletonDelta);
|
||||||
|
ClearEffectiveBoneOffsets(parentBoneScale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 GetScaleAffectingRootMotion () {
|
Vector2 GetScaleAffectingRootMotion () {
|
||||||
@ -253,44 +279,44 @@ namespace Spine.Unity {
|
|||||||
return totalScale;
|
return totalScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdjustMovementDeltaToConfiguration (ref Vector2 localDelta, out Vector2 parentBoneScale, Skeleton skeleton) {
|
Vector2 GetSkeletonSpaceMovementDelta (Vector2 boneLocalDelta, out Vector2 parentBoneScale) {
|
||||||
|
Vector2 skeletonDelta = boneLocalDelta;
|
||||||
Vector2 totalScale = GetScaleAffectingRootMotion(out parentBoneScale);
|
Vector2 totalScale = GetScaleAffectingRootMotion(out parentBoneScale);
|
||||||
localDelta.Scale(totalScale);
|
skeletonDelta.Scale(totalScale);
|
||||||
|
|
||||||
Vector2 rootMotionTranslation = new Vector2(
|
Vector2 rootMotionTranslation = new Vector2(
|
||||||
rootMotionTranslateXPerY * Math.Abs(localDelta.y),
|
rootMotionTranslateXPerY * skeletonDelta.y,
|
||||||
rootMotionTranslateYPerX * Math.Abs(localDelta.x));
|
rootMotionTranslateYPerX * skeletonDelta.x);
|
||||||
|
|
||||||
localDelta.x *= rootMotionScaleX;
|
skeletonDelta.x *= rootMotionScaleX;
|
||||||
localDelta.y *= rootMotionScaleY;
|
skeletonDelta.y *= rootMotionScaleY;
|
||||||
localDelta.x += rootMotionTranslation.x;
|
skeletonDelta.x += rootMotionTranslation.x;
|
||||||
localDelta.y += rootMotionTranslation.y;
|
skeletonDelta.y += rootMotionTranslation.y;
|
||||||
|
|
||||||
if (!transformPositionX) localDelta.x = 0f;
|
if (!transformPositionX) skeletonDelta.x = 0f;
|
||||||
if (!transformPositionY) localDelta.y = 0f;
|
if (!transformPositionY) skeletonDelta.y = 0f;
|
||||||
|
return skeletonDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyRootMotion (Vector2 localDelta, Vector2 parentBoneScale) {
|
void SetEffectiveBoneOffsetsTo (Vector2 displacementSkeletonSpace, Vector2 parentBoneScale) {
|
||||||
// Apply root motion to Transform or RigidBody;
|
|
||||||
if (UsesRigidbody) {
|
|
||||||
rigidbodyDisplacement += (Vector2)transform.TransformVector(localDelta);
|
|
||||||
// Accumulated displacement is applied on the next Physics update (FixedUpdate)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
transform.position += transform.TransformVector(localDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move top level bones in opposite direction of the root motion bone
|
// Move top level bones in opposite direction of the root motion bone
|
||||||
|
var skeleton = skeletonComponent.Skeleton;
|
||||||
foreach (var topLevelBone in topLevelBones) {
|
foreach (var topLevelBone in topLevelBones) {
|
||||||
if (topLevelBone == rootMotionBone) {
|
if (topLevelBone == rootMotionBone) {
|
||||||
if (transformPositionX) topLevelBone.x = 0;
|
if (transformPositionX) topLevelBone.x = displacementSkeletonSpace.x / skeleton.ScaleX;
|
||||||
if (transformPositionY) topLevelBone.y = 0;
|
if (transformPositionY) topLevelBone.y = displacementSkeletonSpace.y / skeleton.ScaleY;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (transformPositionX) topLevelBone.x = -(rootMotionBone.x - initialOffset.x) * parentBoneScale.x;
|
float offsetX = (initialOffset.x - rootMotionBone.x) * parentBoneScale.x;
|
||||||
if (transformPositionY) topLevelBone.y = -(rootMotionBone.y - initialOffset.y) * parentBoneScale.y;
|
float offsetY = (initialOffset.y - rootMotionBone.y) * parentBoneScale.y;
|
||||||
|
if (transformPositionX) topLevelBone.x = (displacementSkeletonSpace.x / skeleton.ScaleX) + offsetX;
|
||||||
|
if (transformPositionY) topLevelBone.y = (displacementSkeletonSpace.y / skeleton.ScaleY) + offsetY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearEffectiveBoneOffsets (Vector2 parentBoneScale) {
|
||||||
|
SetEffectiveBoneOffsetsTo(Vector2.zero, parentBoneScale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user