using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.Serialization; /// <summary> /// 方向盘 /// 通过左右滑动控制转向 /// </summary> public class UISteeringWheel : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler { //约束拖动区域 [SerializeField] private RectTransform m_RectBounds; private RectTransform m_RectTransform; private float halfBoundsWidth; private float halfWidth; [Serializable] public class Move_Event : UnityEvent<float> { } [Serializable] public class Stop_Event : UnityEvent { } [FormerlySerializedAs("onMove")] [SerializeField] public Move_Event MoveEvent = new Move_Event(); [FormerlySerializedAs("onStop")] [SerializeField] public Stop_Event StopEvent = new Stop_Event(); private void Awake() { m_RectTransform = this.GetComponent<RectTransform>(); halfBoundsWidth = m_RectBounds.sizeDelta.x / 2; halfWidth = m_RectTransform.sizeDelta.x / 2; } public void OnPointerDown(PointerEventData eventData) { } //坑:必需要实现OnPointerDown,OnPointerUp才能响应 public void OnPointerUp(PointerEventData eventData) { m_RectTransform.anchoredPosition = Vector2.zero; StopEvent?.Invoke(); } public void OnDrag(PointerEventData eventData) { if (!eventData.IsPointerMoving()) return; var dragPosition = eventData.position; var localPosition = ScreenPointToLocalPointInRectangle(dragPosition); m_RectTransform.anchoredPosition = localPosition; //左右滑动值 float slipX = localPosition.x; float sign = slipX < 0 ? -1 : 1; slipX = Mathf.Abs(slipX); //小幅度滑动时不触发转向事件 float minSlip = halfWidth / 10; if (slipX <= minSlip) return; slipX = slipX - minSlip; //归一化 float value = slipX / (halfBoundsWidth - minSlip); //降低转向灵敏度 value = sign * Mathf.Pow(value, 4); MoveEvent?.Invoke(value); } private Vector2 ScreenPointToLocalPointInRectangle(Vector2 screenPoint) { Vector2 localPoint = Vector2.zero; RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RectBounds, screenPoint, null, out localPoint); return GetAdjustedPosition(localPoint); } private Vector2 GetAdjustedPosition(Vector2 pos) { pos.x = Mathf.Max(pos.x, -halfBoundsWidth); pos.x = Mathf.Min(pos.x, halfBoundsWidth); pos.y = 0; return pos; } }
效果