hch
2025-10-17 cb653cf75b17b9bdca0b5b9e6b88edf1ca72e90c
Main/Component/UI/Common/BoundedDrag.cs
@@ -1,5 +1,5 @@
//--------------------------------------------------------
//    [Author]:           第二世界
//    [Author]:           玩个游戏
//    [  Date ]:           Wednesday, September 06, 2017
//--------------------------------------------------------
using UnityEngine;
@@ -10,241 +10,270 @@
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;
        }
    }
}