yyl
2025-08-29 bb463ef0b13236738a1da9cd04f57def3e7e2c7c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//--------------------------------------------------------
//    [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;
        }
    }
}