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;
}
}
效果