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

news2024/11/17 1:42:21

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

 运行效果如下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/696389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt错误: warning: ignoring old recipe for target ‘childwnd.o‘.

Qt中这样的错误 &#xff1a; 错误原因 &#xff1a; 工程文件, 也就是 *.pro文件, 其中的源文件*.cpp, 头文件*.h, ui文件*.ui以及资源文件*.qrc 重复了, 删掉就好. *.pro文件就是这玩意 &#xff1a; *.pro文件中的文件重复&#xff1a; 如果还是出现这样的错误警告&#…

Flutter中的Alignment是怎么回事?

我们知道Flutter中的Container有个alignment的属性&#xff0c;我们可以设置一些topLeft,center之类的位置名字的值&#xff0c;也可以设置Alignment(x,y)这种具体数值的值。那么Align子widget的位置跟x、y是什么关系呢&#xff1f;以水平方向为例&#xff0c;我们知道x-1表示子…

vs+qt 给打包程序添加图标

1、在创建的qt工程文件中添加如下代码&#xff1a; this->setWindowIcon(QIcon(":/new/prefix1/ico"));//设置软件图标 this->setWindowTitle("XXX软件名 ");//设置软件标题 运行后软件的左上角会有图标 2、让编译成的exe带图标 生成…

dup、dup2、F_DUPFD、dup3、F_DUPFD_CLOEXEC:实例

本实例将输出和错误输出&#xff0c;重定向到文件outlog.txt文件。 dup实现 测试代码&#xff1a; #include <sys/types.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h>…

基于win10环境搭建图片服务器的两种方式

简述 这几天接到一种需求&#xff0c;需要在window环境搭建图片服务&#xff0c;去网上搜一下&#xff0c;最终想出两种方式一种是Nginx方式 &#xff0c;一种是公司常用的iis服务方式&#xff0c;最终使用iis方式&#xff0c;这里简单记录一下。 Nginx nginx方式很简单&#…

机器学习模型优化器Adam报错:ValueError: decay is deprecated in the new Keras optimizer

文章目录 深度学习模型优化器报错&#xff1a;报错原因&#xff1a; 解决方案&#xff1a; 深度学习模型优化器报错&#xff1a; ValueError: decay is deprecated in the new Keras optimizer, pleasecheck the docstring for valid arguments, or use the legacy optimizer,…

5G已难拉动收入增长,运营商对于高投入的5G左右为难

随着三大运营商的5G用户数突破10亿&#xff0c;5G已很难拉动ARPU的增长了&#xff0c;表现出来的业绩就是增长快速放缓&#xff0c;工信部披露的数据显示移动数据业务收入增长已接近于零。 工信部发布了“2023年1&#xff0d;5月份通信业经济运行情况”显示三大运营商的移动数据…

Java(六):Eureka项目搭建、数据请求

Eureka项目搭建、数据请求 Eureka简介Eureka项目创建1、新建Maven项目2、只保留Maven项目的依赖文件3、创建子模块&#xff08;Eureka服务模块&#xff09;4、修改pom.xml5、创建并修改配置文件6、添加Eureka注解7、运行8、创建其他服务9、修改pom.xml10、创建并修改配置文件11…

Mac网络扫描工具iNet Network Scanner

iNet Network Scanner是一款适用于 macOS 系统的网络扫描工具&#xff0c;可以帮助用户快速识别和监控局域网中连接的设备和服务。该软件提供了直观的界面和丰富的功能&#xff0c;支持多种网络协议和扫描选项&#xff0c;并具有高度的可定制性和灵活性。 iNet Network Scanner…

javaee 任务调度 定时任务 schedule

任务调度可以实现指定的时间执行某个任务&#xff0c;比如每一分钟执行一次&#xff0c;指定时间执行一次。 MyTimeTask package com.yyy.schedule;import java.text.SimpleDateFormat; import java.util.TimerTask;public class MyTimeTask extends TimerTask {//重写run方法…

Springboot上传图片和回显示图片

本次演示的是直接使用Springboot上传到服务器而不是七牛云等oss,springboot对于前端传输的文件数据类型格式的封装为MultipartFile,前端上传的图片是被存在服务端的缓存区的,当controller处理的时候,缓存区就被清空,所以需要转存,使用transferTo Api 前端采用elementui 直接上传…

开源之夏2023中选结果公示,504名高校生将投入开源项目贡献

中国科学院软件研究所与openEuler社区联合主办的开源之夏活动项目申请阶段告一段落&#xff0c;中选学生名单已公布。前往官网项目列表即可查看项目中选情况https://summer-ospp.ac.cn/org/projectlist开源之夏今年已进行至第四届&#xff0c;成为每年暑期前最受高校开发者关注…

SAP从入门到放弃系列之订单创建-概念-Part1

目录导航 概述订单创建一、通过计划订单创建生产订单1.1、计划订单转为生产订单-part11.2、计划订单转为生产订单-part2操作方式&#xff1a; 二、通过物料或者复制方式创建三、创建无物料的订单四、通过销售订单创建生产订单五、通过项目创建销售订单 概述 根据不同的需求&am…

【深度学习】深入理解Batch Normalization批标准化

机器学习领域有个很重要的假设&#xff1a;独立同分布假设&#xff08;IID&#xff09;&#xff0c;就是假设训练数据和测试数据是满足相同分布的&#xff0c;这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。那BatchNorm的作用是什么呢&#xff1f;BatchN…

[游戏开发][Unity]出包真机运行花屏(已解决)

花屏真机截屏 原因 原因是启动项目时的第一个场景没有相机是 Skybox或者SolidColor模式&#xff0c;我的启动场景只有一个UI相机&#xff0c;且Clear Flags是DepthOnly 解释&#xff1a; https://blog.csdn.net/yanchezuo/article/details/79002318

【数据库】MySQL主从同步失败或重启后需要重新配置同步,主从同步延迟解决方案,mysql主从同步加速

最近在学习MySQL&#xff0c;主从同步方案。由于是新手&#xff0c;如有出现错误的地方&#xff0c;请大家谅解并留言指正。MySQL不同的版本配置稍有不同&#xff0c;最新版本8.0.27是默认开启binarylog的&#xff0c;见下图 查询MySQL信息 SELECT version,NOW() ;show variabl…

【Zookeeper】win安装随笔

目录 下载地址下载目标解压后目录结构配置文件配置文件详情伪分布式安装LinuxZooKeeper audit is disabled启动解决报错&#xff1a;SLF4J: Class path contains multiple SLF4J bindings. _ 下载地址 https://zookeeper.apache.org/releases.html 下载目标 记住选择带bin的…

《操作系统》by李治军 | 实验8 - 终端设备的控制

目录 一、实验目的 二、实验内容 三、实验准备 1. 键盘输入处理过程 2. 输出字符的控制 四、实验过程 1. 添加 F12 键盘功能处理 2. 添加 * 字符的显示处理 3. 重新编译内核 4. 运行 Linux 0.11 五、实验报告 一、实验目的 1、加深对操作系统设备管理基本原理…

mac docker desktop 无法docker login

mac docker desktop 无法docker login &#xff0c;报错 Error saving credentials: error storing credentials - err: exit status 1, out: Post "http://ipc/registry/credstore-updated": context deadline exceeded (Client.Timeout exceeded while awaiting h…

pytorch快速入门中文——01

PyTorch 深度学习&#xff1a;60分钟快速入门 原文&#xff1a;https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html 作者&#xff1a; Soumith Chintala https://www.youtube.com/embed/u7x8RXwLKcA 什么是 PyTorch&#xff1f; PyTorch 是基于以下两个…