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.

169 lines
7.4 KiB

  1. // Pointer Direction Indicator|Prefabs|0100
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Event Payload
  7. /// </summary>
  8. /// <param name="sender">this object</param>
  9. public delegate void PointerDirectionIndicatorEventHandler(object sender);
  10. /// <summary>
  11. /// Adds a Pointer Direction Indicator to a pointer renderer and determines a given world rotation that can be used by a Destiantion Marker.
  12. /// </summary>
  13. /// <remarks>
  14. /// **Prefab Usage:**
  15. /// * Place the `VRTK/Prefabs/PointerDirectionIndicator/PointerDirectionIndicator` prefab into the scene hierarchy.
  16. /// * Attach the `PointerDirectionIndicator` scene GameObejct to the `Direction Indicator` inspector parameter on a `VRTK_BasePointerRenderer` component.
  17. ///
  18. /// > This can be useful for rotating the play area upon teleporting to face the user in a new direction without expecting them to physically turn in the play space.
  19. /// </remarks>
  20. public class VRTK_PointerDirectionIndicator : MonoBehaviour
  21. {
  22. /// <summary>
  23. /// States of Direction Indicator Visibility.
  24. /// </summary>
  25. public enum VisibilityState
  26. {
  27. /// <summary>
  28. /// Only shows the direction indicator when the pointer is active.
  29. /// </summary>
  30. OnWhenPointerActive,
  31. /// <summary>
  32. /// Only shows the direction indicator when the pointer cursor is visible or if the cursor is hidden and the pointer is active.
  33. /// </summary>
  34. AlwaysOnWithPointerCursor
  35. }
  36. [Header("Control Settings")]
  37. [Tooltip("The touchpad axis needs to be above this deadzone for it to register as a valid touchpad angle.")]
  38. public Vector2 touchpadDeadzone = Vector2.zero;
  39. [Tooltip("The axis to use for the direction coordinates.")]
  40. public VRTK_ControllerEvents.Vector2AxisAlias coordinateAxis = VRTK_ControllerEvents.Vector2AxisAlias.Touchpad;
  41. [Header("Appearance Settings")]
  42. [Tooltip("If this is checked then the reported rotation will include the offset of the headset rotation in relation to the play area.")]
  43. public bool includeHeadsetOffset = true;
  44. [Tooltip("If this is checked then the direction indicator will be displayed when the location is invalid.")]
  45. public bool displayOnInvalidLocation = true;
  46. [Tooltip("If this is checked then the pointer valid/invalid colours will also be used to change the colour of the direction indicator.")]
  47. public bool usePointerColor = false;
  48. [Tooltip("Determines when the direction indicator will be visible.")]
  49. public VisibilityState indicatorVisibility = VisibilityState.OnWhenPointerActive;
  50. [HideInInspector]
  51. public bool isActive = true;
  52. /// <summary>
  53. /// Emitted when the object tooltip is reset.
  54. /// </summary>
  55. public event PointerDirectionIndicatorEventHandler PointerDirectionIndicatorPositionSet;
  56. protected VRTK_ControllerEvents controllerEvents;
  57. protected Transform playArea;
  58. protected Transform headset;
  59. protected GameObject validLocation;
  60. protected GameObject invalidLocation;
  61. public virtual void OnPointerDirectionIndicatorPositionSet()
  62. {
  63. if (PointerDirectionIndicatorPositionSet != null)
  64. {
  65. PointerDirectionIndicatorPositionSet(this);
  66. }
  67. }
  68. /// <summary>
  69. /// The Initialize method is used to set up the direction indicator.
  70. /// </summary>
  71. /// <param name="events">The Controller Events script that is used to control the direction indicator's rotation.</param>
  72. public virtual void Initialize(VRTK_ControllerEvents events)
  73. {
  74. controllerEvents = events;
  75. playArea = VRTK_DeviceFinder.PlayAreaTransform();
  76. headset = VRTK_DeviceFinder.HeadsetTransform();
  77. }
  78. /// <summary>
  79. /// The SetPosition method is used to set the world position of the direction indicator.
  80. /// </summary>
  81. /// <param name="active">Determines if the direction indicator GameObject should be active or not.</param>
  82. /// <param name="position">The position to set the direction indicator to.</param>
  83. public virtual void SetPosition(bool active, Vector3 position)
  84. {
  85. transform.position = position;
  86. gameObject.SetActive((isActive && active));
  87. OnPointerDirectionIndicatorPositionSet();
  88. }
  89. /// <summary>
  90. /// The GetRotation method returns the current reported rotation of the direction indicator.
  91. /// </summary>
  92. /// <returns>The reported rotation of the direction indicator.</returns>
  93. public virtual Quaternion GetRotation()
  94. {
  95. float offset = (includeHeadsetOffset ? playArea.eulerAngles.y - headset.eulerAngles.y : 0f);
  96. return Quaternion.Euler(0f, transform.localEulerAngles.y + offset, 0f);
  97. }
  98. /// <summary>
  99. /// The SetMaterialColor method sets the current material colour on the direction indicator.
  100. /// </summary>
  101. /// <param name="color">The colour to update the direction indicatormaterial to.</param>
  102. /// <param name="validity">Determines if the colour being set is based from a valid location or invalid location.</param>
  103. public virtual void SetMaterialColor(Color color, bool validity)
  104. {
  105. if (validLocation != null)
  106. {
  107. validLocation.SetActive(validity);
  108. }
  109. if (invalidLocation != null)
  110. {
  111. invalidLocation.SetActive((displayOnInvalidLocation ? !validity : validity));
  112. }
  113. if (usePointerColor)
  114. {
  115. Renderer[] renderers = GetComponentsInChildren<Renderer>();
  116. for (int i = 0; i < renderers.Length; i++)
  117. {
  118. renderers[i].material.color = color;
  119. }
  120. }
  121. }
  122. /// <summary>
  123. /// The GetControllerEvents method returns the associated Controller Events script with the Pointer Direction Indicator script.
  124. /// </summary>
  125. /// <returns>The associated Controller Events script.</returns>
  126. public virtual VRTK_ControllerEvents GetControllerEvents()
  127. {
  128. return controllerEvents;
  129. }
  130. protected virtual void Awake()
  131. {
  132. validLocation = transform.Find("ValidLocation").gameObject;
  133. invalidLocation = transform.Find("InvalidLocation").gameObject;
  134. gameObject.SetActive(false);
  135. }
  136. protected virtual void Update()
  137. {
  138. if (controllerEvents != null && controllerEvents.GetAxisState(coordinateAxis, SDK_BaseController.ButtonPressTypes.Touch) && !InsideDeadzone(controllerEvents.GetAxis(coordinateAxis)))
  139. {
  140. float touchpadAngle = controllerEvents.GetAxisAngle(coordinateAxis);
  141. float angle = ((touchpadAngle > 180) ? touchpadAngle -= 360 : touchpadAngle) + headset.eulerAngles.y;
  142. transform.localEulerAngles = new Vector3(0f, angle, 0f);
  143. }
  144. }
  145. protected virtual bool InsideDeadzone(Vector2 currentAxis)
  146. {
  147. return (currentAxis == Vector2.zero || (Mathf.Abs(currentAxis.x) <= touchpadDeadzone.x && Mathf.Abs(currentAxis.y) <= touchpadDeadzone.y));
  148. }
  149. }
  150. }