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.

281 lines
13 KiB

  1. // Slider|Controls3D|100090
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Attaching the script to a game object will allow the user to interact with it as if it were a horizontal or vertical slider. The direction can be freely set and auto-detection is supported.
  7. /// </summary>
  8. /// <remarks>
  9. /// The script will instantiate the required Rigidbody and Interactable components automatically in case they do not exist yet.
  10. /// </remarks>
  11. /// <example>
  12. /// `VRTK/Examples/025_Controls_Overview` has a selection of sliders at various angles with different step values to demonstrate their usage.
  13. /// </example>
  14. [AddComponentMenu("VRTK/Scripts/Controls/3D/VRTK_Slider")]
  15. [System.Obsolete("`VRTK.VRTK_Drawer` has been deprecated and can be recreated with `VRTK.Controllables.PhysicsBased.VRTK_PhysicsSlider`. This script will be removed in a future version of VRTK.")]
  16. public class VRTK_Slider : VRTK_Control
  17. {
  18. [Tooltip("An optional game object to which the wheel will be connected. If the game object moves the wheel will follow along.")]
  19. public GameObject connectedTo;
  20. [Tooltip("The axis on which the slider should move. All other axis will be frozen.")]
  21. public Direction direction = Direction.autodetect;
  22. [Tooltip("The collider to specify the minimum limit of the slider.")]
  23. public Collider minimumLimit;
  24. [Tooltip("The collider to specify the maximum limit of the slider.")]
  25. public Collider maximumLimit;
  26. [Tooltip("The minimum value of the slider.")]
  27. public float minimumValue = 0f;
  28. [Tooltip("The maximum value of the slider.")]
  29. public float maximumValue = 100f;
  30. [Tooltip("The increments in which slider values can change.")]
  31. public float stepSize = 0.1f;
  32. [Tooltip("If this is checked then when the slider is released, it will snap to the nearest value position.")]
  33. public bool snapToStep = false;
  34. [Tooltip("The amount of friction the slider will have when it is released.")]
  35. public float releasedFriction = 50f;
  36. protected Direction finalDirection;
  37. protected Rigidbody sliderRigidbody;
  38. protected ConfigurableJoint sliderJoint;
  39. protected bool sliderJointCreated = false;
  40. protected Vector3 minimumLimitDiff;
  41. protected Vector3 maximumLimitDiff;
  42. protected Vector3 snapPosition;
  43. protected override void OnDrawGizmos()
  44. {
  45. base.OnDrawGizmos();
  46. if (!enabled || !setupSuccessful)
  47. {
  48. return;
  49. }
  50. Gizmos.DrawLine(transform.position, minimumLimit.transform.position);
  51. Gizmos.DrawLine(transform.position, maximumLimit.transform.position);
  52. }
  53. protected override void InitRequiredComponents()
  54. {
  55. DetectSetup();
  56. InitRigidbody();
  57. InitInteractableObject();
  58. InitJoint();
  59. }
  60. protected override bool DetectSetup()
  61. {
  62. if (sliderJointCreated)
  63. {
  64. if (connectedTo != null)
  65. {
  66. sliderJoint.connectedBody = connectedTo.GetComponent<Rigidbody>();
  67. }
  68. }
  69. finalDirection = direction;
  70. if (direction == Direction.autodetect)
  71. {
  72. RaycastHit hitRight;
  73. RaycastHit hitUp;
  74. RaycastHit hitForward;
  75. bool rightHasHit = Physics.Raycast(transform.position, transform.right, out hitRight);
  76. bool upHasHit = Physics.Raycast(transform.position, transform.up, out hitUp);
  77. bool forwardHasHit = Physics.Raycast(transform.position, transform.forward, out hitForward);
  78. Vector3 sliderDiff = transform.localScale / 2f;
  79. //The right ray has found the min on the right, so max is on the left
  80. if (rightHasHit && hitRight.collider.gameObject == minimumLimit.gameObject)
  81. {
  82. finalDirection = Direction.x;
  83. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.right, minimumLimit.transform.localScale.x, sliderDiff.x, false);
  84. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.right, maximumLimit.transform.localScale.x, sliderDiff.x, true);
  85. }
  86. //The right ray has found the max on the right, so min is on the left
  87. if (rightHasHit && hitRight.collider.gameObject == maximumLimit.gameObject)
  88. {
  89. finalDirection = Direction.x;
  90. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.right, minimumLimit.transform.localScale.x, sliderDiff.x, true);
  91. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.right, maximumLimit.transform.localScale.x, sliderDiff.x, false);
  92. }
  93. // the up ray has found the min above, so max is below
  94. if (upHasHit && hitUp.collider.gameObject == minimumLimit.gameObject)
  95. {
  96. finalDirection = Direction.y;
  97. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.up, minimumLimit.transform.localScale.y, sliderDiff.y, false);
  98. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.up, maximumLimit.transform.localScale.y, sliderDiff.y, true);
  99. }
  100. //the up ray has found the max above, so the min ix below
  101. if (upHasHit && hitUp.collider.gameObject == maximumLimit.gameObject)
  102. {
  103. finalDirection = Direction.y;
  104. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.up, minimumLimit.transform.localScale.y, sliderDiff.y, true);
  105. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.up, maximumLimit.transform.localScale.y, sliderDiff.y, false);
  106. }
  107. //the forward ray has found the min in front, so the max is behind
  108. if (forwardHasHit && hitForward.collider.gameObject == minimumLimit.gameObject)
  109. {
  110. finalDirection = Direction.z;
  111. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.forward, minimumLimit.transform.localScale.y, sliderDiff.y, false);
  112. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.forward, maximumLimit.transform.localScale.y, sliderDiff.y, true);
  113. }
  114. //the forward ray has found the max in front, so the min is behind
  115. if (forwardHasHit && hitForward.collider.gameObject == maximumLimit.gameObject)
  116. {
  117. finalDirection = Direction.z;
  118. minimumLimitDiff = CalculateDiff(minimumLimit.transform.localPosition, Vector3.forward, minimumLimit.transform.localScale.z, sliderDiff.z, true);
  119. maximumLimitDiff = CalculateDiff(maximumLimit.transform.localPosition, Vector3.forward, maximumLimit.transform.localScale.z, sliderDiff.z, false);
  120. }
  121. }
  122. return true;
  123. }
  124. protected override ControlValueRange RegisterValueRange()
  125. {
  126. return new ControlValueRange()
  127. {
  128. controlMin = minimumValue,
  129. controlMax = maximumValue
  130. };
  131. }
  132. protected override void HandleUpdate()
  133. {
  134. CalculateValue();
  135. if (snapToStep)
  136. {
  137. SnapToValue();
  138. }
  139. }
  140. protected virtual Vector3 CalculateDiff(Vector3 initialPosition, Vector3 givenDirection, float scaleValue, float diffMultiplier, bool addition)
  141. {
  142. Vector3 additionDiff = givenDirection * diffMultiplier;
  143. Vector3 limitDiff = givenDirection * (scaleValue / 2f);
  144. if (addition)
  145. {
  146. limitDiff = initialPosition + limitDiff;
  147. }
  148. else
  149. {
  150. limitDiff = initialPosition - limitDiff;
  151. }
  152. Vector3 answer = initialPosition - limitDiff;
  153. if (addition)
  154. {
  155. answer -= additionDiff;
  156. }
  157. else
  158. {
  159. answer += additionDiff;
  160. }
  161. return answer;
  162. }
  163. protected virtual void InitRigidbody()
  164. {
  165. sliderRigidbody = GetComponent<Rigidbody>();
  166. if (sliderRigidbody == null)
  167. {
  168. sliderRigidbody = gameObject.AddComponent<Rigidbody>();
  169. }
  170. sliderRigidbody.isKinematic = false;
  171. sliderRigidbody.useGravity = false;
  172. sliderRigidbody.constraints = RigidbodyConstraints.FreezeRotation;
  173. sliderRigidbody.drag = releasedFriction;
  174. if (connectedTo != null)
  175. {
  176. Rigidbody connectedToRigidbody = connectedTo.GetComponent<Rigidbody>();
  177. if (connectedToRigidbody == null)
  178. {
  179. connectedToRigidbody = connectedTo.AddComponent<Rigidbody>();
  180. connectedToRigidbody.useGravity = false;
  181. connectedToRigidbody.isKinematic = true;
  182. }
  183. }
  184. }
  185. protected virtual void InitInteractableObject()
  186. {
  187. VRTK_InteractableObject sliderInteractableObject = GetComponent<VRTK_InteractableObject>();
  188. if (sliderInteractableObject == null)
  189. {
  190. sliderInteractableObject = gameObject.AddComponent<VRTK_InteractableObject>();
  191. }
  192. sliderInteractableObject.isGrabbable = true;
  193. sliderInteractableObject.grabAttachMechanicScript = gameObject.AddComponent<GrabAttachMechanics.VRTK_TrackObjectGrabAttach>();
  194. sliderInteractableObject.secondaryGrabActionScript = gameObject.AddComponent<SecondaryControllerGrabActions.VRTK_SwapControllerGrabAction>();
  195. sliderInteractableObject.grabAttachMechanicScript.precisionGrab = true;
  196. sliderInteractableObject.stayGrabbedOnTeleport = false;
  197. }
  198. protected virtual void InitJoint()
  199. {
  200. sliderJoint = GetComponent<ConfigurableJoint>();
  201. if (sliderJoint == null)
  202. {
  203. sliderJoint = gameObject.AddComponent<ConfigurableJoint>();
  204. }
  205. sliderJoint.xMotion = (finalDirection == Direction.x ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
  206. sliderJoint.yMotion = (finalDirection == Direction.y ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
  207. sliderJoint.zMotion = (finalDirection == Direction.z ? ConfigurableJointMotion.Free : ConfigurableJointMotion.Locked);
  208. sliderJoint.angularXMotion = ConfigurableJointMotion.Locked;
  209. sliderJoint.angularYMotion = ConfigurableJointMotion.Locked;
  210. sliderJoint.angularZMotion = ConfigurableJointMotion.Locked;
  211. ToggleSpring(false);
  212. sliderJointCreated = true;
  213. }
  214. protected virtual void CalculateValue()
  215. {
  216. Vector3 minPoint = minimumLimit.transform.localPosition - minimumLimitDiff;
  217. Vector3 maxPoint = maximumLimit.transform.localPosition - maximumLimitDiff;
  218. float maxDistance = Vector3.Distance(minPoint, maxPoint);
  219. float currentDistance = Vector3.Distance(minPoint, transform.localPosition);
  220. float currentValue = Mathf.Round((minimumValue + Mathf.Clamp01(currentDistance / maxDistance) * (maximumValue - minimumValue)) / stepSize) * stepSize;
  221. float flatValue = currentValue - minimumValue;
  222. float controlRange = maximumValue - minimumValue;
  223. float actualPosition = (flatValue / controlRange);
  224. snapPosition = minPoint + ((maxPoint - minPoint) * actualPosition);
  225. value = currentValue;
  226. }
  227. protected virtual void ToggleSpring(bool state)
  228. {
  229. JointDrive snapDriver = new JointDrive();
  230. snapDriver.positionSpring = (state ? 10000f : 0f);
  231. snapDriver.positionDamper = (state ? 10f : 0f);
  232. snapDriver.maximumForce = (state ? 100f : 0f);
  233. sliderJoint.xDrive = snapDriver;
  234. sliderJoint.yDrive = snapDriver;
  235. sliderJoint.zDrive = snapDriver;
  236. }
  237. protected virtual void SnapToValue()
  238. {
  239. ToggleSpring(true);
  240. sliderJoint.targetPosition = snapPosition * -1f;
  241. sliderJoint.targetVelocity = Vector3.zero;
  242. }
  243. }
  244. }