Unity UGUI 实现一个拖拽一个物体到另一个物体上 并返回两个物体是否相交或者是否在对方物体的中心点

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 相交");
            }
        }
    }

 运行效果如下

猜你喜欢

转载自blog.csdn.net/qq_41973169/article/details/131381816