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.

379 lines
17 KiB

  1. // Interact Haptics|Interactables|35020
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Event Payload
  7. /// </summary>
  8. /// <param name="controllerReference">The reference to the controller to perform haptics on.</param>
  9. public struct InteractHapticsEventArgs
  10. {
  11. public VRTK_ControllerReference controllerReference;
  12. }
  13. /// <summary>
  14. /// Event Payload
  15. /// </summary>
  16. /// <param name="sender">this object</param>
  17. /// <param name="e"><see cref="InteractHapticsEventArgs"/></param>
  18. public delegate void InteractHapticsEventHandler(object sender, InteractHapticsEventArgs e);
  19. /// <summary>
  20. /// Provides controller haptics upon interaction with the specified Interactable Object.
  21. /// </summary>
  22. /// <remarks>
  23. /// **Required Components:**
  24. /// * `VRTK_InteractableObject` - The Interactable Object component to detect interactions on. This must be applied on the same GameObject as this script if one is not provided via the `Object To Affect` parameter.
  25. ///
  26. /// **Script Usage:**
  27. /// * Place the `VRTK_InteractHaptics` script on either:
  28. /// * The GameObject of the Interactable Object to detect interactions on.
  29. /// * Any other scene GameObject and provide a valid `VRTK_InteractableObject` component to the `Object To Affect` parameter of this script.
  30. /// </remarks>
  31. [AddComponentMenu("VRTK/Scripts/Interactions/Interactables/VRTK_InteractHaptics")]
  32. public class VRTK_InteractHaptics : VRTK_InteractableListener
  33. {
  34. [Header("Haptics On Near Touch Settings")]
  35. [Tooltip("Denotes the audio clip to use to rumble the controller on near touch.")]
  36. public AudioClip clipOnNearTouch;
  37. [Tooltip("Denotes how strong the rumble in the controller will be on near touch.")]
  38. [Range(0, 1)]
  39. public float strengthOnNearTouch = 0;
  40. [Tooltip("Denotes how long the rumble in the controller will last on near touch.")]
  41. public float durationOnNearTouch = 0f;
  42. [Tooltip("Denotes interval betweens rumble in the controller on near touch.")]
  43. public float intervalOnNearTouch = minInterval;
  44. [Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer near touching.")]
  45. public bool cancelOnNearUntouch = true;
  46. [Header("Haptics On Touch Settings")]
  47. [Tooltip("Denotes the audio clip to use to rumble the controller on touch.")]
  48. public AudioClip clipOnTouch;
  49. [Tooltip("Denotes how strong the rumble in the controller will be on touch.")]
  50. [Range(0, 1)]
  51. public float strengthOnTouch = 0;
  52. [Tooltip("Denotes how long the rumble in the controller will last on touch.")]
  53. public float durationOnTouch = 0f;
  54. [Tooltip("Denotes interval betweens rumble in the controller on touch.")]
  55. public float intervalOnTouch = minInterval;
  56. [Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer touching.")]
  57. public bool cancelOnUntouch = true;
  58. [Header("Haptics On Grab Settings")]
  59. [Tooltip("Denotes the audio clip to use to rumble the controller on grab.")]
  60. public AudioClip clipOnGrab;
  61. [Tooltip("Denotes how strong the rumble in the controller will be on grab.")]
  62. [Range(0, 1)]
  63. public float strengthOnGrab = 0;
  64. [Tooltip("Denotes how long the rumble in the controller will last on grab.")]
  65. public float durationOnGrab = 0f;
  66. [Tooltip("Denotes interval betweens rumble in the controller on grab.")]
  67. public float intervalOnGrab = minInterval;
  68. [Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer grabbing.")]
  69. public bool cancelOnUngrab = true;
  70. [Header("Haptics On Use Settings")]
  71. [Tooltip("Denotes the audio clip to use to rumble the controller on use.")]
  72. public AudioClip clipOnUse;
  73. [Tooltip("Denotes how strong the rumble in the controller will be on use.")]
  74. [Range(0, 1)]
  75. public float strengthOnUse = 0;
  76. [Tooltip("Denotes how long the rumble in the controller will last on use.")]
  77. public float durationOnUse = 0f;
  78. [Tooltip("Denotes interval betweens rumble in the controller on use.")]
  79. public float intervalOnUse = minInterval;
  80. [Tooltip("If this is checked then the rumble will be cancelled when the controller is no longer using.")]
  81. public bool cancelOnUnuse = true;
  82. [Header("Custom Settings")]
  83. [Tooltip("The Interactable Object to initiate the haptics from. If this is left blank, then the Interactable Object will need to be on the current or a parent GameObject.")]
  84. public VRTK_InteractableObject objectToAffect;
  85. /// <summary>
  86. /// Emitted when the haptics are from a near touch.
  87. /// </summary>
  88. public event InteractHapticsEventHandler InteractHapticsNearTouched;
  89. /// <summary>
  90. /// Emitted when the haptics are from a touch.
  91. /// </summary>
  92. public event InteractHapticsEventHandler InteractHapticsTouched;
  93. /// <summary>
  94. /// Emitted when the haptics are from a grab.
  95. /// </summary>
  96. public event InteractHapticsEventHandler InteractHapticsGrabbed;
  97. /// <summary>
  98. /// Emitted when the haptics are from a use.
  99. /// </summary>
  100. public event InteractHapticsEventHandler InteractHapticsUsed;
  101. protected const float minInterval = 0.05f;
  102. public virtual void OnInteractHapticsNearTouched(InteractHapticsEventArgs e)
  103. {
  104. if (InteractHapticsNearTouched != null)
  105. {
  106. InteractHapticsNearTouched(this, e);
  107. }
  108. }
  109. public virtual void OnInteractHapticsTouched(InteractHapticsEventArgs e)
  110. {
  111. if (InteractHapticsTouched != null)
  112. {
  113. InteractHapticsTouched(this, e);
  114. }
  115. }
  116. public virtual void OnInteractHapticsGrabbed(InteractHapticsEventArgs e)
  117. {
  118. if (InteractHapticsGrabbed != null)
  119. {
  120. InteractHapticsGrabbed(this, e);
  121. }
  122. }
  123. public virtual void OnInteractHapticsUsed(InteractHapticsEventArgs e)
  124. {
  125. if (InteractHapticsUsed != null)
  126. {
  127. InteractHapticsUsed(this, e);
  128. }
  129. }
  130. /// <summary>
  131. /// The CancelHaptics method cancels any existing haptic feedback on the given controller.
  132. /// </summary>
  133. /// <param name="controllerReference"></param>
  134. public virtual void CancelHaptics(VRTK_ControllerReference controllerReference)
  135. {
  136. VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
  137. }
  138. /// <summary>
  139. /// The HapticsOnNearTouch method triggers the haptic feedback on the given controller for the settings associated with near touch.
  140. /// </summary>
  141. /// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
  142. public virtual void HapticsOnNearTouch(VRTK_ControllerReference controllerReference)
  143. {
  144. if (clipOnNearTouch != null)
  145. {
  146. VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnNearTouch);
  147. }
  148. else if (strengthOnNearTouch > 0 && durationOnNearTouch > 0f)
  149. {
  150. TriggerHapticPulse(controllerReference, strengthOnNearTouch, durationOnNearTouch, intervalOnNearTouch);
  151. }
  152. else
  153. {
  154. VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
  155. }
  156. OnInteractHapticsNearTouched(SetEventPayload(controllerReference));
  157. }
  158. /// <summary>
  159. /// The HapticsOnTouch method triggers the haptic feedback on the given controller for the settings associated with touch.
  160. /// </summary>
  161. /// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
  162. public virtual void HapticsOnTouch(VRTK_ControllerReference controllerReference)
  163. {
  164. if (clipOnTouch != null)
  165. {
  166. VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnTouch);
  167. }
  168. else if (strengthOnTouch > 0 && durationOnTouch > 0f)
  169. {
  170. TriggerHapticPulse(controllerReference, strengthOnTouch, durationOnTouch, intervalOnTouch);
  171. }
  172. else
  173. {
  174. VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
  175. }
  176. OnInteractHapticsTouched(SetEventPayload(controllerReference));
  177. }
  178. /// <summary>
  179. /// The HapticsOnGrab method triggers the haptic feedback on the given controller for the settings associated with grab.
  180. /// </summary>
  181. /// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
  182. public virtual void HapticsOnGrab(VRTK_ControllerReference controllerReference)
  183. {
  184. if (clipOnGrab != null)
  185. {
  186. VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnGrab);
  187. }
  188. else if (strengthOnGrab > 0 && durationOnGrab > 0f)
  189. {
  190. TriggerHapticPulse(controllerReference, strengthOnGrab, durationOnGrab, intervalOnGrab);
  191. }
  192. else
  193. {
  194. VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
  195. }
  196. OnInteractHapticsGrabbed(SetEventPayload(controllerReference));
  197. }
  198. /// <summary>
  199. /// The HapticsOnUse method triggers the haptic feedback on the given controller for the settings associated with use.
  200. /// </summary>
  201. /// <param name="controllerReference">The reference to the controller to activate the haptic feedback on.</param>
  202. public virtual void HapticsOnUse(VRTK_ControllerReference controllerReference)
  203. {
  204. if (clipOnUse != null)
  205. {
  206. VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, clipOnUse);
  207. }
  208. else if (strengthOnUse > 0 && durationOnUse > 0f)
  209. {
  210. TriggerHapticPulse(controllerReference, strengthOnUse, durationOnUse, intervalOnUse);
  211. }
  212. else
  213. {
  214. VRTK_ControllerHaptics.CancelHapticPulse(controllerReference);
  215. }
  216. OnInteractHapticsUsed(SetEventPayload(controllerReference));
  217. }
  218. protected virtual void OnEnable()
  219. {
  220. EnableListeners();
  221. }
  222. protected virtual void OnDisable()
  223. {
  224. DisableListeners();
  225. }
  226. protected override bool SetupListeners(bool throwError)
  227. {
  228. objectToAffect = (objectToAffect != null ? objectToAffect : GetComponentInParent<VRTK_InteractableObject>());
  229. if (objectToAffect != null)
  230. {
  231. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.NearUntouch, CancelNearTouchHaptics);
  232. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Untouch, CancelTouchHaptics);
  233. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Ungrab, CancelGrabHaptics);
  234. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Unuse, CancelUseHaptics);
  235. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
  236. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
  237. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
  238. objectToAffect.SubscribeToInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
  239. return true;
  240. }
  241. else if (throwError)
  242. {
  243. VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_InteractHaptics", "VRTK_InteractableObject", "the same or parent"));
  244. }
  245. return false;
  246. }
  247. protected override void TearDownListeners()
  248. {
  249. if (objectToAffect != null)
  250. {
  251. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.NearUntouch, CancelNearTouchHaptics);
  252. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Untouch, CancelTouchHaptics);
  253. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Ungrab, CancelGrabHaptics);
  254. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Unuse, CancelUseHaptics);
  255. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.NearTouch, NearTouchHaptics);
  256. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Touch, TouchHaptics);
  257. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Grab, GrabHaptics);
  258. objectToAffect.UnsubscribeFromInteractionEvent(VRTK_InteractableObject.InteractionType.Use, UseHaptics);
  259. }
  260. }
  261. protected virtual void TriggerHapticPulse(VRTK_ControllerReference controllerReference, float strength, float duration, float interval)
  262. {
  263. VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, strength, duration, (interval >= minInterval ? interval : minInterval));
  264. }
  265. protected virtual InteractHapticsEventArgs SetEventPayload(VRTK_ControllerReference givenControllerReference)
  266. {
  267. InteractHapticsEventArgs e;
  268. e.controllerReference = givenControllerReference;
  269. return e;
  270. }
  271. protected virtual void NearTouchHaptics(object sender, InteractableObjectEventArgs e)
  272. {
  273. VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
  274. if (VRTK_ControllerReference.IsValid(controllerReference))
  275. {
  276. HapticsOnNearTouch(controllerReference);
  277. }
  278. }
  279. protected virtual void TouchHaptics(object sender, InteractableObjectEventArgs e)
  280. {
  281. VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
  282. if (VRTK_ControllerReference.IsValid(controllerReference))
  283. {
  284. HapticsOnTouch(controllerReference);
  285. }
  286. }
  287. protected virtual void GrabHaptics(object sender, InteractableObjectEventArgs e)
  288. {
  289. VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
  290. if (VRTK_ControllerReference.IsValid(controllerReference))
  291. {
  292. HapticsOnGrab(controllerReference);
  293. }
  294. }
  295. protected virtual void UseHaptics(object sender, InteractableObjectEventArgs e)
  296. {
  297. VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(e.interactingObject);
  298. if (VRTK_ControllerReference.IsValid(controllerReference))
  299. {
  300. HapticsOnUse(controllerReference);
  301. }
  302. }
  303. protected virtual void CancelOn(GameObject givenObject)
  304. {
  305. VRTK_ControllerReference controllerReference = VRTK_ControllerReference.GetControllerReference(givenObject);
  306. if (VRTK_ControllerReference.IsValid(controllerReference))
  307. {
  308. CancelHaptics(controllerReference);
  309. }
  310. }
  311. protected virtual void CancelNearTouchHaptics(object sender, InteractableObjectEventArgs e)
  312. {
  313. if (cancelOnNearUntouch)
  314. {
  315. CancelOn(e.interactingObject);
  316. }
  317. }
  318. protected virtual void CancelTouchHaptics(object sender, InteractableObjectEventArgs e)
  319. {
  320. if (cancelOnUntouch)
  321. {
  322. CancelOn(e.interactingObject);
  323. }
  324. }
  325. protected virtual void CancelGrabHaptics(object sender, InteractableObjectEventArgs e)
  326. {
  327. if (cancelOnUngrab)
  328. {
  329. CancelOn(e.interactingObject);
  330. }
  331. }
  332. protected virtual void CancelUseHaptics(object sender, InteractableObjectEventArgs e)
  333. {
  334. if (cancelOnUnuse)
  335. {
  336. CancelOn(e.interactingObject);
  337. }
  338. }
  339. }
  340. }