123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Events;
- using UnityEngine.EventSystems;
- namespace MinorFunction
- {
- public enum DragHandleMode
- {
- Free, // 自由拖拽
- WithinScreen, // 在屏幕内拖拽
- WithinParent, // 在父对象内拖拽
- }
- [RequireComponent(typeof(CanvasGroup))]
- public class DragHandle : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
- {
- public DragHandleMode dragMode = DragHandleMode.Free;
- // 是否偏移
- public bool isOffset = true;
- // 是否位置重叠判定
- public bool isOverlap = true;
- // 拖动置顶层级
- public bool isDragTop = false;
- // 偏移向量
- private Vector2 offset = Vector2.zero;
- public UnityEvent onBeginDrag;// 开始拖动
- public UnityEvent onDrag;// 拖动
- public UnityEvent onEndDrag; // 拖动结束
- [HideInInspector]
- public SlotHandle currentSlotHandle;
- public SlotHandle[] slotHandles;
- public void OnBeginDrag(PointerEventData eventData)
- {
- slotHandles = Object.FindObjectsOfType<SlotHandle>();
- offset = eventData.position - (Vector2)transform.position;
- gameObject.GetComponent<CanvasGroup>().blocksRaycasts = false;
- if (isDragTop)
- {
- transform.SetAsLastSibling();
- }
- onBeginDrag?.Invoke();
- }
- public void OnDrag(PointerEventData eventData)
- {
- switch (dragMode)
- {
- case DragHandleMode.Free:
- SetFreeDrag(eventData);
- break;
- case DragHandleMode.WithinScreen:
- SetDragWithinScreen(eventData);
- break;
- case DragHandleMode.WithinParent:
- SetDragWithinParent(eventData);
- break;
- }
- onDrag?.Invoke();
- }
- public void OnEndDrag(PointerEventData eventData)
- {
- gameObject.GetComponent<CanvasGroup>().blocksRaycasts = true;
- if (isOverlap)
- {
- bool overlap = false;
- int overlapIndex = 0;
- for (int i = 0; i < slotHandles.Length; i++)
- {
- if (IsRectanglesOverlapping(GetComponent<RectTransform>(), slotHandles[i].GetComponent<RectTransform>()))
- {
- overlap = true;
- overlapIndex = i;
- break;
- }
- }
- if (overlap)
- {
- //Debug.Log($"{gameObject.name} 有重叠 {slotHandles[overlapIndex].gameObject.name}");
- slotHandles[overlapIndex].ModifyDrag(this);
- }
- else
- {
- if (currentSlotHandle)
- {
- RemoveSlotHandle();
- currentSlotHandle = null;
- }
- //Debug.Log("无任何重叠");
- }
- }
- else
- {
- if (currentSlotHandle)
- {
- if (!currentSlotHandle.isEnter)
- {
- RemoveSlotHandle();
- currentSlotHandle = null;
- }
- }
- }
- onEndDrag?.Invoke();
- }
- /// <summary>
- /// 移除SlotHandle
- /// </summary>
- public void RemoveSlotHandle()
- {
- currentSlotHandle.onDragExit?.Invoke(this);
- currentSlotHandle.currentDragHandles.Remove(this);
- currentSlotHandle = null;
- }
- #region 拖动模式
- // 自由拖动
- public void SetFreeDrag(PointerEventData eventData)
- {
- if (isOffset)
- {
- transform.position = eventData.position - offset;
- }
- else
- {
- transform.position = eventData.position;
- }
- }
- // 设置屏幕内拖动
- public void SetDragWithinScreen(PointerEventData eventData)
- {
- RectTransform rectTransform = transform as RectTransform;
- Vector2 pos = Vector2.zero;
- if (isOffset)
- {
- pos = eventData.position - offset;
- }
- else
- {
- pos = eventData.position;
- }
- // 屏幕范围
- float parentMinX = 0;
- float parentMinY = 0;
- float parentMaxX = Screen.width;
- float parentMaxY = Screen.height;
- var pivotDistance = GetPivotDistance(rectTransform);
- float pivotMinX = pivotDistance.pivotMinX;
- float pivotMinY = pivotDistance.pivotMinY;
- float pivotMaxX = pivotDistance.pivotMaxX;
- float pivotMaxY = pivotDistance.pivotMaxY;
- // 限制范围
- float minX = parentMinX + pivotMinX;
- float minY = parentMinY + pivotMinY;
- float maxX = parentMaxX - pivotMaxX;
- float maxY = parentMaxY - pivotMaxY;
- // 限制拖动范围
- pos.x = Mathf.Clamp(pos.x, minX, maxX);
- pos.y = Mathf.Clamp(pos.y, minY, maxY);
- transform.position = pos;
- }
- // 限制矩形内拖动
- public void SetDragWithinParent(PointerEventData eventData)
- {
- RectTransform rectTransform = transform as RectTransform;
- RectTransform parentRectTransform = transform.parent as RectTransform;
- Vector2 pos = Vector2.zero;
- if (isOffset)
- {
- pos = eventData.position - offset;
- }
- else
- {
- pos = eventData.position;
- }
- var parentMinMax = GetMinMax(parentRectTransform);
- float parentMinX = parentMinMax.minX;
- float parentMinY = parentMinMax.minY;
- float parentMaxX = parentMinMax.maxX;
- float parentMaxY = parentMinMax.maxY;
- var pivotDistance = GetPivotDistance(rectTransform);
- float pivotMinX = pivotDistance.pivotMinX;
- float pivotMinY = pivotDistance.pivotMinY;
- float pivotMaxX = pivotDistance.pivotMaxX;
- float pivotMaxY = pivotDistance.pivotMaxY;
- // 限制范围
- float minX = parentMinX + pivotMinX;
- float minY = parentMinY + pivotMinY;
- float maxX = parentMaxX - pivotMaxX;
- float maxY = parentMaxY - pivotMaxY;
- // 限制拖动范围
- pos.x = Mathf.Clamp(pos.x, minX, maxX);
- pos.y = Mathf.Clamp(pos.y, minY, maxY);
- transform.position = pos;
- }
- #endregion
- #region 功能
- // 计算物体中心点到四条边的距离
- public (float pivotMinX, float pivotMinY, float pivotMaxX, float pivotMaxY) GetPivotDistance(RectTransform rectTransform)
- {
- float width = rectTransform.rect.width;
- float height = rectTransform.rect.height;
- // 注:这里一定要使用全局坐标,不然计算会受到父物体缩放的影响
- float scaleX = rectTransform.lossyScale.x;
- float scaleY = rectTransform.lossyScale.y;
- Vector2 pivot = rectTransform.pivot;
- float pivotMinX = width * pivot.x * scaleX;
- float pivotMinY = height * pivot.y * scaleY;
- float pivotMaxX = width * (1 - pivot.x) * scaleX;
- float pivotMaxY = height * (1 - pivot.y) * scaleY;
- return (pivotMinX, pivotMinY, pivotMaxX, pivotMaxY);
- }
- // 计算物体X,Y最大值最小值
- public (float minX, float minY, float maxX, float maxY) GetMinMax(RectTransform rectTransform)
- {
- float parentX = rectTransform.position.x;
- float parentY = rectTransform.position.y;
- var pivotDistance = GetPivotDistance(rectTransform);
- float pivotMinX = pivotDistance.pivotMinX;
- float pivotMinY = pivotDistance.pivotMinY;
- float pivotMaxX = pivotDistance.pivotMaxX;
- float pivotMaxY = pivotDistance.pivotMaxY;
- float minX = parentX - pivotMinX;
- float minY = parentY - pivotMinY;
- float maxX = parentX + pivotMaxX;
- float maxY = parentY + pivotMaxY;
- return (minX, minY, maxX, maxY);
- }
- public bool IsRectanglesOverlapping(RectTransform rect1, RectTransform rect2)
- {
- Vector2 rect1Min = rect1.anchoredPosition - (rect1.sizeDelta * rect1.pivot) * rect1.lossyScale;
- Vector2 rect1Max = rect1.anchoredPosition + (rect1.sizeDelta * (Vector2.one - rect1.pivot)) * rect1.lossyScale;
- Vector2 rect2Min = rect2.anchoredPosition - (rect2.sizeDelta * rect2.pivot) * rect2.lossyScale;
- Vector2 rect2Max = rect2.anchoredPosition + (rect2.sizeDelta * (Vector2.one - rect2.pivot)) * rect2.lossyScale;
- // 判断矩形 1 的最右边小于矩形 2 的最左边,或者矩形 2 的最右边小于矩形 1 的最左边,说明没有水平方向重叠
- if (rect1Max.x < rect2Min.x || rect2Max.x < rect1Min.x || rect1Max.y < rect2Min.y || rect2Max.y < rect1Min.y)
- {
- return false;
- }
- return true;
- }
- #endregion
- }
- }
|