//-------------------------------------------------------- // [Author]: 玩个游戏 // [ Date ]: Wednesday, September 06, 2017 //-------------------------------------------------------- using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; using UnityEngine.EventSystems; 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; // 双指缩放的上一帧触摸位置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; // 初始化位置 } /// /// 拖拽开始事件处理 /// 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; } } }