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.

190 lines
8.4 KiB

  1. // Step Multiplier|Locomotion|20130
  2. namespace VRTK
  3. {
  4. using UnityEngine;
  5. /// <summary>
  6. /// Multiplies each real world step within the play area to enable further distances to be travelled in the virtual world.
  7. /// </summary>
  8. /// <remarks>
  9. /// **Optional Components:**
  10. /// * `VRTK_ControllerEvents` - The events component to listen for the button presses on. This must be applied on the same GameObject as this script if one is not provided via the `Controller Events` parameter.
  11. ///
  12. /// **Script Usage:**
  13. /// * Place the `VRTK_StepMultiplier` script on either:
  14. /// * Any GameObject in the scene if no activation button is required.
  15. /// * The GameObject with the Controller Events scripts if an activation button is required.
  16. /// * Any other scene GameObject and provide a valid `VRTK_ControllerEvents` component to the `Controller Events` parameter of this script if an activation button is required.
  17. /// </remarks>
  18. /// <example>
  19. /// `VRTK/Examples/028_CameraRig_RoomExtender` shows how the Step Multiplier can be used to move around the scene with multiplied steps.
  20. /// </example>
  21. [AddComponentMenu("VRTK/Scripts/Locomotion/VRTK_StepMultiplier")]
  22. public class VRTK_StepMultiplier : MonoBehaviour
  23. {
  24. /// <summary>
  25. /// Movement methods.
  26. /// </summary>
  27. public enum MovementFunction
  28. {
  29. /// <summary>
  30. /// Moves the head with a non-linear drift movement.
  31. /// </summary>
  32. Nonlinear,
  33. /// <summary>
  34. /// Moves the headset in a direct linear movement.
  35. /// </summary>
  36. LinearDirect
  37. }
  38. [Header("Step Multiplier Settings")]
  39. [Tooltip("The controller button to activate the step multiplier effect. If it is `Undefined` then the step multiplier will always be active.")]
  40. public VRTK_ControllerEvents.ButtonAlias activationButton = VRTK_ControllerEvents.ButtonAlias.Undefined;
  41. [Tooltip("This determines the type of movement used by the extender.")]
  42. public MovementFunction movementFunction = MovementFunction.LinearDirect;
  43. [Tooltip("This is the factor by which movement at the edge of the circle is amplified. `0` is no movement of the play area. Higher values simulate a bigger play area but may be too uncomfortable.")]
  44. [Range(0, 10)]
  45. public float additionalMovementMultiplier = 1.0f;
  46. [Tooltip("This is the size of the circle in which the play area is not moved and everything is normal. If it is to low it becomes uncomfortable when crouching.")]
  47. [Range(0, 5)]
  48. public float headZoneRadius = 0.25f;
  49. [Header("Custom Settings")]
  50. [Tooltip("The Controller Events to listen for the events on. If the script is being applied onto a controller then this parameter can be left blank as it will be auto populated by the controller the script is on at runtime.")]
  51. public VRTK_ControllerEvents controllerEvents;
  52. protected Vector3 relativeMovementOfCameraRig = new Vector3();
  53. protected Transform movementTransform;
  54. protected Transform playArea;
  55. protected Vector3 headCirclePosition;
  56. protected Vector3 lastPosition;
  57. protected Vector3 lastMovement;
  58. protected bool activationEnabled;
  59. protected VRTK_ControllerEvents.ButtonAlias subscribedActivationButton = VRTK_ControllerEvents.ButtonAlias.Undefined;
  60. protected bool buttonSubscribed;
  61. protected virtual void Awake()
  62. {
  63. VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
  64. }
  65. protected virtual void OnEnable()
  66. {
  67. activationEnabled = false;
  68. buttonSubscribed = false;
  69. movementTransform = VRTK_DeviceFinder.HeadsetTransform();
  70. playArea = VRTK_DeviceFinder.PlayAreaTransform();
  71. MoveHeadCircleNonLinearDrift();
  72. if (movementTransform != null)
  73. {
  74. lastPosition = movementTransform.localPosition;
  75. }
  76. }
  77. protected virtual void OnDestroy()
  78. {
  79. VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
  80. }
  81. protected virtual void Update()
  82. {
  83. ManageButtonSubscription();
  84. switch (movementFunction)
  85. {
  86. case MovementFunction.Nonlinear:
  87. MoveHeadCircleNonLinearDrift();
  88. break;
  89. case MovementFunction.LinearDirect:
  90. MoveHeadCircle();
  91. break;
  92. default:
  93. break;
  94. }
  95. }
  96. protected virtual void ManageButtonSubscription()
  97. {
  98. controllerEvents = (controllerEvents != null ? controllerEvents : GetComponentInParent<VRTK_ControllerEvents>());
  99. if (controllerEvents != null && buttonSubscribed && subscribedActivationButton != VRTK_ControllerEvents.ButtonAlias.Undefined && activationButton != subscribedActivationButton)
  100. {
  101. buttonSubscribed = false;
  102. controllerEvents.UnsubscribeToButtonAliasEvent(subscribedActivationButton, true, ActivationButtonPressed);
  103. controllerEvents.UnsubscribeToButtonAliasEvent(subscribedActivationButton, false, ActivationButtonReleased);
  104. subscribedActivationButton = VRTK_ControllerEvents.ButtonAlias.Undefined;
  105. }
  106. if (controllerEvents != null && !buttonSubscribed && activationButton != VRTK_ControllerEvents.ButtonAlias.Undefined)
  107. {
  108. controllerEvents.SubscribeToButtonAliasEvent(activationButton, true, ActivationButtonPressed);
  109. controllerEvents.SubscribeToButtonAliasEvent(activationButton, false, ActivationButtonReleased);
  110. buttonSubscribed = true;
  111. subscribedActivationButton = activationButton;
  112. }
  113. }
  114. protected virtual void ActivationButtonPressed(object sender, ControllerInteractionEventArgs e)
  115. {
  116. activationEnabled = true;
  117. }
  118. protected virtual void ActivationButtonReleased(object sender, ControllerInteractionEventArgs e)
  119. {
  120. activationEnabled = false;
  121. }
  122. protected virtual void Move(Vector3 movement)
  123. {
  124. headCirclePosition += movement;
  125. if (playArea != null && (activationEnabled || activationButton == VRTK_ControllerEvents.ButtonAlias.Undefined))
  126. {
  127. playArea.localPosition += movement * additionalMovementMultiplier;
  128. relativeMovementOfCameraRig += movement * additionalMovementMultiplier;
  129. }
  130. }
  131. protected virtual void MoveHeadCircle()
  132. {
  133. if (movementTransform != null)
  134. {
  135. //Get the movement of the head relative to the headCircle.
  136. Vector3 circleCenterToHead = new Vector3(movementTransform.localPosition.x - headCirclePosition.x, 0, movementTransform.localPosition.z - headCirclePosition.z);
  137. //Get the direction of the head movement.
  138. UpdateLastMovement();
  139. //Checks if the head is outside of the head cirlce and moves the head circle and play area in the movementDirection.
  140. if (circleCenterToHead.sqrMagnitude > headZoneRadius * headZoneRadius && lastMovement != Vector3.zero)
  141. {
  142. //Just move like the headset moved
  143. Move(lastMovement);
  144. }
  145. }
  146. }
  147. protected virtual void MoveHeadCircleNonLinearDrift()
  148. {
  149. if (movementTransform != null)
  150. {
  151. Vector3 movement = new Vector3(movementTransform.localPosition.x - headCirclePosition.x, 0, movementTransform.localPosition.z - headCirclePosition.z);
  152. if (movement.sqrMagnitude > headZoneRadius * headZoneRadius)
  153. {
  154. Vector3 deltaMovement = movement.normalized * (movement.magnitude - headZoneRadius);
  155. Move(deltaMovement);
  156. }
  157. }
  158. }
  159. protected virtual void UpdateLastMovement()
  160. {
  161. if (movementTransform != null)
  162. {
  163. //Save the last movement
  164. lastMovement = movementTransform.localPosition - lastPosition;
  165. lastMovement.y = 0;
  166. lastPosition = movementTransform.localPosition;
  167. }
  168. }
  169. }
  170. }