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.

257 lines
8.7 KiB

  1. // Control|Controls3D|100010
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Event Payload
  7. /// </summary>
  8. /// <param name="value">The current value being reported by the control.</param>
  9. /// <param name="normalizedValue">The normalized value being reported by the control.</param>
  10. public struct Control3DEventArgs
  11. {
  12. public float value;
  13. public float normalizedValue;
  14. }
  15. /// <summary>
  16. /// Event Payload
  17. /// </summary>
  18. /// <param name="sender">this object</param>
  19. /// <param name="e"><see cref="Control3DEventArgs"/></param>
  20. public delegate void Control3DEventHandler(object sender, Control3DEventArgs e);
  21. /// <summary>
  22. /// All 3D controls extend the `VRTK_Control` abstract class which provides a default set of methods and events that all of the subsequent controls expose.
  23. /// </summary>
  24. [ExecuteInEditMode]
  25. [System.Obsolete("`VRTK_Control` has been deprecated. This script will be removed in a future version of VRTK.")]
  26. public abstract class VRTK_Control : MonoBehaviour
  27. {
  28. /// <summary>
  29. /// The ControlValueRange struct provides a way for each inherited control to support value normalization.
  30. /// </summary>
  31. public struct ControlValueRange
  32. {
  33. public float controlMin;
  34. public float controlMax;
  35. }
  36. /// <summary>
  37. /// 3D Control Directions
  38. /// </summary>
  39. public enum Direction
  40. {
  41. /// <summary>
  42. /// Attempt to auto detect the axis.
  43. /// </summary>
  44. autodetect,
  45. /// <summary>
  46. /// The world x direction.
  47. /// </summary>
  48. x,
  49. /// <summary>
  50. /// The world y direction.
  51. /// </summary>
  52. y,
  53. /// <summary>
  54. /// The world z direction.
  55. /// </summary>
  56. z
  57. }
  58. [Tooltip("If active the control will react to the controller without the need to push the grab button.")]
  59. public bool interactWithoutGrab = false;
  60. /// <summary>
  61. /// Emitted when the 3D Control value has changed.
  62. /// </summary>
  63. public event Control3DEventHandler ValueChanged;
  64. abstract protected void InitRequiredComponents();
  65. abstract protected bool DetectSetup();
  66. abstract protected ControlValueRange RegisterValueRange();
  67. protected Bounds bounds;
  68. protected bool setupSuccessful = true;
  69. protected VRTK_ControllerRigidbodyActivator autoTriggerVolume;
  70. protected float value;
  71. protected static Color COLOR_OK = Color.yellow;
  72. protected static Color COLOR_ERROR = new Color(1, 0, 0, 0.9f);
  73. protected const float MIN_OPENING_DISTANCE = 20f; // percentage how far open something needs to be in order to activate it
  74. protected ControlValueRange valueRange;
  75. protected GameObject controlContent;
  76. protected bool hideControlContent = false;
  77. public virtual void OnValueChanged(Control3DEventArgs e)
  78. {
  79. if (ValueChanged != null)
  80. {
  81. ValueChanged(this, e);
  82. }
  83. }
  84. /// <summary>
  85. /// The GetValue method returns the current value/position/setting of the control depending on the control that is extending this abstract class.
  86. /// </summary>
  87. /// <returns>The current value of the control.</returns>
  88. public virtual float GetValue()
  89. {
  90. return value;
  91. }
  92. /// <summary>
  93. /// The GetNormalizedValue method returns the current value mapped onto a range between 0 and 100.
  94. /// </summary>
  95. /// <returns>The current normalized value of the control.</returns>
  96. public virtual float GetNormalizedValue()
  97. {
  98. return Mathf.Abs(Mathf.Round((value - valueRange.controlMin) / (valueRange.controlMax - valueRange.controlMin) * 100));
  99. }
  100. /// <summary>
  101. /// The SetContent method sets the given game object as the content of the control. This will then disable and optionally hide the content when a control is obscuring its view to prevent interacting with content within a control.
  102. /// </summary>
  103. /// <param name="content">The content to be considered within the control.</param>
  104. /// <param name="hideContent">When true the content will be hidden in addition to being non-interactable in case the control is fully closed.</param>
  105. public virtual void SetContent(GameObject content, bool hideContent)
  106. {
  107. controlContent = content;
  108. hideControlContent = hideContent;
  109. }
  110. /// <summary>
  111. /// The GetContent method returns the current game object of the control's content.
  112. /// </summary>
  113. /// <returns>The currently stored content for the control.</returns>
  114. public virtual GameObject GetContent()
  115. {
  116. return controlContent;
  117. }
  118. abstract protected void HandleUpdate();
  119. protected virtual void Awake()
  120. {
  121. if (Application.isPlaying)
  122. {
  123. InitRequiredComponents();
  124. if (interactWithoutGrab)
  125. {
  126. CreateTriggerVolume();
  127. }
  128. }
  129. setupSuccessful = DetectSetup();
  130. if (Application.isPlaying)
  131. {
  132. valueRange = RegisterValueRange();
  133. HandleInteractables();
  134. }
  135. }
  136. protected virtual void Update()
  137. {
  138. if (!Application.isPlaying)
  139. {
  140. setupSuccessful = DetectSetup();
  141. }
  142. else if (setupSuccessful)
  143. {
  144. float oldValue = value;
  145. HandleUpdate();
  146. // trigger events
  147. if (value != oldValue)
  148. {
  149. HandleInteractables();
  150. OnValueChanged(SetControlEvent());
  151. }
  152. }
  153. }
  154. protected virtual Control3DEventArgs SetControlEvent()
  155. {
  156. Control3DEventArgs e;
  157. e.value = GetValue();
  158. e.normalizedValue = GetNormalizedValue();
  159. return e;
  160. }
  161. protected virtual void OnDrawGizmos()
  162. {
  163. if (!enabled)
  164. {
  165. return;
  166. }
  167. bounds = VRTK_SharedMethods.GetBounds(transform);
  168. Gizmos.color = (setupSuccessful) ? COLOR_OK : COLOR_ERROR;
  169. if (setupSuccessful)
  170. {
  171. Gizmos.DrawWireCube(bounds.center, bounds.size);
  172. }
  173. else
  174. {
  175. Gizmos.DrawCube(bounds.center, bounds.size * 1.01f); // draw slightly bigger to eliminate flickering
  176. }
  177. }
  178. protected virtual void CreateTriggerVolume()
  179. {
  180. GameObject autoTriggerVolumeGO = new GameObject(name + "-Trigger");
  181. autoTriggerVolumeGO.transform.SetParent(transform);
  182. autoTriggerVolume = autoTriggerVolumeGO.AddComponent<VRTK_ControllerRigidbodyActivator>();
  183. // calculate bounding box
  184. Bounds triggerBounds = VRTK_SharedMethods.GetBounds(transform);
  185. triggerBounds.Expand(triggerBounds.size * 0.2f);
  186. autoTriggerVolumeGO.transform.position = triggerBounds.center;
  187. BoxCollider triggerCollider = autoTriggerVolumeGO.AddComponent<BoxCollider>();
  188. triggerCollider.isTrigger = true;
  189. triggerCollider.size = triggerBounds.size;
  190. }
  191. protected Vector3 GetThirdDirection(Vector3 axis1, Vector3 axis2)
  192. {
  193. bool xTaken = axis1.x != 0 || axis2.x != 0;
  194. bool yTaken = axis1.y != 0 || axis2.y != 0;
  195. bool zTaken = axis1.z != 0 || axis2.z != 0;
  196. if (xTaken && yTaken)
  197. {
  198. return Vector3.forward;
  199. }
  200. else if (xTaken && zTaken)
  201. {
  202. return Vector3.up;
  203. }
  204. else
  205. {
  206. return Vector3.right;
  207. }
  208. }
  209. protected virtual void HandleInteractables()
  210. {
  211. if (controlContent == null)
  212. {
  213. return;
  214. }
  215. if (hideControlContent)
  216. {
  217. controlContent.SetActive(value > 0);
  218. }
  219. // do not cache objects since otherwise they would still be made inactive once taken out of the content
  220. VRTK_InteractableObject[] foundInteractableObjects = controlContent.GetComponentsInChildren<VRTK_InteractableObject>(true);
  221. for (int i = 0; i < foundInteractableObjects.Length; i++)
  222. {
  223. foundInteractableObjects[i].enabled = value > MIN_OPENING_DISTANCE;
  224. }
  225. }
  226. }
  227. }