Unity版本 2021.3.25f1c1
首先创建一个碰撞管理器
ColliderNodeManager.cs
具体代码实现如下
using System;
using UnityEngine;
/// <summary>
/// 碰撞检测管理器
/// </summary>
public class ColliderNodeManager : MonoBehaviour
{
public static ColliderNodeManager _Instance;
public static ColliderNodeManager ins
{
get
{
if (_Instance == null)
{
_Instance = FindObjectOfType<ColliderNodeManager>();
if (_Instance == null)
{
GameObject obj = new GameObject("ColliderNodeManager");
_Instance = obj.AddComponent<ColliderNodeManager>();
}
}
return _Instance;
}
}
// 添加碰撞拖拽检测功能的方法
public void AddColliderNodeFunctionality(RectTransform sourceRectTransform, RectTransform targetRectTransform,Action<GameObject,GameObject> callBack)
{
if (sourceRectTransform == null || targetRectTransform == null)
{
Debug.LogError("sourceRectTransform:"+sourceRectTransform+" targetRectTransform :"+targetRectTransform );
return;
}
// 在源 RectTransform 上添加 ColliderNode 组件
ColliderNode sourceColliderNode = sourceRectTransform.gameObject.AddComponent<ColliderNode>();
sourceColliderNode.targetRectTransform = targetRectTransform;
sourceColliderNode.SetCallBack(callBack);
}
}
接下来创建一个碰撞拖拽的具体实现
ColliderNode.cs脚本
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// 拖拽类碰撞检测具体实现
/// </summary>
public class ColliderNode : MonoBehaviour, IPointerDownHandler, IDragHandler, IEndDragHandler
{
// 目标 RectTransform 属性
public RectTransform targetRectTransform { get; set; }
private RectTransform rectTransform; // RectTransform 组件,用于移动位置
private Vector2 originalPosition; // 原始位置
private CanvasScaler canvas;
//是否返回原来的位置
private bool isReturnPos = false;
//碰撞回调
private Action<GameObject, GameObject> m_CallBack;
//设置回调
public void SetCallBack(Action<GameObject, GameObject> callBack)
{
this.m_CallBack = callBack;
}
private void Awake()
{
this.canvas = GameObject.Find("Canvas").GetComponent<CanvasScaler>();
rectTransform = this.gameObject.GetComponent<RectTransform>(); // 获取 RectTransform 组件
}
// 鼠标按下时的回调方法
public void OnPointerDown(PointerEventData eventData)
{
isReturnPos = false;
originalPosition = rectTransform.anchoredPosition; // 记录原始位置
}
// 拖拽时的回调方法
public void OnDrag(PointerEventData eventData)
{
float scaleFactor = canvas.scaleFactor;//获取画布的缩放因子来调整增量值
rectTransform.anchoredPosition += eventData.delta * scaleFactor; // 根据拖拽的增量调整 RectTransform 的位置
}
private void Update()
{
//end 结束之后回到原位置
if (isReturnPos)
{
rectTransform.anchoredPosition = Vector2.MoveTowards(rectTransform.anchoredPosition, this.originalPosition,5);
if(rectTransform.anchoredPosition == this.originalPosition)
{
isReturnPos = false;
}
}
}
// 拖拽结束时的回调方法
public void OnEndDrag(PointerEventData eventData)
{
isReturnPos = true;
if (targetRectTransform != null)
{
Vector2 localPoint;
// 将屏幕坐标转换为目标 RectTransform 的本地坐标
RectTransformUtility.ScreenPointToLocalPointInRectangle(targetRectTransform, eventData.position, null, out localPoint);
Vector2 targetSizeDelta = targetRectTransform.sizeDelta; // 目标 RectTransform 的大小
float minX = -targetSizeDelta.x / 2; // X轴最小值
float maxX = targetSizeDelta.x / 2; // X轴最大值
float minY = -targetSizeDelta.y / 2; // Y轴最小值
float maxY = targetSizeDelta.y / 2; // Y轴最大值
// 判断拖拽结束位置是否在目标 RectTransform 的边界内
if (IsWithinBounds(localPoint, minX, maxX, minY, maxY))
{
this.m_CallBack?.Invoke(this.gameObject, this.targetRectTransform.gameObject);
Debug.Log("拖拽到目标 RectTransform 内");
}
}
}
/// <summary>
/// 判断给定的点是否在指定的边界范围内。
/// 检查点的 x 坐标是否大于最小 x 值(minX),
/// 并且小于最大 x 值(maxX),
/// 同时检查点的 y 坐标是否大于最小 y 值(minY),
/// 并且小于最大 y 值(maxY)。如果点同时满足这四个条件,
/// 则认为它位于边界范围内,并返回 true,否则返回 false。
/// </summary>
/// <param name="point">给定的点</param>
/// <param name="minX">x最小值</param>
/// <param name="maxX">x最大值</param>
/// <param name="minY">y最小值</param>
/// <param name="maxY">y最大值</param>
/// <returns></returns>
private bool IsWithinBounds(Vector2 point, float minX, float maxX, float minY, float maxY)
{
return point.x > minX && point.x < maxX && point.y > minY && point.y < maxY;
}
}
创建一个测试脚本
Test.cs
using UnityEngine;
public class Test : MonoBehaviour
{
public RectTransform sourceRectTransform;
public RectTransform targetRectTransform;
void Start()
{
ColliderNodeManager.ins.AddColliderNodeFunctionality(sourceRectTransform, targetRectTransform, this.ColliderCallBack);
}
void ColliderCallBack(GameObject sourceGameObject,GameObject targetGameObject)
{
Debug.Log("============ 在对方区域内");
}
}
测试结果如下
判断两个物体是否相交可以写入如下方法
// 检查两个 RectTransform 是否相交
private bool CheckIntersection(RectTransform rectTransform1, RectTransform rectTransform2)
{
//获取 RectTransform 的矩形边界
Rect rect1 = rectTransform1.rect;
Rect rect2 = rectTransform2.rect;
// 创建 RectTransform 的矩形对象
Rect rect1Rect = new Rect(rect1.position, rect1.size);
Rect rect2Rect = new Rect(rect2.position, rect2.size);
//使用 Overlaps() 方法判断两个矩形是否相交
return rect1Rect.Overlaps(rect2Rect);
}
将OnEndDrag函数修改为如下即可
// 拖拽结束时的回调方法
public void OnEndDrag(PointerEventData eventData)
{
isReturnPos = true;
if (targetRectTransform != null)
{
// 判断拖拽结束时两个 RectTransform 是否相交
bool isIntersected = CheckIntersection(rectTransform, targetRectTransform);
if (isIntersected)
{
this.m_CallBack?.Invoke(this.gameObject, this.targetRectTransform.gameObject);
Debug.Log("两个 RectTransform 相交");
}
}
}
运行效果如下