//-------------------------------------------------------- 
 | 
//    [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; 
 | 
        } 
 | 
    } 
 | 
} 
 |