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.

169 lines
6.0 KiB

  1. // Object Follow|Utilities|90110
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Abstract class that allows to change one game object's properties to follow another game object.
  7. /// </summary>
  8. public abstract class VRTK_ObjectFollow : MonoBehaviour
  9. {
  10. [Header("Object Settings")]
  11. [Tooltip("The game object to follow. The followed property values will be taken from this one.")]
  12. public GameObject gameObjectToFollow;
  13. [Tooltip("The game object to change the property values of. If left empty the game object this script is attached to will be changed.")]
  14. public GameObject gameObjectToChange;
  15. [Header("Position Settings")]
  16. [Tooltip("Whether to follow the position of the given game object.")]
  17. public bool followsPosition = true;
  18. [Tooltip("Whether to smooth the position when following `gameObjectToFollow`.")]
  19. public bool smoothsPosition;
  20. [Tooltip("The maximum allowed distance between the unsmoothed source and the smoothed target per frame to use for smoothing.")]
  21. public float maxAllowedPerFrameDistanceDifference = 0.003f;
  22. /// <summary>
  23. /// The position that results by following `gameObjectToFollow`.
  24. /// </summary>
  25. public Vector3 targetPosition { get; private set; }
  26. [Header("Rotation Settings")]
  27. [Tooltip("Whether to follow the rotation of the given game object.")]
  28. public bool followsRotation = true;
  29. [Tooltip("Whether to smooth the rotation when following `gameObjectToFollow`.")]
  30. public bool smoothsRotation;
  31. [Tooltip("The maximum allowed angle between the unsmoothed source and the smoothed target per frame to use for smoothing.")]
  32. public float maxAllowedPerFrameAngleDifference = 1.5f;
  33. /// <summary>
  34. /// The rotation that results by following `gameObjectToFollow`.
  35. /// </summary>
  36. public Quaternion targetRotation { get; private set; }
  37. [Header("Scale Settings")]
  38. [Tooltip("Whether to follow the scale of the given game object.")]
  39. public bool followsScale = true;
  40. [Tooltip("Whether to smooth the scale when following `gameObjectToFollow`.")]
  41. public bool smoothsScale;
  42. [Tooltip("The maximum allowed size between the unsmoothed source and the smoothed target per frame to use for smoothing.")]
  43. public float maxAllowedPerFrameSizeDifference = 0.003f;
  44. /// <summary>
  45. /// The scale that results by following `gameObjectToFollow`.
  46. /// </summary>
  47. public Vector3 targetScale { get; private set; }
  48. /// <summary>
  49. /// Follow `gameObjectToFollow` using the current settings.
  50. /// </summary>
  51. public virtual void Follow()
  52. {
  53. if (gameObjectToFollow == null)
  54. {
  55. return;
  56. }
  57. if (followsPosition)
  58. {
  59. FollowPosition();
  60. }
  61. if (followsRotation)
  62. {
  63. FollowRotation();
  64. }
  65. if (followsScale)
  66. {
  67. FollowScale();
  68. }
  69. }
  70. protected virtual void OnEnable()
  71. {
  72. gameObjectToChange = gameObjectToChange != null ? gameObjectToChange : gameObject;
  73. }
  74. protected virtual void OnValidate()
  75. {
  76. maxAllowedPerFrameDistanceDifference = Mathf.Max(0.0001f, maxAllowedPerFrameDistanceDifference);
  77. maxAllowedPerFrameAngleDifference = Mathf.Max(0.0001f, maxAllowedPerFrameAngleDifference);
  78. maxAllowedPerFrameSizeDifference = Mathf.Max(0.0001f, maxAllowedPerFrameSizeDifference);
  79. }
  80. protected abstract Vector3 GetPositionToFollow();
  81. protected abstract void SetPositionOnGameObject(Vector3 newPosition);
  82. protected abstract Quaternion GetRotationToFollow();
  83. protected abstract void SetRotationOnGameObject(Quaternion newRotation);
  84. protected virtual Vector3 GetScaleToFollow()
  85. {
  86. return gameObjectToFollow.transform.localScale;
  87. }
  88. protected virtual void SetScaleOnGameObject(Vector3 newScale)
  89. {
  90. gameObjectToChange.transform.localScale = newScale;
  91. }
  92. protected virtual void FollowPosition()
  93. {
  94. Vector3 positionToFollow = GetPositionToFollow();
  95. Vector3 newPosition;
  96. if (smoothsPosition)
  97. {
  98. float alpha = Mathf.Clamp01(Vector3.Distance(targetPosition, positionToFollow) / maxAllowedPerFrameDistanceDifference);
  99. newPosition = Vector3.Lerp(targetPosition, positionToFollow, alpha);
  100. }
  101. else
  102. {
  103. newPosition = positionToFollow;
  104. }
  105. targetPosition = newPosition;
  106. SetPositionOnGameObject(newPosition);
  107. }
  108. protected virtual void FollowRotation()
  109. {
  110. Quaternion rotationToFollow = GetRotationToFollow();
  111. Quaternion newRotation;
  112. if (smoothsRotation)
  113. {
  114. float alpha = Mathf.Clamp01(Quaternion.Angle(targetRotation, rotationToFollow) / maxAllowedPerFrameAngleDifference);
  115. newRotation = Quaternion.Lerp(targetRotation, rotationToFollow, alpha);
  116. }
  117. else
  118. {
  119. newRotation = rotationToFollow;
  120. }
  121. targetRotation = newRotation;
  122. SetRotationOnGameObject(newRotation);
  123. }
  124. protected virtual void FollowScale()
  125. {
  126. Vector3 scaleToFollow = GetScaleToFollow();
  127. Vector3 newScale;
  128. if (smoothsScale)
  129. {
  130. float alpha = Mathf.Clamp01(Vector3.Distance(targetScale, scaleToFollow) / maxAllowedPerFrameSizeDifference);
  131. newScale = Vector3.Lerp(targetScale, scaleToFollow, alpha);
  132. }
  133. else
  134. {
  135. newScale = scaleToFollow;
  136. }
  137. targetScale = newScale;
  138. SetScaleOnGameObject(newScale);
  139. }
  140. }
  141. }