using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.EnhancedTouch; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.OnScreen; using UnityEngine.Serialization; [AddComponentMenu("Input/虚拟摇杆 - 新输入系统(InputSystem)")] public class JoyStick_InputSystem : OnScreenControl, IPointerDownHandler { enum JoyStickType { [InspectorName("固定在默认位置")] FixedInDefaultPosition = 0, [InspectorName("固定在触摸位置")] FixedInClickPosition = 1, [InspectorName("跟随触摸移动")] Flexible = 2 } [Header("基础设置")] [Tooltip("摇杆背景")] [SerializeField] private RectTransform joyStickBackGround; [Tooltip("摇杆按钮")] [SerializeField] private RectTransform joyStickButton; [Tooltip("摇杆按钮移动范围(半径)")] [FormerlySerializedAs("movementRange")] [SerializeField] private float movementRange = 50; [Tooltip("控制设备路径")] [InputControl(layout = "Vector2")] [SerializeField] private new string controlPath; [Header("类型设置")] [Tooltip("摇杆类型")] [SerializeField] private JoyStickType joyStickType; [Tooltip("摇杆是否默认隐藏")] [SerializeField] private bool isHideWithoutTouch; //触摸屏(设备) private Touchscreen currentTouchScreen; //控制摇杆的触点对象 private TouchControl joyStickTouch; //摇杆初始位置 private Vector2 joyStickStartPos; //与屏幕相关的相机(主要用于将屏幕上的位置转换为某UI矩形内的相对位置) private Camera screenCamera; //模拟(鼠标或者笔)输入 private TouchSimulation touchSimulation; //画布渲染模式 private RenderMode renderMode; //点击区域UI的RectTransform private RectTransform rectTransform; protected override string controlPathInternal { get => controlPath; set => controlPath = value; } private void Awake() { #if UNITY_EDITOR if (!gameObject.TryGetComponent(out touchSimulation)) { touchSimulation = gameObject.AddComponent(); } #endif } private void Start() { currentTouchScreen = Touchscreen.current; //记录摇杆初始位置 joyStickStartPos = joyStickBackGround.anchoredPosition; if (isHideWithoutTouch) { joyStickBackGround.gameObject.SetActive(false); } //获取画布的渲染模式 var canvas = transform.GetComponentInParent(); renderMode = canvas != null ? canvas.renderMode : RenderMode.ScreenSpaceOverlay; //获取点击区域UI的RectTransform rectTransform = transform.GetComponent(); } private void Update() { UpdateJoyStickUIPos(); } private void OnDestroy() { #if UNITY_EDITOR touchSimulation = null; #endif } public void OnPointerDown(PointerEventData eventData) { //获取与屏幕相关的相机 if (renderMode != RenderMode.ScreenSpaceOverlay) { screenCamera = eventData.pressEventCamera; } //摇杆没有被控制时分配控制权 if (joyStickTouch == null) { for (int i = 0; i < currentTouchScreen.touches.Count; i++) { var touch = currentTouchScreen.touches[i]; if (touch.phase.ReadValue() == UnityEngine.InputSystem.TouchPhase.Began) { if ( RectTransformUtility.RectangleContainsScreenPoint( rectTransform, touch.position.ReadValue(), screenCamera ) ) { joyStickTouch = touch; RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, joyStickTouch.position.ReadValue(), screenCamera, out var joyStickBgPos ); SetJoyStickUI(joyStickBgPos, Vector2.zero, true); } } } } } private void UpdateJoyStickUIPos() { if (joyStickTouch == null) return; bool isActive = true; Vector2 joyStickBgPos = Vector2.zero; Vector2 joyStickBtnPos = Vector2.zero; Vector2 sendToControlValue = Vector2.zero; switch (joyStickTouch.phase.ReadValue()) { case UnityEngine.InputSystem.TouchPhase.None: break; case UnityEngine.InputSystem.TouchPhase.Began: case UnityEngine.InputSystem.TouchPhase.Moved: //更新摇杆位置数据 RectTransformUtility.ScreenPointToLocalPointInRectangle( rectTransform, joyStickTouch.position.ReadValue(), screenCamera, out var touchInRectPos ); Vector2 delta = touchInRectPos - joyStickBackGround.anchoredPosition; joyStickBgPos = joyStickBackGround.anchoredPosition; if (joyStickType == JoyStickType.Flexible) { if (delta.magnitude > movementRange) { joyStickBgPos += delta.normalized * (delta.magnitude - movementRange); } } joyStickBtnPos = Vector2.ClampMagnitude(delta, movementRange); isActive = true; sendToControlValue = delta / movementRange; break; case UnityEngine.InputSystem.TouchPhase.Ended: case UnityEngine.InputSystem.TouchPhase.Canceled: //收回Touch对摇杆的控制权 joyStickTouch = null; joyStickBgPos = joyStickStartPos; isActive = false; break; case UnityEngine.InputSystem.TouchPhase.Stationary: break; } //设置摇杆位置 SetJoyStickUI(joyStickBgPos, joyStickBtnPos, isActive); //给控制器发送新位置 SendValueToControl(sendToControlValue); } private void SetJoyStickUI(Vector2 joyStickBgPos, Vector2 joyStickBtnPos, bool isActive) { //设置joyStickBackGround位置 switch (joyStickType) { case JoyStickType.FixedInDefaultPosition: break; case JoyStickType.FixedInClickPosition: case JoyStickType.Flexible: joyStickBackGround.anchoredPosition = joyStickBgPos; break; } //设置joyStickButton位置 joyStickButton.anchoredPosition = joyStickBtnPos; //设置 if (isHideWithoutTouch && joyStickBackGround.gameObject.activeSelf != isActive) { joyStickBackGround.gameObject.SetActive(isActive); } } }