|
@@ -33,82 +33,93 @@ using UnityEngine;
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
namespace Spine.Unity.Modules {
|
|
|
+
|
|
|
+ // SkeletonUtilityKinematicShadow allows hinge chains to inherit a velocity interpreted from changes in parent transform position or from unrelated rigidbodies.
|
|
|
+ // Note: Uncheck "useRootTransformIfNull
|
|
|
public class SkeletonUtilityKinematicShadow : MonoBehaviour {
|
|
|
- public bool hideShadow = true;
|
|
|
+ #region Inspector
|
|
|
+ [Tooltip("If checked, the hinge chain can inherit your root transform's velocity or position/rotation changes.")]
|
|
|
+ public bool detachedShadow = false;
|
|
|
public Transform parent;
|
|
|
- Dictionary<Transform, Transform> shadowTable;
|
|
|
+ public bool hideShadow = true;
|
|
|
+ #endregion
|
|
|
+
|
|
|
GameObject shadowRoot;
|
|
|
+ readonly List<TransformPair> shadowTable = new List<TransformPair>();
|
|
|
+ struct TransformPair {
|
|
|
+ public Transform dest, src;
|
|
|
+ }
|
|
|
|
|
|
void Start () {
|
|
|
- shadowRoot = (GameObject)Instantiate(gameObject);
|
|
|
- if (hideShadow)
|
|
|
- shadowRoot.hideFlags = HideFlags.HideInHierarchy;
|
|
|
-
|
|
|
- if (parent == null)
|
|
|
- shadowRoot.transform.parent = transform.root;
|
|
|
- else
|
|
|
- shadowRoot.transform.parent = parent;
|
|
|
-
|
|
|
- shadowTable = new Dictionary<Transform, Transform>();
|
|
|
-
|
|
|
+ // Duplicate this gameObject as the "shadow" with a different parent.
|
|
|
+ shadowRoot = Instantiate<GameObject>(this.gameObject);
|
|
|
Destroy(shadowRoot.GetComponent<SkeletonUtilityKinematicShadow>());
|
|
|
|
|
|
- shadowRoot.transform.position = transform.position;
|
|
|
- shadowRoot.transform.rotation = transform.rotation;
|
|
|
+ // Prepare shadow gameObject's properties.
|
|
|
+ var shadowRootTransform = shadowRoot.transform;
|
|
|
+ shadowRootTransform.position = transform.position;
|
|
|
+ shadowRootTransform.rotation = transform.rotation;
|
|
|
|
|
|
Vector3 scaleRef = transform.TransformPoint(Vector3.right);
|
|
|
float scale = Vector3.Distance(transform.position, scaleRef);
|
|
|
- shadowRoot.transform.localScale = Vector3.one;
|
|
|
+ shadowRootTransform.localScale = Vector3.one;
|
|
|
+
|
|
|
+ if (!detachedShadow) {
|
|
|
+ // Do not change to null coalescing operator (??). Unity overloads null checks for UnityEngine.Objects but not the ?? operator.
|
|
|
+ if (parent == null)
|
|
|
+ shadowRootTransform.parent = transform.root;
|
|
|
+ else
|
|
|
+ shadowRootTransform.parent = parent;
|
|
|
+ }
|
|
|
|
|
|
+ if (hideShadow)
|
|
|
+ shadowRoot.hideFlags = HideFlags.HideInHierarchy;
|
|
|
+
|
|
|
var shadowJoints = shadowRoot.GetComponentsInChildren<Joint>();
|
|
|
- foreach (Joint j in shadowJoints) {
|
|
|
+ foreach (Joint j in shadowJoints)
|
|
|
j.connectedAnchor *= scale;
|
|
|
- }
|
|
|
-
|
|
|
- var joints = GetComponentsInChildren<Joint>();
|
|
|
- foreach (var j in joints)
|
|
|
- Destroy(j);
|
|
|
|
|
|
- var rbs = GetComponentsInChildren<Rigidbody>();
|
|
|
- foreach (var rb in rbs)
|
|
|
- Destroy(rb);
|
|
|
-
|
|
|
- var colliders = GetComponentsInChildren<Collider>();
|
|
|
- foreach (var c in colliders)
|
|
|
- Destroy(c);
|
|
|
-
|
|
|
-
|
|
|
- //match by bone name
|
|
|
- var shadowBones = shadowRoot.GetComponentsInChildren<SkeletonUtilityBone>();
|
|
|
+ // Build list of bone pairs (matches shadow transforms with bone transforms)
|
|
|
var bones = GetComponentsInChildren<SkeletonUtilityBone>();
|
|
|
-
|
|
|
- //build bone lookup
|
|
|
+ var shadowBones = shadowRoot.GetComponentsInChildren<SkeletonUtilityBone>();
|
|
|
foreach (var b in bones) {
|
|
|
- if (b.gameObject == gameObject)
|
|
|
+ if (b.gameObject == this.gameObject)
|
|
|
continue;
|
|
|
-
|
|
|
+
|
|
|
foreach (var sb in shadowBones) {
|
|
|
- if (sb.GetComponent<Rigidbody>() == null)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (sb.boneName == b.boneName) {
|
|
|
- shadowTable.Add(sb.transform, b.transform);
|
|
|
+ if (sb.GetComponent<Rigidbody>() != null && sb.boneName == b.boneName) {
|
|
|
+ shadowTable.Add(new TransformPair {
|
|
|
+ dest = b.transform,
|
|
|
+ src = sb.transform
|
|
|
+ });
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
- foreach (var b in shadowBones)
|
|
|
- Destroy(b);
|
|
|
+ // Destroy conflicting and unneeded components
|
|
|
+ DestroyComponents(shadowBones);
|
|
|
+
|
|
|
+ DestroyComponents(GetComponentsInChildren<Joint>());
|
|
|
+ DestroyComponents(GetComponentsInChildren<Rigidbody>());
|
|
|
+ DestroyComponents(GetComponentsInChildren<Collider>());
|
|
|
}
|
|
|
|
|
|
- void FixedUpdate () {
|
|
|
- shadowRoot.GetComponent<Rigidbody>().MovePosition(transform.position);
|
|
|
- shadowRoot.GetComponent<Rigidbody>().MoveRotation(transform.rotation);
|
|
|
+ static void DestroyComponents (Component[] components) {
|
|
|
+ for (int i = 0, n = components.Length; i < n; i++)
|
|
|
+ Destroy(components[i]);
|
|
|
+ }
|
|
|
|
|
|
- foreach (var pair in shadowTable) {
|
|
|
- pair.Value.localPosition = pair.Key.localPosition;
|
|
|
- pair.Value.localRotation = pair.Key.localRotation;
|
|
|
+ void FixedUpdate () {
|
|
|
+ var shadowRootRigidbody = shadowRoot.GetComponent<Rigidbody>();
|
|
|
+ shadowRootRigidbody.MovePosition(transform.position);
|
|
|
+ shadowRootRigidbody.MoveRotation(transform.rotation);
|
|
|
+
|
|
|
+ for (int i = 0, n = shadowTable.Count; i < n; i++) {
|
|
|
+ var pair = shadowTable[i];
|
|
|
+ pair.dest.localPosition = pair.src.localPosition;
|
|
|
+ pair.dest.localRotation = pair.src.localRotation;
|
|
|
}
|
|
|
}
|
|
|
}
|