【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.rhkb.cn/news/360319.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker基础使用教程

1.准备工作 例子:工程在docker_test 生成requirements.txt文件命令:(使用参考链接2) pip list --formatfreeze > requirements.txt 参考链接1: 安装pipreqs可能比较困难 python 项目自动生成环境配置文件require…

【C语言】解决C语言报错:Invalid Pointer

文章目录 简介什么是Invalid PointerInvalid Pointer的常见原因如何检测和调试Invalid Pointer解决Invalid Pointer的最佳实践详细实例解析示例1:未初始化的指针示例2:已释放的指针示例3:返回局部变量的指针示例4:野指针 进一步阅…

5个wordpress成品站主题

Sora索啦高端制造业wordpress主题 红色高端制造业wordpress主题,适合外贸企业出海建独立站的wordpress模板。 https://www.jianzhanpress.com/?p5885 Polar钋啦wordpress外贸主题 制造业wordpress网站模板,适合生产制造企业官方网站使用的wordpress外…

汉语翻译藏语软件,这几款软件不妨一试!

在全球化日益加深的今天,语言障碍成为了许多人在文化交流、商务洽谈或旅游探险中不得不面对的问题。特别是对于汉语和藏语这两种语言来说,由于其独特的文化背景和语法结构,翻译起来更是难上加难。不过,好在科技的进步为我们带来了…

Intelij IDEA中Mapper.xml无法构建到资源目录的问题

问题场景: 在尝试把原本在eclipse上的Java Web项目转移至Intelij idea上时,在配置文件均与eclipse一致的情况下出现了如下报错: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.umbrella.crm_core.…

图书管理系统(详解版 附源码)

目录 项目分析 实现页面 功能描述 页面预览 准备工作 数据准备 创建数据库 用户表 创建项目 导入前端页面 测试前端页面 后端代码实现 项目公共模块 实体类 公共层 统一结果返回 统一异常处理 业务实现 持久层 用户登录 用户注册 密码加密验证 添加图书…

Mac 安装HomeBrew(亲测成功)

1、终端安装命令: /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"执行后,没有安装git,会先安装,安装后再执行一下命令。 2、根据中文选择源安装 3、相关命令 查看版本号&a…

本地服务怎么发布成rpc服务

目录 1.引入 2.user.proto 3.userservice.cc 1.引入 example文件夹作为我们框架项目的使用实例,在example文件夹下创建callee和caller两个文件夹 callee是RPC服务的提供者。在callee创建一个文件:userservice.cc 我们有没有这样一个框架,把…

【面试题】MySQL数据库

目录 什么是视图,视图的作用是什么?什么是索引?MySQL中有哪些类型的索引?简述索引设计原则?简述索引的数据结构?简述Hash 和 B 树索引的区别?列出MySQL中导致索引失效的情况?简述数据…

mysql窗口函数排名查询 与 连续出现的数字查询

排名查询 学会这一个查询,我们应该对该类型的查询 方法就能有一个了解,不然 如果下次遇到该类型的查询,我们依然分析不出 给你一张表,里面有id 和score字段,根据score的分数大小 排序 ,假如有相同的分数&…

【山东】2024年夏季高考文化成绩一分一段表

文末有图片版,可直接保存下载!! 2024年夏季高考文化成绩一分一段表分数段全体-选考物理-选考化学-选考生物-选考思想政治-选考历史-选考地理分数段本段人数累计人数本段人数累计人数本段人数累计人数本段人数累计人数本段人数累计人数本段人…

Upload-Labs-Linux1 使用 一句话木马

解题步骤&#xff1a; 1.新建一个php文件&#xff0c;编写内容&#xff1a; <?php eval($_REQUEST[123]) ?> 2.将编写好的php文件上传&#xff0c;但是发现被阻止&#xff0c;网站只能上传图片文件。 3.解决方法&#xff1a; 将php文件改为图片文件&#xff08;例…

毕业生离校系统

摘 要 随着信息技术的快速发展和普及&#xff0c;越来越多的高校开始利用信息化手段来提升管理和服务效率。毕业生离校是高校管理工作中的一个重要环节&#xff0c;涉及到毕业生的个人信息、学业成绩、离校手续等多个方面。传统的离校流程往往繁琐、耗时&#xff0c;且容易出现…

Apple - Framework Programming Guide

本文翻译自&#xff1a;Framework Programming Guide&#xff08;更新日期&#xff1a;2013-09-17 https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Frameworks.html#//apple_ref/doc/uid/10000183i 文章目录 一、框架编程指南简介…

永洪bi里topN的设置/用法

要实现的效果&#xff1a;实现通过输入参数&#xff0c;进行图表top的排序筛选 图示&#xff1a; 筛选前&#xff1a; 输入3&#xff0c;看top3的值&#xff1a; 输入-3&#xff0c;看倒数3个的值&#xff1a; 设置步骤&#xff1a; 1️⃣&#xff1a;添加一个“文本参数组件…

打造智能家居:用ESP32轻松实现无线控制与环境监测

ESP32是一款集成了Wi-Fi和蓝牙功能的微控制器&#xff0c;广泛应用于物联网项目。它由Espressif Systems公司开发&#xff0c;具有强大的处理能力和丰富的外设接口。下面我们将详细介绍ESP32的基础功能和引脚功能&#xff0c;并通过具体的实例项目展示其应用。 主要功能 双核处…

找不到mfc140u.dll怎么修复,mfc140u.dll丢失的多种修复方法

计算机丢失mfc140u.dll文件会导致依赖该文件的软件无法正常运行。mfc140u.dll是Microsoft Visual C 2015的可再发行组件之一&#xff0c;它属于Microsoft Foundation Class (MFC) 库&#xff0c;许多使用MFC开发的程序需要这个DLL文件来正确执行。丢失了mfc140u.dll文件。会导致…

数据结构需要每个都具体实现吗?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「数据结构的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“666”之后私信回复“666”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;用c的stl能刷算法题是不…

水浅王八多

今天有三个被自媒体和韭菜们转疯的视频。 &#xff08;1&#xff09; 财政部公布&#xff1a;今年1-5月份证券交易印花税&#xff0c;同比去年1-5月份&#xff0c;降低50.8%。 其实是&#xff1a;2023年8月27日&#xff0c;为活跃资本市场&#xff0c;财政部、证监会和三大交易…

wondershaper 一款限制 linux 服务器网卡级别的带宽工具

文章目录 一、关于wondershaper二、文档链接三、源码下载四、限流测试五、常见报错1. /usr/local/sbin/wondershaper: line 145: tc: command not found2. Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist: No URLs.. 一、关于wonder…