Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
6.6 KiB

  1. // Rigidbody Follow|Utilities|90120
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Changes one GameObject's rigidbody to follow another GameObject's rigidbody.
  7. /// </summary>
  8. [AddComponentMenu("VRTK/Scripts/Utilities/Object Follow/VRTK_RigidbodyFollow")]
  9. public class VRTK_RigidbodyFollow : VRTK_ObjectFollow
  10. {
  11. /// <summary>
  12. /// Specifies how to position and rotate the rigidbody.
  13. /// </summary>
  14. public enum MovementOption
  15. {
  16. /// <summary>
  17. /// Use Rigidbody.position and Rigidbody.rotation.
  18. /// </summary>
  19. Set,
  20. /// <summary>
  21. /// Use Rigidbody.MovePosition and Rigidbody.MoveRotation.
  22. /// </summary>
  23. Move,
  24. /// <summary>
  25. /// Use Rigidbody.AddForce(Vector3) and Rigidbody.AddTorque(Vector3).
  26. /// </summary>
  27. Add,
  28. /// <summary>
  29. /// Use velocity and angular velocity with MoveTowards.
  30. /// </summary>
  31. Track
  32. }
  33. [Header("Follow Settings")]
  34. [Tooltip("Specifies how to position and rotate the rigidbody.")]
  35. public MovementOption movementOption = MovementOption.Set;
  36. [Header("Track Movement Settings")]
  37. [Tooltip("The maximum distance the tracked `Game Object To Change` Rigidbody can be from the `Game Object To Follow` Rigidbody before the position is forcibly set to match the position.")]
  38. public float trackMaxDistance = 0.25f;
  39. protected Rigidbody rigidbodyToFollow;
  40. protected Rigidbody rigidbodyToChange;
  41. protected float maxDistanceDelta = 10f;
  42. /// <summary>
  43. /// Follow `gameObjectToFollow` using the current settings.
  44. /// </summary>
  45. public override void Follow()
  46. {
  47. CacheRigidbodies();
  48. base.Follow();
  49. }
  50. protected virtual void OnDisable()
  51. {
  52. rigidbodyToFollow = null;
  53. rigidbodyToChange = null;
  54. }
  55. protected virtual void FixedUpdate()
  56. {
  57. Follow();
  58. }
  59. protected virtual void CacheRigidbodies()
  60. {
  61. if (gameObjectToFollow == null || gameObjectToChange == null || (rigidbodyToFollow != null && rigidbodyToChange != null))
  62. {
  63. return;
  64. }
  65. rigidbodyToFollow = gameObjectToFollow.GetComponent<Rigidbody>();
  66. rigidbodyToChange = gameObjectToChange.GetComponent<Rigidbody>();
  67. }
  68. protected override Vector3 GetPositionToFollow()
  69. {
  70. return (rigidbodyToFollow != null ? rigidbodyToFollow.position : Vector3.zero);
  71. }
  72. protected override Quaternion GetRotationToFollow()
  73. {
  74. return (rigidbodyToFollow != null ? rigidbodyToFollow.rotation : Quaternion.identity);
  75. }
  76. protected override Vector3 GetScaleToFollow()
  77. {
  78. return (rigidbodyToFollow != null ? rigidbodyToFollow.transform.localScale : Vector3.zero);
  79. }
  80. protected override void SetPositionOnGameObject(Vector3 newPosition)
  81. {
  82. switch (movementOption)
  83. {
  84. case MovementOption.Set:
  85. rigidbodyToChange.position = newPosition;
  86. break;
  87. case MovementOption.Move:
  88. rigidbodyToChange.MovePosition(newPosition);
  89. break;
  90. case MovementOption.Add:
  91. // TODO: Test if this is correct
  92. rigidbodyToChange.AddForce(newPosition - rigidbodyToChange.position);
  93. break;
  94. case MovementOption.Track:
  95. TrackPosition(newPosition);
  96. break;
  97. }
  98. }
  99. protected override void SetRotationOnGameObject(Quaternion newRotation)
  100. {
  101. switch (movementOption)
  102. {
  103. case MovementOption.Set:
  104. rigidbodyToChange.rotation = newRotation;
  105. break;
  106. case MovementOption.Move:
  107. rigidbodyToChange.MoveRotation(newRotation);
  108. break;
  109. case MovementOption.Add:
  110. // TODO: Test if this is correct
  111. rigidbodyToChange.AddTorque(newRotation * Quaternion.Inverse(rigidbodyToChange.rotation).eulerAngles);
  112. break;
  113. case MovementOption.Track:
  114. TrackRotation(newRotation);
  115. break;
  116. }
  117. }
  118. protected virtual void TrackPosition(Vector3 newPosition)
  119. {
  120. if (rigidbodyToFollow == null)
  121. {
  122. return;
  123. }
  124. if (Vector3.Distance(rigidbodyToChange.position, rigidbodyToFollow.position) > trackMaxDistance)
  125. {
  126. rigidbodyToChange.position = rigidbodyToFollow.position;
  127. rigidbodyToChange.rotation = rigidbodyToFollow.rotation;
  128. }
  129. float trackVelocityLimit = float.PositiveInfinity;
  130. Vector3 positionDelta = newPosition - rigidbodyToChange.position;
  131. Vector3 velocityTarget = positionDelta / Time.fixedDeltaTime;
  132. Vector3 calculatedVelocity = Vector3.MoveTowards(rigidbodyToChange.velocity, velocityTarget, maxDistanceDelta);
  133. if (trackVelocityLimit == float.PositiveInfinity || calculatedVelocity.sqrMagnitude < trackVelocityLimit)
  134. {
  135. rigidbodyToChange.velocity = calculatedVelocity;
  136. }
  137. }
  138. protected virtual void TrackRotation(Quaternion newRotation)
  139. {
  140. if (rigidbodyToFollow == null)
  141. {
  142. return;
  143. }
  144. float trackAngularVelocityLimit = float.PositiveInfinity;
  145. Quaternion rotationDelta = newRotation * Quaternion.Inverse(rigidbodyToChange.rotation);
  146. float angle;
  147. Vector3 axis;
  148. rotationDelta.ToAngleAxis(out angle, out axis);
  149. angle = ((angle > 180) ? angle -= 360 : angle);
  150. if (angle != 0)
  151. {
  152. Vector3 angularTarget = angle * axis;
  153. Vector3 calculatedAngularVelocity = Vector3.MoveTowards(rigidbodyToChange.angularVelocity, angularTarget, maxDistanceDelta);
  154. if (trackAngularVelocityLimit == float.PositiveInfinity || calculatedAngularVelocity.sqrMagnitude < trackAngularVelocityLimit)
  155. {
  156. rigidbodyToChange.angularVelocity = calculatedAngularVelocity;
  157. }
  158. }
  159. }
  160. }
  161. }