【Unity拖拽物体】实现对点中的3D物体进行拖拽的功能

场景结构,两个普通模型

第一种 脚本所挂载的物体才可以被拖拽 【PC鼠标版本】

using UnityEngine;

// 这个脚本实现了,本脚本所在的游戏物体能够被拖拽
public class DragObjectT : MonoBehaviour
{
    private Vector3 screenPoint; // 存储物体在屏幕上的位置
    private Vector3 offset; // 存储鼠标点击位置与物体实际位置的偏移量
    private bool isDragging = false; // 标志位,表示物体是否正在被拖拽

    void Update()
    {
        // 检测鼠标左键是否按下
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // 从摄像机发射一条射线到鼠标位置

            // 使用射线检测是否击中了某个物体
            if (Physics.Raycast(ray, out hit))
            {
                // 检查被击中的物体是否是本脚本所附加的物体
                if (hit.collider.gameObject == gameObject)
                {
                    screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position); // 将物体的世界坐标转换为屏幕坐标
                    offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z)); // 计算偏移量
                    isDragging = true; // 设置拖拽标志位为真
                }
            }
        }

        // 检测鼠标左键是否持续按下并且物体正在被拖拽
        if (Input.GetMouseButton(0) && isDragging)
        {
            Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z); // 获取当前鼠标位置的屏幕坐标
            Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset; // 将屏幕坐标转换为世界坐标并加上偏移量
            transform.position = curPosition; // 更新物体的位置
        }

        // 检测鼠标左键是否释放
        if (Input.GetMouseButtonUp(0))
        {
            isDragging = false; // 设置拖拽标志位为假
        }
    }
}

这个脚本通过检测鼠标输入来实现物体的拖拽功能。以下是详细的步骤解释:

  1. 变量声明

    • screenPoint:存储物体在屏幕上的位置。

    • offset:存储鼠标点击位置与物体实际位置的偏移量。

    • isDragging:标志位,表示物体是否正在被拖拽。

  2. Update方法

    • 检测鼠标左键是否按下(Input.GetMouseButtonDown(0))。

    • 如果按下,从摄像机发射一条射线到鼠标位置(Camera.main.ScreenPointToRay(Input.mousePosition))。

    • 使用射线检测是否击中了某个物体(Physics.Raycast(ray, out hit))。

    • 检查被击中的物体是否是本脚本所附加的物体(hit.collider.gameObject == gameObject)。

    • 如果是,将物体的世界坐标转换为屏幕坐标(Camera.main.WorldToScreenPoint(gameObject.transform.position)),并计算偏移量(offset)。

    • 设置拖拽标志位为真(isDragging = true)。

  3. 拖拽逻辑

    • 检测鼠标左键是否持续按下并且物体正在被拖拽(Input.GetMouseButton(0) && isDragging)。

    • 获取当前鼠标位置的屏幕坐标(curScreenPoint)。

    • 将屏幕坐标转换为世界坐标并加上偏移量(curPosition)。

    • 更新物体的位置(transform.position = curPosition)。

  4. 释放逻辑

    • 检测鼠标左键是否释放(Input.GetMouseButtonUp(0))。

    • 设置拖拽标志位为假(isDragging = false)。

 

以下是适用于移动端触摸屏的版本:

using UnityEngine;

// 这个脚本实现了,本脚本所在的游戏物体能够被触摸拖拽
public class DragObjectT : MonoBehaviour
{
    private Vector3 screenPoint; // 存储物体在屏幕上的位置
    private Vector3 offset; // 存储触摸点击位置与物体实际位置的偏移量
    private bool isDragging = false; // 标志位,表示物体是否正在被拖拽

    void Update()
    {
        // 检测是否有触摸输入
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0); // 获取第一个触摸点

            // 检测触摸开始
            if (touch.phase == TouchPhase.Began)
            {
                RaycastHit hit;
                Ray ray = Camera.main.ScreenPointToRay(touch.position); // 从摄像机发射一条射线到触摸位置

                // 使用射线检测是否击中了某个物体
                if (Physics.Raycast(ray, out hit))
                {
                    // 检查被击中的物体是否是本脚本所附加的物体
                    if (hit.collider.gameObject == gameObject)
                    {
                        screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position); // 将物体的世界坐标转换为屏幕坐标
                        offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, screenPoint.z)); // 计算偏移量
                        isDragging = true; // 设置拖拽标志位为真
                    }
                }
            }

            // 检测触摸移动并且物体正在被拖拽
            if (touch.phase == TouchPhase.Moved && isDragging)
            {
                Vector3 curScreenPoint = new Vector3(touch.position.x, touch.position.y, screenPoint.z); // 获取当前触摸位置的屏幕坐标
                Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset; // 将屏幕坐标转换为世界坐标并加上偏移量
                transform.position = curPosition; // 更新物体的位置
            }

            // 检测触摸结束
            if (touch.phase == TouchPhase.Ended)
            {
                isDragging = false; // 设置拖拽标志位为假
            }
        }
    }
}

