| //-------------------------------------------------------- | 
| //    [Author]:           玩个游戏 | 
| //    [  Date ]:           Wednesday, September 06, 2017 | 
| //-------------------------------------------------------- | 
| using UnityEngine; | 
| using System.Collections; | 
| using UnityEngine.UI; | 
| using System.Collections.Generic; | 
| using UnityEngine.EventSystems; | 
| using System; | 
|   | 
|   | 
| /// <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; | 
|         } | 
|     } | 
| } |