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.

248 lines
11 KiB

  1. // UI Canvas|UI|80010
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. using UnityEngine.UI;
  6. using UnityEngine.EventSystems;
  7. using System.Collections;
  8. using System.Reflection;
  9. using System;
  10. /// <summary>
  11. /// Denotes a Unity World UI Canvas can be interacted with a UIPointer script.
  12. /// </summary>
  13. /// <remarks>
  14. /// **Script Usage:**
  15. /// * Place the `VRTK_UICanvas` script on the Unity World UI Canvas to allow UIPointer interactions with.
  16. ///
  17. /// **Script Dependencies:**
  18. /// * A UI Pointer attached to another GameObject (e.g. controller script alias) to interact with the UICanvas script.
  19. /// </remarks>
  20. /// <example>
  21. /// `VRTK/Examples/034_Controls_InteractingWithUnityUI` uses the `VRTK_UICanvas` script on two of the canvases to show how the UI Pointer can interact with them.
  22. /// </example>
  23. [AddComponentMenu("VRTK/Scripts/UI/VRTK_UICanvas")]
  24. public class VRTK_UICanvas : MonoBehaviour
  25. {
  26. [Tooltip("Determines if a UI Click action should happen when a UI Pointer game object collides with this canvas.")]
  27. public bool clickOnPointerCollision = false;
  28. [Tooltip("Determines if a UI Pointer will be auto activated if a UI Pointer game object comes within the given distance of this canvas. If a value of `0` is given then no auto activation will occur.")]
  29. public float autoActivateWithinDistance = 0f;
  30. protected BoxCollider canvasBoxCollider;
  31. protected Rigidbody canvasRigidBody;
  32. protected Coroutine draggablePanelCreation;
  33. protected const string CANVAS_DRAGGABLE_PANEL = "VRTK_UICANVAS_DRAGGABLE_PANEL";
  34. protected const string ACTIVATOR_FRONT_TRIGGER_GAMEOBJECT = "VRTK_UICANVAS_ACTIVATOR_FRONT_TRIGGER";
  35. protected virtual void OnEnable()
  36. {
  37. SetupCanvas();
  38. }
  39. protected virtual void OnDisable()
  40. {
  41. RemoveCanvas();
  42. }
  43. protected virtual void OnDestroy()
  44. {
  45. RemoveCanvas();
  46. }
  47. protected virtual void OnTriggerEnter(Collider collider)
  48. {
  49. VRTK_PlayerObject colliderCheck = collider.GetComponentInParent<VRTK_PlayerObject>();
  50. VRTK_UIPointer pointerCheck = collider.GetComponentInParent<VRTK_UIPointer>();
  51. if (pointerCheck != null && colliderCheck != null && colliderCheck.objectType == VRTK_PlayerObject.ObjectTypes.Collider)
  52. {
  53. pointerCheck.collisionClick = clickOnPointerCollision;
  54. }
  55. }
  56. protected virtual void OnTriggerExit(Collider collider)
  57. {
  58. VRTK_UIPointer pointerCheck = collider.GetComponentInParent<VRTK_UIPointer>();
  59. if (pointerCheck != null)
  60. {
  61. pointerCheck.collisionClick = false;
  62. }
  63. }
  64. protected virtual void SetupCanvas()
  65. {
  66. Canvas canvas = GetComponent<Canvas>();
  67. if (canvas == null || canvas.renderMode != RenderMode.WorldSpace)
  68. {
  69. VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_FROM_GAMEOBJECT, "VRTK_UICanvas", "Canvas", "the same", " that is set to `Render Mode = World Space`"));
  70. return;
  71. }
  72. RectTransform canvasRectTransform = canvas.GetComponent<RectTransform>();
  73. Vector2 canvasSize = canvasRectTransform.sizeDelta;
  74. //copy public params then disable existing graphic raycaster
  75. GraphicRaycaster defaultRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>();
  76. VRTK_UIGraphicRaycaster customRaycaster = canvas.gameObject.GetComponent<VRTK_UIGraphicRaycaster>();
  77. //if it doesn't already exist, add the custom raycaster
  78. if (customRaycaster == null)
  79. {
  80. customRaycaster = canvas.gameObject.AddComponent<VRTK_UIGraphicRaycaster>();
  81. }
  82. if (defaultRaycaster != null && defaultRaycaster.enabled)
  83. {
  84. customRaycaster.ignoreReversedGraphics = defaultRaycaster.ignoreReversedGraphics;
  85. customRaycaster.blockingObjects = defaultRaycaster.blockingObjects;
  86. //Use Reflection to transfer the BlockingMask
  87. customRaycaster.GetType().GetField("m_BlockingMask", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(customRaycaster,defaultRaycaster.GetType().GetField("m_BlockingMask", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(defaultRaycaster));
  88. defaultRaycaster.enabled = false;
  89. }
  90. //add a box collider and background image to ensure the rays always hit
  91. if (canvas.gameObject.GetComponent<BoxCollider>() == null)
  92. {
  93. Vector2 pivot = canvasRectTransform.pivot;
  94. float zSize = 0.1f;
  95. float zScale = zSize / canvasRectTransform.localScale.z;
  96. canvasBoxCollider = canvas.gameObject.AddComponent<BoxCollider>();
  97. canvasBoxCollider.size = new Vector3(canvasSize.x, canvasSize.y, zScale);
  98. canvasBoxCollider.center = new Vector3(canvasSize.x / 2 - canvasSize.x * pivot.x, canvasSize.y / 2 - canvasSize.y * pivot.y, zScale / 2f);
  99. canvasBoxCollider.isTrigger = true;
  100. }
  101. if (canvas.gameObject.GetComponent<Rigidbody>() == null)
  102. {
  103. canvasRigidBody = canvas.gameObject.AddComponent<Rigidbody>();
  104. canvasRigidBody.isKinematic = true;
  105. }
  106. draggablePanelCreation = StartCoroutine(CreateDraggablePanel(canvas, canvasSize));
  107. CreateActivator(canvas, canvasSize);
  108. }
  109. protected virtual IEnumerator CreateDraggablePanel(Canvas canvas, Vector2 canvasSize)
  110. {
  111. if (canvas != null && !canvas.transform.Find(CANVAS_DRAGGABLE_PANEL))
  112. {
  113. yield return null;
  114. GameObject draggablePanel = new GameObject(CANVAS_DRAGGABLE_PANEL, typeof(RectTransform));
  115. draggablePanel.AddComponent<LayoutElement>().ignoreLayout = true;
  116. draggablePanel.AddComponent<Image>().color = Color.clear;
  117. draggablePanel.AddComponent<EventTrigger>();
  118. draggablePanel.transform.SetParent(canvas.transform);
  119. draggablePanel.transform.localPosition = Vector3.zero;
  120. draggablePanel.transform.localRotation = Quaternion.identity;
  121. draggablePanel.transform.localScale = Vector3.one;
  122. draggablePanel.transform.SetAsFirstSibling();
  123. draggablePanel.GetComponent<RectTransform>().sizeDelta = canvasSize;
  124. }
  125. }
  126. protected virtual void CreateActivator(Canvas canvas, Vector2 canvasSize)
  127. {
  128. //if autoActivateWithinDistance is greater than 0 then create the front collider sub object
  129. if (autoActivateWithinDistance > 0f && canvas != null && !canvas.transform.Find(ACTIVATOR_FRONT_TRIGGER_GAMEOBJECT))
  130. {
  131. RectTransform canvasRectTransform = canvas.GetComponent<RectTransform>();
  132. Vector2 pivot = canvasRectTransform.pivot;
  133. GameObject frontTrigger = new GameObject(ACTIVATOR_FRONT_TRIGGER_GAMEOBJECT);
  134. frontTrigger.transform.SetParent(canvas.transform);
  135. frontTrigger.transform.SetAsFirstSibling();
  136. frontTrigger.transform.localPosition = new Vector3(canvasSize.x / 2 - canvasSize.x * pivot.x, canvasSize.y / 2 - canvasSize.y * pivot.y);
  137. frontTrigger.transform.localRotation = Quaternion.identity;
  138. frontTrigger.transform.localScale = Vector3.one;
  139. float actualActivationDistance = autoActivateWithinDistance / canvasRectTransform.localScale.z;
  140. BoxCollider frontTriggerBoxCollider = frontTrigger.AddComponent<BoxCollider>();
  141. frontTriggerBoxCollider.isTrigger = true;
  142. frontTriggerBoxCollider.size = new Vector3(canvasSize.x, canvasSize.y, actualActivationDistance);
  143. frontTriggerBoxCollider.center = new Vector3(0f, 0f, -(actualActivationDistance / 2));
  144. frontTrigger.AddComponent<Rigidbody>().isKinematic = true;
  145. frontTrigger.AddComponent<VRTK_UIPointerAutoActivator>();
  146. frontTrigger.layer = LayerMask.NameToLayer("Ignore Raycast");
  147. }
  148. }
  149. protected virtual void RemoveCanvas()
  150. {
  151. Canvas canvas = GetComponent<Canvas>();
  152. if (canvas == null)
  153. {
  154. return;
  155. }
  156. GraphicRaycaster defaultRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>();
  157. VRTK_UIGraphicRaycaster customRaycaster = canvas.gameObject.GetComponent<VRTK_UIGraphicRaycaster>();
  158. //if a custom raycaster exists then remove it
  159. if (customRaycaster != null)
  160. {
  161. Destroy(customRaycaster);
  162. }
  163. //If the default raycaster is disabled, then re-enable it
  164. if (defaultRaycaster != null && !defaultRaycaster.enabled)
  165. {
  166. defaultRaycaster.enabled = true;
  167. }
  168. //Check if there is a collider and remove it if there is
  169. if (canvasBoxCollider != null)
  170. {
  171. Destroy(canvasBoxCollider);
  172. }
  173. if (canvasRigidBody != null)
  174. {
  175. Destroy(canvasRigidBody);
  176. }
  177. if (draggablePanelCreation != null)
  178. {
  179. StopCoroutine(draggablePanelCreation);
  180. }
  181. Transform draggablePanel = canvas.transform.Find(CANVAS_DRAGGABLE_PANEL);
  182. if (draggablePanel != null)
  183. {
  184. Destroy(draggablePanel.gameObject);
  185. }
  186. Transform frontTrigger = canvas.transform.Find(ACTIVATOR_FRONT_TRIGGER_GAMEOBJECT);
  187. if (frontTrigger != null)
  188. {
  189. Destroy(frontTrigger.gameObject);
  190. }
  191. }
  192. }
  193. public class VRTK_UIPointerAutoActivator : MonoBehaviour
  194. {
  195. protected virtual void OnTriggerEnter(Collider collider)
  196. {
  197. VRTK_PlayerObject colliderCheck = collider.GetComponentInParent<VRTK_PlayerObject>();
  198. VRTK_UIPointer pointerCheck = collider.GetComponentInParent<VRTK_UIPointer>();
  199. if (pointerCheck != null && colliderCheck != null && colliderCheck.objectType == VRTK_PlayerObject.ObjectTypes.Collider)
  200. {
  201. pointerCheck.autoActivatingCanvas = gameObject;
  202. }
  203. }
  204. protected virtual void OnTriggerExit(Collider collider)
  205. {
  206. VRTK_UIPointer pointerCheck = collider.GetComponentInParent<VRTK_UIPointer>();
  207. if (pointerCheck != null && pointerCheck.autoActivatingCanvas == gameObject)
  208. {
  209. pointerCheck.autoActivatingCanvas = null;
  210. }
  211. }
  212. }
  213. }