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