这个脚本通过检测触摸输入来实现物体的拖拽功能。以下是详细的步骤解释:

  1. 变量声明

    • screenPoint:存储物体在屏幕上的位置。

    • offset:存储触摸点击位置与物体实际位置的偏移量。

    • isDragging:标志位,表示物体是否正在被拖拽。

  2. Update方法

    • 检测是否有触摸输入(Input.touchCount > 0)。

    • 获取第一个触摸点(Touch touch = Input.GetTouch(0))。

    • 检测触摸开始(touch.phase == TouchPhase.Began)。

    • 如果触摸开始,从摄像机发射一条射线到触摸位置(Camera.main.ScreenPointToRay(touch.position))。

    • 使用射线检测是否击中了某个物体(Physics.Raycast(ray, out hit))。

    • 检查被击中的物体是否是本脚本所附加的物体(hit.collider.gameObject == gameObject)。

    • 如果是,将物体的世界坐标转换为屏幕坐标(Camera.main.WorldToScreenPoint(gameObject.transform.position)),并计算偏移量(offset)。

    • 设置拖拽标志位为真(isDragging = true)。

  3. 拖拽逻辑

    • 检测触摸移动并且物体正在被拖拽(touch.phase == TouchPhase.Moved && isDragging)。

    • 获取当前触摸位置的屏幕坐标(curScreenPoint)。

    • 将屏幕坐标转换为世界坐标并加上偏移量(curPosition)。

    • 更新物体的位置(transform.position = curPosition)。

  4. 释放逻辑

    • 检测触摸结束(touch.phase == TouchPhase.Ended)。

    • 设置拖拽标志位为假(isDragging = false)。

第二种 全局脚本,所有有碰撞器的物体都可以被拖拽

using UnityEngine;

public class GlobalDragManager : MonoBehaviour
{
    private GameObject draggedObject;
    private Vector3 screenPoint;
    private Vector3 offset;

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(ray, out hit))
            {
                draggedObject = hit.collider.gameObject;
                screenPoint = Camera.main.WorldToScreenPoint(draggedObject.transform.position);
                offset = draggedObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
            }
        }

        if (Input.GetMouseButton(0) && draggedObject != null)
        {
            Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
            Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
            draggedObject.transform.position = curPosition;
        }

        if (Input.GetMouseButtonUp(0))
        {
            draggedObject = null;
        }
    }
}

 

这个脚本的工作原理如下:

  1. Update方法

    • 在每一帧中,检查是否按下了鼠标左键(Input.GetMouseButtonDown(0))。

    • 如果按下了鼠标左键,发射一条从主摄像机到鼠标位置的射线(Physics.Raycast(ray, out hit))。

    • 如果射线击中了某个物体(hit.collider.gameObject),则将该物体的引用存储在draggedObject变量中,并记录物体的屏幕位置和偏移量。

  2. 拖动逻辑

    • 如果鼠标左键保持按下并且draggedObject不为空,根据当前鼠标位置计算物体的新位置(curPosition),并将其应用到物体的变换位置上(draggedObject.transform.position = curPosition)。

  3. 释放物体

    • 当鼠标左键释放时(Input.GetMouseButtonUp(0)),将draggedObject设置为null,表示没有物体正在被拖动。

通过这种方式,你只需要挂载一个脚本到场景中的某个空游戏对象上,就可以实现对所有带有碰撞器的物体的拖拽功能,而不需要为每个物体单独挂载脚本。

适用于移动端触摸屏交互的版本

using UnityEngine;

public class GlobalDragManager : MonoBehaviour
{
    private GameObject draggedObject;
    private Vector3 screenPoint;
    private Vector3 offset;

    void Update()
    {
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {
                RaycastHit hit;
                Ray ray = Camera.main.ScreenPointToRay(touch.position);

                if (Physics.Raycast(ray, out hit))
                {
                    draggedObject = hit.collider.gameObject;
                    screenPoint = Camera.main.WorldToScreenPoint(draggedObject.transform.position);
                    offset = draggedObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, screenPoint.z));
                }
            }

            if (touch.phase == TouchPhase.Moved && draggedObject != null)
            {
                Vector3 curScreenPoint = new Vector3(touch.position.x, touch.position.y, screenPoint.z);
                Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint) + offset;
                draggedObject.transform.position = curPosition;
            }

            if (touch.phase == TouchPhase.Ended)
            {
                draggedObject = null;
            }
        }
    }
}

