JoystickController.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using UnityEngine;
  2. using UnityEngine.EventSystems;
  3. using UnityEngine.UI;
  4. namespace Google.Maps.Demos.Utilities {
  5. /// <summary>
  6. /// This class implements a simple joystick meant for mobile deployment
  7. /// that allows users to move the camera around the scene.
  8. /// It includes support for: Vertical motion up and down, Forward, Reverse, Yaw.
  9. ///
  10. /// The rotations and forward/reverse motion are controlled by dragging the joystick knob
  11. /// on the circular area. Rotations and Forward are exclusive from each other,
  12. /// and triggered when the knob reaches specific angles.
  13. /// This is meant to create a smooth user experience.
  14. /// Rotation and forward/reverse speeds increase proportionally to the distance of the knob
  15. /// from the joystick center, up to a specified max value.
  16. ///
  17. /// Up and down motion are controlled by two separate buttons.
  18. ///
  19. /// </summary>
  20. public class JoystickController : MonoBehaviour, IDragHandler, IPointerUpHandler,
  21. IPointerDownHandler {
  22. #region properties
  23. // Joystick bounds
  24. public Image Background;
  25. // Camera Rig to move
  26. public Transform CameraRig;
  27. // Direction to follow
  28. public Vector3 InputDirection;
  29. // Lever knob to control forward/reverse, CW and CCW rotations
  30. public Image Lever;
  31. // Maximum rotation speed
  32. public float MaxRotationSpeed = 1f;
  33. // Maximum forward/reverse speed
  34. public float MaxForwardSpeed = 200f;
  35. // Controls going down
  36. public JoystickButton DownButton;
  37. // Min altitude (in meters)
  38. public float MinAltitude = 5;
  39. // Controls going up
  40. public JoystickButton UpButton;
  41. // Max altitude (in meters)
  42. public float MaxAltitude = 300;
  43. // Vertical displacement speed
  44. public float MaxVerticalSpeed = 200f;
  45. // Reference to camera (a child of the camera rig)
  46. private Camera Camera;
  47. #endregion
  48. /// <summary>
  49. /// On start, set joystick defaults.
  50. /// If the app is deployed on mobile device, show the joystick in the scene,
  51. /// and initialize the cameraRig.
  52. ///
  53. /// </summary>
  54. private void Start() {
  55. InputDirection = Vector3.zero;
  56. // Hide by default
  57. gameObject.transform.parent.gameObject.SetActive(false);
  58. // If the example isn't run on mobile devices, hide the joystick
  59. #if (UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR
  60. gameObject.transform.parent.gameObject.SetActive(true);
  61. // Initialize the camera container's position
  62. Camera = CameraRig.GetComponentInChildren<Camera>();
  63. if (Camera != null) {
  64. CameraRig.position = new Vector3(
  65. Camera.transform.position.x,
  66. Camera.transform.position.y,
  67. Camera.transform.position.z);
  68. Camera.transform.localPosition = Vector3.zero;
  69. }
  70. #endif
  71. }
  72. /// <summary>
  73. /// On Updates, adjust the position and CW, CCW rotations of the Rig.
  74. /// The code also applies vertical motions if Up and Down buttons are continously pressed.
  75. ///
  76. /// </summary>
  77. private void Update() {
  78. // Move the camera at a speed that is linearly dependent on the height of the camera above
  79. // the ground plane to make camera manual camera movement practicable. The movement speed
  80. // is clamped between 1% and 100% of the configured MovementSpeed.
  81. float forwardSpeed = Mathf.Clamp(
  82. CameraRig.transform.position.y,
  83. MaxForwardSpeed * 0.01f,
  84. MaxForwardSpeed)*Time.deltaTime;
  85. // Max speed in high altitude
  86. // Min speed at 0
  87. // 0 < Pos y < max altitude
  88. float verticalSpeed = Mathf.Clamp(
  89. CameraRig.transform.position.y,
  90. MaxVerticalSpeed * 0.01f,
  91. MaxVerticalSpeed)*Time.deltaTime;
  92. if (InputDirection.magnitude != 0 && CameraRig != null) {
  93. float rotationDirection = 1f;
  94. float angle = Vector3.Angle(InputDirection, Vector3.right);
  95. if (angle > 90f) rotationDirection = -1f;
  96. if (angle < 80f || angle > 100) {
  97. // Rotate target around y axis
  98. CameraRig.transform.RotateAround(
  99. CameraRig.transform.position,
  100. Vector3.up,
  101. rotationDirection * MaxRotationSpeed * InputDirection.magnitude * Time.deltaTime);
  102. }
  103. else {
  104. float dir = InputDirection.y >= 0 ? 1f : -1f;
  105. CameraRig.transform.position += CameraRig.transform.forward * forwardSpeed * dir
  106. * InputDirection.magnitude;
  107. }
  108. }
  109. if (UpButton != null && CameraRig != null && UpButton.IsButtonPressed()) {
  110. CameraRig.transform.position += CameraRig.transform.up * verticalSpeed;
  111. }
  112. if (DownButton != null && CameraRig != null && DownButton.IsButtonPressed()) {
  113. CameraRig.transform.position -= CameraRig.transform.up * verticalSpeed;
  114. }
  115. CameraRig.transform.position = new Vector3(
  116. CameraRig.transform.position.x,
  117. Mathf.Clamp(CameraRig.transform.position.y, MinAltitude, MaxAltitude),
  118. CameraRig.transform.position.z);
  119. }
  120. #region event listeners
  121. /// <summary>
  122. /// Implements the IDragHandler interface.
  123. /// The function converts the drag of the joystick knob on the UI overlay
  124. /// to a direction vector in worldspace that can be applied to our target.
  125. /// </summary>
  126. /// <param name="ped">The pointer event data</param>
  127. public void OnDrag(PointerEventData ped) {
  128. // Current position
  129. var pos = Vector2.zero;
  130. var rect = Background.rectTransform;
  131. // Move the target based on the Lever's position
  132. RectTransformUtility.ScreenPointToLocalPointInRectangle(
  133. rect,
  134. ped.position,
  135. ped.pressEventCamera,
  136. out pos);
  137. pos.x = pos.x / rect.sizeDelta.x;
  138. pos.y = pos.y / rect.sizeDelta.y;
  139. InputDirection = new Vector3(pos.x, pos.y, 0f);
  140. InputDirection = InputDirection.magnitude > 1 ? InputDirection.normalized : InputDirection;
  141. Lever.rectTransform.anchoredPosition = new Vector3(
  142. InputDirection.x * (rect.sizeDelta.x / 3),
  143. InputDirection.y * rect.sizeDelta.y / 3);
  144. }
  145. /// <summary>
  146. /// Implements the IPointerUpHandler interface.
  147. /// Applies changes in similar ways to the OnDrag function.
  148. /// </summary>
  149. /// <param name="ped">The pointer event data</param>
  150. public void OnPointerDown(PointerEventData ped) {
  151. OnDrag(ped);
  152. }
  153. /// <summary>
  154. /// Implements the IPointerDownHandler interface.
  155. /// Resets the position of the joystick knob and the direction vector.
  156. /// </summary>
  157. /// <param name="ped"></param>
  158. public void OnPointerUp(PointerEventData ped) {
  159. Lever.rectTransform.anchoredPosition = Vector3.zero;
  160. InputDirection = Vector3.zero;
  161. }
  162. #endregion
  163. }
  164. }