| | |
| | | using System; |
| | | |
| | | |
| | | public class BoundedDrag : MonoBehaviour, IEndDragHandler, IBeginDragHandler, IDragHandler |
| | | { |
| | | |
| | | [SerializeField] |
| | | RectTransform m_Target; |
| | | public RectTransform target { |
| | | get { return m_Target; } |
| | | set { |
| | | m_Target = value; |
| | | } |
| | | } |
| | | |
| | | public RectTransform rectTransform { get { return this.transform as RectTransform; } } |
| | | |
| | | [SerializeField] |
| | | ScaleRange m_ScaleRange; |
| | | public ScaleRange scaleRange { |
| | | get { return m_ScaleRange; } |
| | | set { m_ScaleRange = value; } |
| | | } |
| | | |
| | | [SerializeField] |
| | | float m_DefaultScale; |
| | | public float defaultScale { get { return m_DefaultScale; } } |
| | | |
| | | [SerializeField] |
| | | float m_DestScale = 1f; |
| | | public float destScale { |
| | | get { return m_DestScale; } |
| | | set { m_DestScale = Mathf.Clamp(value, scaleRange.min, scaleRange.max); } |
| | | } |
| | | |
| | | float refScale = 0f; |
| | | |
| | | public float currentScale { |
| | | get { |
| | | return target.localScale.x; |
| | | } |
| | | set { |
| | | target.localScale = Vector3.one * Mathf.Clamp(value, scaleRange.min, scaleRange.max); |
| | | } |
| | | } |
| | | |
| | | [SerializeField] |
| | | MoveArea m_MoveArea; |
| | | public MoveArea moveArea { |
| | | get { return m_MoveArea; } |
| | | set { m_MoveArea = value; } |
| | | } |
| | | |
| | | [SerializeField] |
| | | Vector2 m_DestPosition = Vector2.zero; |
| | | public Vector2 destPosition { |
| | | get { return m_DestPosition; } |
| | | set { m_DestPosition = new Vector2(Mathf.Clamp(value.x, moveArea.Left * destScale, moveArea.Right * destScale), Mathf.Clamp(value.y, moveArea.Bottom * destScale, moveArea.Top * destScale)); } |
| | | } |
| | | |
| | | Vector3 refPosition = Vector3.zero; |
| | | |
| | | public Vector2 currentPosition { |
| | | get { return target.anchoredPosition; } |
| | | set { target.anchoredPosition = value; } |
| | | } |
| | | |
| | | Vector2 startTouchPosition01; |
| | | Vector2 startGroundPosition; |
| | | |
| | | Vector2 lastTouchPosition01; |
| | | Vector2 curTouchPosition01; |
| | | Vector2 lastTouchPosition02; |
| | | Vector2 curTouchPosition02; |
| | | |
| | | [SerializeField] |
| | | Action m_OnBeginDrag; |
| | | public Action onBeginDrag { |
| | | get { return m_OnBeginDrag; } |
| | | } |
| | | |
| | | bool m_Actionable = true; |
| | | public bool actionable { |
| | | get { return m_Actionable; } |
| | | set { m_Actionable = value; } |
| | | } |
| | | |
| | | private void OnEnable() |
| | | { |
| | | destPosition = currentPosition = Vector3.zero; |
| | | } |
| | | |
| | | public void OnBeginDrag(PointerEventData eventData) |
| | | { |
| | | |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | if (Input.GetKey(KeyCode.LeftControl) && eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | TwoFingerHandleBegin(); |
| | | } |
| | | else if (eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | OneFingerHandleBegin(eventData); |
| | | } |
| | | #else |
| | | if (Input.touchCount == 2) { |
| | | TwoFingerHandleBegin(); |
| | | } |
| | | if (Input.touchCount == 1) { |
| | | OneFingerHandleBegin(eventData); |
| | | } |
| | | #endif |
| | | onBeginDrag?.Invoke(); |
| | | } |
| | | |
| | | public void OnDrag(PointerEventData eventData) |
| | | { |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | if (Input.GetKey(KeyCode.LeftControl) && eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | TwoFingerHandle(); |
| | | } |
| | | else if (eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | OneFingerHandle(eventData); |
| | | } |
| | | #else |
| | | if (Input.touchCount == 2) { |
| | | TwoFingerHandle(); |
| | | } |
| | | if (Input.touchCount == 1) { |
| | | OneFingerHandle(eventData); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | public void OnEndDrag(PointerEventData eventData) |
| | | { |
| | | } |
| | | |
| | | void LateUpdate() |
| | | { |
| | | if (!actionable) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | if (Mathf.Abs(currentScale - destScale) > 0.01f) |
| | | { |
| | | float newScale = Mathf.SmoothDamp(currentScale, destScale, ref refScale, 0.15f); |
| | | currentScale = newScale; |
| | | } |
| | | |
| | | if (Vector2.Distance(currentPosition, destPosition) > 0.1f) |
| | | { |
| | | Vector2 newPosition = Vector3.SmoothDamp(currentPosition, destPosition, ref refPosition, 0.15f); |
| | | currentPosition = newPosition; |
| | | } |
| | | } |
| | | |
| | | private void OneFingerHandleBegin(PointerEventData eventData) |
| | | { |
| | | startTouchPosition01 = Vector2.zero; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out startTouchPosition01); |
| | | startGroundPosition = currentPosition; |
| | | |
| | | } |
| | | |
| | | private void OneFingerHandle(PointerEventData eventData) |
| | | { |
| | | Vector2 localMouse; |
| | | if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out localMouse)) |
| | | { |
| | | var pointerDelta = localMouse - startTouchPosition01; |
| | | destPosition = startGroundPosition + pointerDelta; |
| | | } |
| | | } |
| | | |
| | | private void TwoFingerHandle() |
| | | { |
| | | // 方便PC调试逻辑 |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | curTouchPosition01 = new Vector2(Screen.width / 2, Screen.height / 2); |
| | | curTouchPosition02 = new Vector2(Input.mousePosition.x, Input.mousePosition.y); |
| | | #else |
| | | Touch touchFirst = Input.touches[0]; |
| | | Touch touchSecond = Input.touches[1]; |
| | | curTouchPosition01 = touchFirst.position; |
| | | curTouchPosition02 = touchSecond.position; |
| | | #endif |
| | | |
| | | float lastLength = Vector2.Distance(lastTouchPosition01, lastTouchPosition02); |
| | | float curLength = Vector2.Distance(curTouchPosition01, curTouchPosition02); |
| | | destScale *= curLength / Mathf.Clamp(lastLength, 1, float.MaxValue); |
| | | |
| | | lastTouchPosition01 = curTouchPosition01; |
| | | lastTouchPosition02 = curTouchPosition02; |
| | | } |
| | | |
| | | private void TwoFingerHandleBegin() |
| | | { |
| | | // 方便PC调试逻辑 |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | curTouchPosition01 = new Vector2(Screen.width / 2, Screen.height / 2); |
| | | curTouchPosition02 = new Vector2(Input.mousePosition.x, Input.mousePosition.y); |
| | | #else |
| | | Touch touchFirst = Input.touches[0]; |
| | | Touch touchSecond = Input.touches[1]; |
| | | curTouchPosition01 = touchFirst.position; |
| | | curTouchPosition02 = touchSecond.position; |
| | | #endif |
| | | |
| | | lastTouchPosition01 = curTouchPosition01; |
| | | lastTouchPosition02 = curTouchPosition02; |
| | | } |
| | | |
| | | [Serializable] |
| | | public struct ScaleRange |
| | | { |
| | | public float min; |
| | | public float max; |
| | | } |
| | | |
| | | [Serializable] |
| | | public struct MoveArea |
| | | { |
| | | public float Left; |
| | | public float Right; |
| | | public float Top; |
| | | public float Bottom; |
| | | |
| | | public MoveArea(float _left, float _right, float _top, float _bottom) |
| | | { |
| | | this.Left = _left; |
| | | this.Right = _right; |
| | | this.Top = _top; |
| | | this.Bottom = _bottom; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 实现拖拽和缩放功能的组件,支持单指拖拽和双指缩放。 |
| | | /// </summary> |
| | | public class BoundedDrag : MonoBehaviour, IEndDragHandler, IBeginDragHandler, IDragHandler |
| | | { |
| | | [SerializeField] |
| | | RectTransform m_Target; // 拖拽的目标对象 |
| | | public RectTransform target { |
| | | get { return m_Target; } |
| | | set { |
| | | m_Target = value; |
| | | } |
| | | } |
| | | |
| | | public RectTransform rectTransform { get { return this.transform as RectTransform; } } |
| | | |
| | | [SerializeField] |
| | | ScaleRange m_ScaleRange; // 缩放范围 |
| | | public ScaleRange scaleRange { |
| | | get { return m_ScaleRange; } |
| | | set { m_ScaleRange = value; } |
| | | } |
| | | |
| | | [SerializeField] |
| | | float m_DefaultScale; // 默认缩放值 |
| | | public float defaultScale { get { return m_DefaultScale; } } |
| | | |
| | | [SerializeField] |
| | | float m_DestScale = 1f; // 目标缩放值 |
| | | public float destScale { |
| | | get { return m_DestScale; } |
| | | set { m_DestScale = Mathf.Clamp(value, scaleRange.min, scaleRange.max); } |
| | | } |
| | | |
| | | float refScale = 0f; // 用于平滑缩放的参考值 |
| | | |
| | | public float currentScale { |
| | | get { |
| | | return target.localScale.x; |
| | | } |
| | | set { |
| | | target.localScale = Vector3.one * Mathf.Clamp(value, scaleRange.min, scaleRange.max); |
| | | } |
| | | } |
| | | |
| | | [SerializeField] |
| | | MoveArea m_MoveArea; // 拖拽的边界区域 |
| | | public MoveArea moveArea { |
| | | get { return m_MoveArea; } |
| | | set { m_MoveArea = value; } |
| | | } |
| | | |
| | | [SerializeField] |
| | | Vector2 m_DestPosition = Vector2.zero; // 目标位置 |
| | | public Vector2 destPosition { |
| | | get { return m_DestPosition; } |
| | | set { m_DestPosition = new Vector2(Mathf.Clamp(value.x, moveArea.Left * destScale, moveArea.Right * destScale), Mathf.Clamp(value.y, moveArea.Bottom * destScale, moveArea.Top * destScale)); } |
| | | } |
| | | |
| | | Vector3 refPosition = Vector3.zero; // 用于平滑移动的参考值 |
| | | |
| | | public Vector2 currentPosition { |
| | | get { return target.anchoredPosition; } |
| | | set { target.anchoredPosition = value; } |
| | | } |
| | | |
| | | Vector2 startTouchPosition01; // 单指拖拽的起始触摸位置 |
| | | Vector2 startGroundPosition; // 单指拖拽的起始地面位置 |
| | | |
| | | Vector2 lastTouchPosition01; // 双指缩放的上一帧触摸位置1 |
| | | Vector2 curTouchPosition01; // 双指缩放的当前帧触摸位置1 |
| | | Vector2 lastTouchPosition02; // 双指缩放的上一帧触摸位置2 |
| | | Vector2 curTouchPosition02; // 双指缩放的当前帧触摸位置2 |
| | | |
| | | [SerializeField] |
| | | Action m_OnBeginDrag; // 拖拽开始事件 |
| | | public Action onBeginDrag { |
| | | get { return m_OnBeginDrag; } |
| | | } |
| | | |
| | | bool m_Actionable = true; // 是否可操作 |
| | | public bool actionable { |
| | | get { return m_Actionable; } |
| | | set { m_Actionable = value; } |
| | | } |
| | | |
| | | private void OnEnable() |
| | | { |
| | | destPosition = currentPosition = Vector3.zero; // 初始化位置 |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 拖拽开始事件处理 |
| | | /// </summary> |
| | | public void OnBeginDrag(PointerEventData eventData) |
| | | { |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | if (Input.GetKey(KeyCode.LeftControl) && eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | TwoFingerHandleBegin(); // 双指缩放开始 |
| | | } |
| | | else if (eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | OneFingerHandleBegin(eventData); // 单指拖拽开始 |
| | | } |
| | | #else |
| | | if (Input.touchCount == 2) { |
| | | TwoFingerHandleBegin(); |
| | | } |
| | | if (Input.touchCount == 1) { |
| | | OneFingerHandleBegin(eventData); |
| | | } |
| | | #endif |
| | | onBeginDrag?.Invoke(); // 触发拖拽开始事件 |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 拖拽过程中的事件处理 |
| | | /// </summary> |
| | | public void OnDrag(PointerEventData eventData) |
| | | { |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | if (Input.GetKey(KeyCode.LeftControl) && eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | TwoFingerHandle(); // 双指缩放 |
| | | } |
| | | else if (eventData.button == PointerEventData.InputButton.Left) |
| | | { |
| | | OneFingerHandle(eventData); // 单指拖拽 |
| | | } |
| | | #else |
| | | if (Input.touchCount == 2) { |
| | | TwoFingerHandle(); |
| | | } |
| | | if (Input.touchCount == 1) { |
| | | OneFingerHandle(eventData); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 拖拽结束事件处理 |
| | | /// </summary> |
| | | public void OnEndDrag(PointerEventData eventData) |
| | | { |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 每帧更新,平滑处理缩放和位置 |
| | | /// </summary> |
| | | void LateUpdate() |
| | | { |
| | | if (!actionable) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | if (Mathf.Abs(currentScale - destScale) > 0.01f) |
| | | { |
| | | float newScale = Mathf.SmoothDamp(currentScale, destScale, ref refScale, 0.15f); |
| | | currentScale = newScale; |
| | | } |
| | | |
| | | if (Vector2.Distance(currentPosition, destPosition) > 0.1f) |
| | | { |
| | | Vector2 newPosition = Vector3.SmoothDamp(currentPosition, destPosition, ref refPosition, 0.15f); |
| | | currentPosition = newPosition; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 单指拖拽开始 |
| | | /// </summary> |
| | | private void OneFingerHandleBegin(PointerEventData eventData) |
| | | { |
| | | startTouchPosition01 = Vector2.zero; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out startTouchPosition01); |
| | | startGroundPosition = currentPosition; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 单指拖拽处理 |
| | | /// </summary> |
| | | private void OneFingerHandle(PointerEventData eventData) |
| | | { |
| | | Vector2 localMouse; |
| | | if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out localMouse)) |
| | | { |
| | | var pointerDelta = localMouse - startTouchPosition01; |
| | | destPosition = startGroundPosition + pointerDelta; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 双指缩放处理 |
| | | /// </summary> |
| | | private void TwoFingerHandle() |
| | | { |
| | | // 方便PC调试逻辑 |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | curTouchPosition01 = new Vector2(Screen.width / 2, Screen.height / 2); |
| | | curTouchPosition02 = new Vector2(Input.mousePosition.x, Input.mousePosition.y); |
| | | #else |
| | | Touch touchFirst = Input.touches[0]; |
| | | Touch touchSecond = Input.touches[1]; |
| | | curTouchPosition01 = touchFirst.position; |
| | | curTouchPosition02 = touchSecond.position; |
| | | #endif |
| | | |
| | | float lastLength = Vector2.Distance(lastTouchPosition01, lastTouchPosition02); |
| | | float curLength = Vector2.Distance(curTouchPosition01, curTouchPosition02); |
| | | destScale *= curLength / Mathf.Clamp(lastLength, 1, float.MaxValue); |
| | | |
| | | lastTouchPosition01 = curTouchPosition01; |
| | | lastTouchPosition02 = curTouchPosition02; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 双指缩放开始 |
| | | /// </summary> |
| | | private void TwoFingerHandleBegin() |
| | | { |
| | | // 方便PC调试逻辑 |
| | | #if UNITY_EDITOR || UNITY_STANDALONE |
| | | curTouchPosition01 = new Vector2(Screen.width / 2, Screen.height / 2); |
| | | curTouchPosition02 = new Vector2(Input.mousePosition.x, Input.mousePosition.y); |
| | | #else |
| | | Touch touchFirst = Input.touches[0]; |
| | | Touch touchSecond = Input.touches[1]; |
| | | curTouchPosition01 = touchFirst.position; |
| | | curTouchPosition02 = touchSecond.position; |
| | | #endif |
| | | |
| | | lastTouchPosition01 = curTouchPosition01; |
| | | lastTouchPosition02 = curTouchPosition02; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 缩放范围结构体 |
| | | /// </summary> |
| | | [Serializable] |
| | | public struct ScaleRange |
| | | { |
| | | public float min; // 最小缩放值 |
| | | public float max; // 最大缩放值 |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 拖拽区域结构体 |
| | | /// </summary> |
| | | [Serializable] |
| | | public struct MoveArea |
| | | { |
| | | public float Left; // 左边界 |
| | | public float Right; // 右边界 |
| | | public float Top; // 上边界 |
| | | public float Bottom; // 下边界 |
| | | |
| | | public MoveArea(float _left, float _right, float _top, float _bottom) |
| | | { |
| | | this.Left = _left; |
| | | this.Right = _right; |
| | | this.Top = _top; |
| | | this.Bottom = _bottom; |
| | | } |
| | | } |
| | | } |