这个脚本的工作原理如下:

  1. Update方法

    • 在每一帧中,检查是否有触摸输入(Input.touchCount > 0)。

    • 如果有触摸输入,获取第一个触摸点(Touch touch = Input.GetTouch(0))。

  2. 触摸开始

    • 如果触摸开始(touch.phase == TouchPhase.Began),发射一条从主摄像机到触摸位置的射线(Physics.Raycast(ray, out hit))。

    • 如果射线击中了某个物体(hit.collider.gameObject),则将该物体的引用存储在draggedObject变量中,并记录物体的屏幕位置和偏移量。

  3. 触摸移动

    • 如果触摸移动(touch.phase == TouchPhase.Moved)并且draggedObject不为空,根据当前触摸位置计算物体的新位置(curPosition),并将其应用到物体的变换位置上(draggedObject.transform.position = curPosition)。

  4. 触摸结束

    • 当触摸结束(touch.phase == TouchPhase.Ended),将draggedObject设置为null,表示没有物体正在被拖动。

通过这种方式,你可以在移动端触摸屏上实现对所有带有碰撞器的物体的拖拽功能,而不需要为每个物体单独挂载脚本。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Seata】Seata——分布式事务框架(理论篇)

目录 解释Seata的三大角色Seata的分布式事务解决方案:AT 模式整体机制一阶段二阶段 完整图例 XA模式DTP模型Seata的XA模式Seata-XA的价值小结XA协议的问题 TCC模式解释Seata的TCC模式Seata-TCC特点 Saga模式Saga的价值Saga状态机基本原理Saga状态机设计器 四种模式的…

JavaFX 下拉框

组合框允许用户选择几个选项之一。用户可以滚动到下拉列表。组合框可以是可编辑和不可编辑的。 创建组合框 以下代码将选项列表包装到ObservableList中&#xff0c;然后使用observable列表实例化ComboBox类。 ObservableList<String> options FXCollections.observab…

情系端午,爱暖精诚 | 我院开展温情献礼端午慰问活动

端午佳节将至&#xff0c;为感谢全体员工在医院发展中的无私奉献和辛勤努力&#xff0c;传递对大家的深情关怀&#xff0c;提升员工的归属感与凝聚力。6月6日&#xff0c;医院特别为全体员工精心准备了节日福利&#xff0c;为每位员工送上饱含爱意的节日礼品。 一盒盒满载心意的…

【Docker实战】jenkins卡在编译Dockerfile的问题

我们的项目是标准的CI/CD流程&#xff0c;也即是GitlabJenkinsHarborDocker的容器自动化部署。 经历了上上周的docker灾难&#xff0c;上周的服务器磁盘空间灾难&#xff0c;这次又发生了jenkins卡住的灾难。 当然&#xff0c;这些灾难有一定的连锁反应&#xff0c;是先发生的d…

vue3-父子通信

一个简单的vue3子组件调用父组件方法的demo <template> <div> <h2>Parent Component父组件</h2> <ChildComponent notify-parent"handleParentMethod" /> </div> </template> <script> import { ref } fr…

hugging face:大模型时代的github介绍

1. Hugging Face是什么&#xff1a; Hugging Face大模型时代的“github”&#xff0c;很多人有个这样的认知&#xff0c;但是我觉得不完全准确&#xff0c;他们相似的地方在于资源丰富&#xff0c;github有各种各样的软件代码和示例&#xff0c;但是它不是系统的&#xff0c;没…

HTML5基本语法

文章目录 HTML5基本语法一、基础标签1、分级标题2、段标签3、换行及水平线标签4、文本格式标签 二、图片标签1、格式2、属性介绍 三、音频标签1、格式2、属性介绍 四、视频标签1、格式2、属性介绍 五、链接标签1、格式2、显示特点3、属性介绍4、补充&#xff08;空链接&#xf…

计算机毕业设计Python+Flask弹幕情感分析 B站视频数据可视化 B站爬虫 机器学习 深度学习 人工智能 NLP文本分类 数据可视化 大数据毕业设计

首先安装需要的python库&#xff0c; 安装完之后利用navicat导入数据库文件bili100.sql到mysql中&#xff0c; 再在pycharm编译器中连接mysql数据库&#xff0c;并在设置文件中将密码修改成你的数据库密码。最后运行app.py&#xff0c;打开链接&#xff0c;即可运行。 B站爬虫数…

【博士每天一篇文献-算法】Memory aware synapses_ Learning what (not) to forget

