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.

280 lines
10 KiB

  1. // Headset Collision|Presence|70010
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Event Payload
  7. /// </summary>
  8. /// <param name="collider">The Collider of the game object the headset has collided with.</param>
  9. /// <param name="currentTransform">The current Transform of the object that the Headset Collision Fade script is attached to (Camera).</param>
  10. public struct HeadsetCollisionEventArgs
  11. {
  12. public Collider collider;
  13. public Transform currentTransform;
  14. }
  15. /// <summary>
  16. /// Event Payload
  17. /// </summary>
  18. /// <param name="sender">this object</param>
  19. /// <param name="e"><see cref="HeadsetCollisionEventArgs"/></param>
  20. public delegate void HeadsetCollisionEventHandler(object sender, HeadsetCollisionEventArgs e);
  21. /// <summary>
  22. /// Denotes when the HMD is colliding with valid geometry.
  23. /// </summary>
  24. /// <remarks>
  25. /// **Script Usage:**
  26. /// * Place the `VRTK_HeadsetCollision` script on any active scene GameObject.
  27. /// </remarks>
  28. /// <example>
  29. /// `VRTK/Examples/011_Camera_HeadSetCollisionFading` has collidable walls around the play area and if the user puts their head into any of the walls then the headset will fade to black.
  30. /// </example>
  31. [AddComponentMenu("VRTK/Scripts/Presence/VRTK_HeadsetCollision")]
  32. public class VRTK_HeadsetCollision : MonoBehaviour
  33. {
  34. [Tooltip("If this is checked then the headset collision will ignore colliders set to `Is Trigger = true`.")]
  35. public bool ignoreTriggerColliders = false;
  36. [Tooltip("The radius of the auto generated sphere collider for detecting collisions on the headset.")]
  37. public float colliderRadius = 0.1f;
  38. [Tooltip("A specified VRTK_PolicyList to use to determine whether any objects will be acted upon by the Headset Collision.")]
  39. public VRTK_PolicyList targetListPolicy;
  40. /// <summary>
  41. /// Emitted when the user's headset collides with another game object.
  42. /// </summary>
  43. public event HeadsetCollisionEventHandler HeadsetCollisionDetect;
  44. /// <summary>
  45. /// Emitted when the user's headset stops colliding with a game object.
  46. /// </summary>
  47. public event HeadsetCollisionEventHandler HeadsetCollisionEnded;
  48. /// <summary>
  49. /// Determines if the headset is currently colliding with another object.
  50. /// </summary>
  51. [HideInInspector]
  52. public bool headsetColliding = false;
  53. /// <summary>
  54. /// Stores the collider of what the headset is colliding with.
  55. /// </summary>
  56. [HideInInspector]
  57. public Collider collidingWith = null;
  58. protected Transform headset;
  59. protected VRTK_HeadsetCollider headsetColliderScript;
  60. protected GameObject headsetColliderContainer;
  61. protected bool generateCollider = false;
  62. protected bool generateRigidbody = false;
  63. public virtual void OnHeadsetCollisionDetect(HeadsetCollisionEventArgs e)
  64. {
  65. if (HeadsetCollisionDetect != null)
  66. {
  67. HeadsetCollisionDetect(this, e);
  68. }
  69. }
  70. public virtual void OnHeadsetCollisionEnded(HeadsetCollisionEventArgs e)
  71. {
  72. if (HeadsetCollisionEnded != null)
  73. {
  74. HeadsetCollisionEnded(this, e);
  75. }
  76. }
  77. /// <summary>
  78. /// The IsColliding method is used to determine if the headset is currently colliding with a valid game object and returns true if it is and false if it is not colliding with anything or an invalid game object.
  79. /// </summary>
  80. /// <returns>Returns `true` if the headset is currently colliding with a valid game object.</returns>
  81. public virtual bool IsColliding()
  82. {
  83. return headsetColliding;
  84. }
  85. /// <summary>
  86. /// The GetHeadsetColliderContainer method returns the auto generated GameObject that contains the headset collider.
  87. /// </summary>
  88. /// <returns>The auto generated headset collider GameObject.</returns>
  89. public virtual GameObject GetHeadsetColliderContainer()
  90. {
  91. return headsetColliderContainer;
  92. }
  93. protected virtual void Awake()
  94. {
  95. VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
  96. }
  97. protected virtual void OnEnable()
  98. {
  99. headset = VRTK_DeviceFinder.HeadsetTransform();
  100. if (headset != null)
  101. {
  102. headsetColliding = false;
  103. SetupHeadset();
  104. VRTK_PlayerObject.SetPlayerObject(headsetColliderContainer.gameObject, VRTK_PlayerObject.ObjectTypes.Headset);
  105. }
  106. }
  107. protected virtual void OnDisable()
  108. {
  109. if (headset != null && headsetColliderScript != null)
  110. {
  111. headsetColliderScript.EndCollision(collidingWith);
  112. TearDownHeadset();
  113. }
  114. }
  115. protected virtual void OnDestroy()
  116. {
  117. VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
  118. }
  119. protected virtual void Update()
  120. {
  121. if (headsetColliderContainer != null && headsetColliderContainer.transform.parent != headset)
  122. {
  123. headsetColliderContainer.transform.SetParent(headset);
  124. headsetColliderContainer.transform.localPosition = Vector3.zero;
  125. headsetColliderContainer.transform.localRotation = headset.localRotation;
  126. }
  127. }
  128. protected virtual void CreateHeadsetColliderContainer()
  129. {
  130. if (headsetColliderContainer == null)
  131. {
  132. headsetColliderContainer = new GameObject(VRTK_SharedMethods.GenerateVRTKObjectName(true, "HeadsetColliderContainer"));
  133. headsetColliderContainer.transform.position = Vector3.zero;
  134. headsetColliderContainer.transform.localRotation = headset.localRotation;
  135. headsetColliderContainer.transform.localScale = Vector3.one;
  136. headsetColliderContainer.layer = LayerMask.NameToLayer("Ignore Raycast");
  137. }
  138. }
  139. protected virtual void SetupHeadset()
  140. {
  141. Rigidbody headsetRigidbody = headset.GetComponentInChildren<Rigidbody>();
  142. if (headsetRigidbody == null)
  143. {
  144. CreateHeadsetColliderContainer();
  145. headsetRigidbody = headsetColliderContainer.AddComponent<Rigidbody>();
  146. headsetRigidbody.constraints = RigidbodyConstraints.FreezeAll;
  147. generateRigidbody = true;
  148. }
  149. headsetRigidbody.isKinematic = true;
  150. headsetRigidbody.useGravity = false;
  151. Collider headsetCollider = headset.GetComponentInChildren<Collider>();
  152. if (headsetCollider == null)
  153. {
  154. CreateHeadsetColliderContainer();
  155. SphereCollider newCollider = headsetColliderContainer.gameObject.AddComponent<SphereCollider>();
  156. newCollider.radius = colliderRadius;
  157. headsetCollider = newCollider;
  158. generateCollider = true;
  159. }
  160. headsetCollider.isTrigger = true;
  161. if (headsetColliderScript == null)
  162. {
  163. GameObject attachTo = (headsetColliderContainer ? headsetColliderContainer : headset.gameObject);
  164. headsetColliderScript = attachTo.AddComponent<VRTK_HeadsetCollider>();
  165. headsetColliderScript.SetParent(gameObject);
  166. headsetColliderScript.SetIgnoreTarget(targetListPolicy);
  167. }
  168. }
  169. protected virtual void TearDownHeadset()
  170. {
  171. if (generateCollider)
  172. {
  173. Destroy(headset.gameObject.GetComponent<BoxCollider>());
  174. }
  175. if (generateRigidbody)
  176. {
  177. Destroy(headset.gameObject.GetComponent<Rigidbody>());
  178. }
  179. if (headsetColliderScript != null)
  180. {
  181. Destroy(headsetColliderScript);
  182. }
  183. if (headsetColliderContainer != null)
  184. {
  185. Destroy(headsetColliderContainer);
  186. }
  187. }
  188. }
  189. public class VRTK_HeadsetCollider : MonoBehaviour
  190. {
  191. protected VRTK_HeadsetCollision parent;
  192. protected VRTK_PolicyList targetListPolicy;
  193. public virtual void SetParent(GameObject setParent)
  194. {
  195. parent = setParent.GetComponent<VRTK_HeadsetCollision>();
  196. }
  197. public virtual void SetIgnoreTarget(VRTK_PolicyList list = null)
  198. {
  199. targetListPolicy = list;
  200. }
  201. public virtual void EndCollision(Collider collider)
  202. {
  203. if (collider == null || !VRTK_PlayerObject.IsPlayerObject(collider.gameObject))
  204. {
  205. parent.headsetColliding = false;
  206. parent.collidingWith = null;
  207. parent.OnHeadsetCollisionEnded(SetHeadsetCollisionEvent(collider, transform));
  208. }
  209. }
  210. protected virtual void OnTriggerStay(Collider collider)
  211. {
  212. if (parent.ignoreTriggerColliders && collider != null && collider.isTrigger)
  213. {
  214. return;
  215. }
  216. if (enabled && !VRTK_PlayerObject.IsPlayerObject(collider.gameObject) && ValidTarget(collider.transform))
  217. {
  218. parent.headsetColliding = true;
  219. parent.collidingWith = collider;
  220. parent.OnHeadsetCollisionDetect(SetHeadsetCollisionEvent(collider, transform));
  221. }
  222. }
  223. protected virtual void OnTriggerExit(Collider collider)
  224. {
  225. if (parent.ignoreTriggerColliders && collider != null && collider.isTrigger)
  226. {
  227. return;
  228. }
  229. EndCollision(collider);
  230. }
  231. protected virtual void Update()
  232. {
  233. if (parent.headsetColliding && (parent.collidingWith == null || !parent.collidingWith.gameObject.activeInHierarchy))
  234. {
  235. EndCollision(parent.collidingWith);
  236. }
  237. }
  238. protected virtual HeadsetCollisionEventArgs SetHeadsetCollisionEvent(Collider collider, Transform currentTransform)
  239. {
  240. HeadsetCollisionEventArgs e;
  241. e.collider = collider;
  242. e.currentTransform = currentTransform;
  243. return e;
  244. }
  245. protected virtual bool ValidTarget(Transform target)
  246. {
  247. return (target != null && !(VRTK_PolicyList.Check(target.gameObject, targetListPolicy)));
  248. }
  249. }
  250. }