JoyStick_InputSystem.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using UnityEngine;
  2. using UnityEngine.EventSystems;
  3. using UnityEngine.InputSystem;
  4. using UnityEngine.InputSystem.Controls;
  5. using UnityEngine.InputSystem.EnhancedTouch;
  6. using UnityEngine.InputSystem.Layouts;
  7. using UnityEngine.InputSystem.OnScreen;
  8. using UnityEngine.Serialization;
  9. [AddComponentMenu("Input/虚拟摇杆 - 新输入系统(InputSystem)")]
  10. public class JoyStick_InputSystem : OnScreenControl, IPointerDownHandler
  11. {
  12. enum JoyStickType
  13. {
  14. [InspectorName("固定在默认位置")]
  15. FixedInDefaultPosition = 0,
  16. [InspectorName("固定在触摸位置")]
  17. FixedInClickPosition = 1,
  18. [InspectorName("跟随触摸移动")]
  19. Flexible = 2
  20. }
  21. [Header("基础设置")]
  22. [Tooltip("摇杆背景")]
  23. [SerializeField]
  24. private RectTransform joyStickBackGround;
  25. [Tooltip("摇杆按钮")]
  26. [SerializeField]
  27. private RectTransform joyStickButton;
  28. [Tooltip("摇杆按钮移动范围(半径)")]
  29. [FormerlySerializedAs("movementRange")]
  30. [SerializeField]
  31. private float movementRange = 50;
  32. [Tooltip("控制设备路径")]
  33. [InputControl(layout = "Vector2")]
  34. [SerializeField]
  35. private new string controlPath;
  36. [Header("类型设置")]
  37. [Tooltip("摇杆类型")]
  38. [SerializeField]
  39. private JoyStickType joyStickType;
  40. [Tooltip("摇杆是否默认隐藏")]
  41. [SerializeField]
  42. private bool isHideWithoutTouch;
  43. //触摸屏(设备)
  44. private Touchscreen currentTouchScreen;
  45. //控制摇杆的触点对象
  46. private TouchControl joyStickTouch;
  47. //摇杆初始位置
  48. private Vector2 joyStickStartPos;
  49. //与屏幕相关的相机(主要用于将屏幕上的位置转换为某UI矩形内的相对位置)
  50. private Camera screenCamera;
  51. //模拟(鼠标或者笔)输入
  52. private TouchSimulation touchSimulation;
  53. //画布渲染模式
  54. private RenderMode renderMode;
  55. //点击区域UI的RectTransform
  56. private RectTransform rectTransform;
  57. protected override string controlPathInternal
  58. {
  59. get => controlPath;
  60. set => controlPath = value;
  61. }
  62. private void Awake()
  63. {
  64. #if UNITY_EDITOR
  65. if (!gameObject.TryGetComponent(out touchSimulation))
  66. {
  67. touchSimulation = gameObject.AddComponent<TouchSimulation>();
  68. }
  69. #endif
  70. }
  71. private void Start()
  72. {
  73. currentTouchScreen = Touchscreen.current;
  74. //记录摇杆初始位置
  75. joyStickStartPos = joyStickBackGround.anchoredPosition;
  76. if (isHideWithoutTouch)
  77. {
  78. joyStickBackGround.gameObject.SetActive(false);
  79. }
  80. //获取画布的渲染模式
  81. var canvas = transform.GetComponentInParent<Canvas>();
  82. renderMode = canvas != null ? canvas.renderMode : RenderMode.ScreenSpaceOverlay;
  83. //获取点击区域UI的RectTransform
  84. rectTransform = transform.GetComponent<RectTransform>();
  85. }
  86. private void Update()
  87. {
  88. UpdateJoyStickUIPos();
  89. }
  90. private void OnDestroy()
  91. {
  92. #if UNITY_EDITOR
  93. touchSimulation = null;
  94. #endif
  95. }
  96. public void OnPointerDown(PointerEventData eventData)
  97. {
  98. //获取与屏幕相关的相机
  99. if (renderMode != RenderMode.ScreenSpaceOverlay)
  100. {
  101. screenCamera = eventData.pressEventCamera;
  102. }
  103. //摇杆没有被控制时分配控制权
  104. if (joyStickTouch == null)
  105. {
  106. for (int i = 0; i < currentTouchScreen.touches.Count; i++)
  107. {
  108. var touch = currentTouchScreen.touches[i];
  109. if (touch.phase.ReadValue() == UnityEngine.InputSystem.TouchPhase.Began)
  110. {
  111. if (
  112. RectTransformUtility.RectangleContainsScreenPoint(
  113. rectTransform,
  114. touch.position.ReadValue(),
  115. screenCamera
  116. )
  117. )
  118. {
  119. joyStickTouch = touch;
  120. RectTransformUtility.ScreenPointToLocalPointInRectangle(
  121. rectTransform,
  122. joyStickTouch.position.ReadValue(),
  123. screenCamera,
  124. out var joyStickBgPos
  125. );
  126. SetJoyStickUI(joyStickBgPos, Vector2.zero, true);
  127. }
  128. }
  129. }
  130. }
  131. }
  132. private void UpdateJoyStickUIPos()
  133. {
  134. if (joyStickTouch == null)
  135. return;
  136. bool isActive = true;
  137. Vector2 joyStickBgPos = Vector2.zero;
  138. Vector2 joyStickBtnPos = Vector2.zero;
  139. Vector2 sendToControlValue = Vector2.zero;
  140. switch (joyStickTouch.phase.ReadValue())
  141. {
  142. case UnityEngine.InputSystem.TouchPhase.None:
  143. break;
  144. case UnityEngine.InputSystem.TouchPhase.Began:
  145. case UnityEngine.InputSystem.TouchPhase.Moved:
  146. //更新摇杆位置数据
  147. RectTransformUtility.ScreenPointToLocalPointInRectangle(
  148. rectTransform,
  149. joyStickTouch.position.ReadValue(),
  150. screenCamera,
  151. out var touchInRectPos
  152. );
  153. Vector2 delta = touchInRectPos - joyStickBackGround.anchoredPosition;
  154. joyStickBgPos = joyStickBackGround.anchoredPosition;
  155. if (joyStickType == JoyStickType.Flexible)
  156. {
  157. if (delta.magnitude > movementRange)
  158. {
  159. joyStickBgPos += delta.normalized * (delta.magnitude - movementRange);
  160. }
  161. }
  162. joyStickBtnPos = Vector2.ClampMagnitude(delta, movementRange);
  163. isActive = true;
  164. sendToControlValue = delta / movementRange;
  165. break;
  166. case UnityEngine.InputSystem.TouchPhase.Ended:
  167. case UnityEngine.InputSystem.TouchPhase.Canceled:
  168. //收回Touch对摇杆的控制权
  169. joyStickTouch = null;
  170. joyStickBgPos = joyStickStartPos;
  171. isActive = false;
  172. break;
  173. case UnityEngine.InputSystem.TouchPhase.Stationary:
  174. break;
  175. }
  176. //设置摇杆位置
  177. SetJoyStickUI(joyStickBgPos, joyStickBtnPos, isActive);
  178. //给控制器发送新位置
  179. SendValueToControl(sendToControlValue);
  180. }
  181. private void SetJoyStickUI(Vector2 joyStickBgPos, Vector2 joyStickBtnPos, bool isActive)
  182. {
  183. //设置joyStickBackGround位置
  184. switch (joyStickType)
  185. {
  186. case JoyStickType.FixedInDefaultPosition:
  187. break;
  188. case JoyStickType.FixedInClickPosition:
  189. case JoyStickType.Flexible:
  190. joyStickBackGround.anchoredPosition = joyStickBgPos;
  191. break;
  192. }
  193. //设置joyStickButton位置
  194. joyStickButton.anchoredPosition = joyStickBtnPos;
  195. //设置
  196. if (isHideWithoutTouch && joyStickBackGround.gameObject.activeSelf != isActive)
  197. {
  198. joyStickBackGround.gameObject.SetActive(isActive);
  199. }
  200. }
  201. }