阅读时间&#xff1a;2023-12-13 1 介绍 年份&#xff1a;2018 作者&#xff1a;Rahaf Aljundi,丰田汽车欧洲公司研究员;阿卜杜拉国王科技大学(KAUST)助理教授;Marcus Rohrbach德国达姆施塔特工业大学多模式可靠人工智能教授 会议&#xff1a; Proceedings of the European c…

物联网协议应用

目录 前言一、WIFI简介二、NTP协议2.1 NTP简介2.2 NTP实现 三、HTTP协议3.1 HTTP协议简介3.2 HTTP服务器 四、MQTT协议4.1 MQTT协议简介4.1.1 MQTT通信模型4.1.2 MQTT协议实现原理4.1.3 MQTT 控制报文 4.2 移植MQTT协议 前言 本文主要介绍一下物联网协议如NTP协议、HTTP协议和M…

Redis 内存策略

一、Redis 内存回收 Redis 之所以性能强&#xff0c;最主要的原因就是基于内存存储。然而单节点的 Redis 其内存大小不宜过大&#xff0c;会影响持久化或主从同步性能。 我们可以通过修改配置文件来设置 Redis 的最大内存&#xff1a; # 格式&#xff1a; # maxmemory <byt…

高等数学笔记(二):极限

一、数列极限的定义 以下符号表示 “对于任意给定的” 以下符号表示 “存在” 以下符号表示 “如果什么&#xff08;箭头左&#xff09;&#xff0c;则什么&#xff08;箭头右&#xff09;” 二、收敛数列的性质 2.1 唯一性 2.2 有界性 2.3 保号性 2.4 子数列收敛性 三、函数…

无痛接入图像生成风格迁移能力:GAN生成对抗网络

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

网络安全:探索云安全的最佳实践

文章目录 网络安全&#xff1a;探索云安全的最佳实践引言云安全简介云安全面临的挑战云安全的最佳实践数据加密身份和访问管理定期安全审计 结语 网络安全&#xff1a;探索云安全的最佳实践 引言 在我们之前的文章中&#xff0c;我们讨论了网络安全的多个方面&#xff0c;包括…

卫生间毫米波雷达跌倒检测,飞睿智能人体存在感应器,智能识别老人跌倒守护安全

在智能家居飞速发展的今天&#xff0c;雷达技术已经悄然走进了我们的生活&#xff0c;尤其在卫生间这样的特殊场景中&#xff0c;毫米波雷达人体存在感应器和跌倒检测技术的应用&#xff0c;通过及时识别老年人跌倒等意外情况&#xff0c;及时发送警报信息&#xff0c;不仅为我…

数学建模基础:线性模型

目录 前言 一、线性方程组 二、线性规划 三、线性回归 四、线性模型的应用 五、实例示范&#xff1a;医疗成本预测 步骤 1&#xff1a;导入数据 步骤 2&#xff1a;数据预处理 步骤 3&#xff1a;建立多元线性回归模型 步骤 4&#xff1a;模型验证 步骤 5&#xff1…

数据库物理计划执行指南

一、背景介绍 伴随信息技术地迅猛发展和应用范围地逐步扩大&#xff0c;数据库已成为企业存储与管理数据的重要工具。但数据量激增以及用户访问需求的与日剧增&#xff0c;数据库性能也将面临巨大挑战。 好在数据库物理计划执行是解决数据库性能问题的重要手段之一&#xff0…

【机器学习】第11章 神经网络与深度学习(重中之重)

一、概念 1.神经元模型 &#xff08;1&#xff09;神经网络的基本组成单位 &#xff08;2&#xff09;生物上&#xff0c;每个神经元通过树突接受来自其他被激活神经元的信息&#xff0c;通过轴突释放出来的化学递质改变当前神经元内的电位。当神经元内的电位累计到一个水平时…

基础购物车(Javascript)

使用Javascript写一个基础购物车&#xff0c;其中包含商品数量加加减减&#xff0c;下面的总价和总数量跟着商品数量变动&#xff0c;还可以自己添加需要的商品。 基础购物车的结构样式如下&#xff1a; HTML代码&#xff1a; <body><table border"1px" c…

百度智能云推出智能运维工具,云助手让云服务器运维更简单

为了提升云服务器执行命令的效率&#xff0c;百度智能云发布了 SmartTerm 远程连接终端。不止于此&#xff0c;为了更加极致地提升运维效率&#xff0c;我们又推出了「云助手」这款轻量快捷的运维工具。 ​ 只有做过云服务器运维的人才知道管理上万台云服务器有多崩溃。在海量…