Unity3D UI 拖拽

Unity3D 实现 UI 元素拖拽功能。

UI 拖拽

通常画布上的 UI 元素都是固定位置的,我们可以通过实现拖拽接口,让 UI 元素可以被拖拽到其他位置。

拖拽接口

创建一个脚本 UIDrag.cs,在默认继承的 MonoBehaviour 后面,再继承三个接口。

  • IBeginDragHandler(开始拖拽)
  • IDragHandler(拖拽中)
  • IEndDragHandler(结束拖拽)

继承接口之后,要在脚本中实现接口中定义的方法,即 OnBeginDragOnDragOnEndDrag

using UnityEngine;
using UnityEngine.EventSystems;public class UIDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{public void OnBeginDrag(PointerEventData eventData){}public void OnDrag(PointerEventData eventData){transform.position = eventData.position;}public void OnEndDrag(PointerEventData eventData){}
}

这里先在 OnDrag 方法中,把 eventData.position 赋值给 transform.position

然后创建一个 Image,把 UIDrag 脚本拖拽到 Image 上。

挂载组件

运行游戏,点击拖拽图片。

拖拽效果

画布渲染模式

上述的拖拽实现,是基于画布的 Overlay 模式。

Overlay模式

如果把画布渲染模式改成 Camera 模式,上述的代码实现就会出现问题。

因为 Camera 模式的画布会被缩小到相机的视野范围内,坐标的数值会变得很小。

Camera模式

此时的运行效果,拖拽后图片飞到了离画布很远的位置,坐标错误。

坐标错误

所以我们需要对拖拽时获得的坐标位置进行转换。

坐标转换

首先,定义一个 RectTransform 变量,在 Awake 时进行赋值。

然后利用 RectTransformUtility.ScreenPointToWorldPointInRectangle 方法,把自身的 recteventData.positioneventData.pressEventCamera 传入,如果坐标转换正常,则会返回转换后的 worldPoint,把这个坐标赋值给 rect.position 就可以了。

这个方法可以把屏幕空间坐标转换成 UI 元素所在的世界坐标。

using UnityEngine;
using UnityEngine.EventSystems;public class UIDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{RectTransform rect;void Awake(){rect = GetComponent<RectTransform>();}public void OnBeginDrag(PointerEventData eventData){}public void OnDrag(PointerEventData eventData){if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position,eventData.pressEventCamera, out Vector3 worldPoint)){rect.position = worldPoint;}}public void OnEndDrag(PointerEventData eventData){}
}

修改代码后,无论画布是 Overlay 还是 Camera 模式,都可以正常拖拽。

切换模式

开始与结束拖拽

单纯的拖拽,只需要 OnDrag 方法,而 OnBeginDragOnEndDrag 可以为拖拽操作添加更多的逻辑处理。

例如,在场景中添加两个 Image,修改名字,改变颜色和不透明度,放置到左右两边。

添加容器

然后在代码中添加更多的逻辑,添加一个 raycastResults 用于保存射线检测到的 UI 元素列表,通过 EventSystem.current.RaycastAll 方法,把鼠标经过的 UI 元素都添加到列表中(包含 Image 自己)。

如果鼠标经过的 UI 元素的名字包含 Container,就把目标元素赋值给 target;如果列表中只有 Image 自己,则 target 为空。

我们可以在 OnBeginDrag 中,把 Image 原来的位置保存起来。在 OnEndDrag 中,检查 target 为空时,把原来的位置赋值给 Image,回到原位。只有在 target 不为空时,Image 才会移动到目标容器位置。

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;public class UIDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{RectTransform rect;List<RaycastResult> raycastResults;GameObject target;Vector3 originPos;void Awake(){rect = GetComponent<RectTransform>();raycastResults = new List<RaycastResult>();}public void OnBeginDrag(PointerEventData eventData){originPos = transform.position;}public void OnDrag(PointerEventData eventData){if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position,eventData.pressEventCamera, out Vector3 worldPoint)){rect.position = worldPoint;}// 清空上一次的射线检测结果raycastResults.Clear();// 进行射线检测EventSystem.current.RaycastAll(eventData, raycastResults);// 包含两个 UI 元素以上if (raycastResults.Count > 1){// 遍历检测结果foreach (RaycastResult result in raycastResults){// 跳过自身对象的检测if (result.gameObject == gameObject) continue;// 检测到目标容器if (result.gameObject.name.Contains("Container")){target = result.gameObject;}}}// 只包含自己,没有目标else{target = null;}}public void OnEndDrag(PointerEventData eventData){if (target == null){transform.position = originPos;}else{transform.position = target.transform.position;}}
}

运行效果:

拖到容器

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

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

相关文章

《重学Java设计模式》之 工厂方法模式

《重学Java设计模式》之 建造者模式 《重学Java设计模式》之 原型模式 《重学Java设计模式》之 单例模式 模拟发奖多种商品 工程结构 奖品发放接口 package com.yys.mes.design.factory.store;public interface ICommodity {/*** Author Sherry* Date 14:20 2024/11/6**/voi…

【Python爬虫实战】DrissionPage 与 ChromiumPage:高效网页自动化与数据抓取的双利器

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、DrissionPage简介 &#xff08;一&#xff09;特点 &#xff08;二&#xff09;安装 &#xff08;三…

Word大珩助手:超大数字怎么读?35位数字?69位数字?

俄罗斯日前对谷歌开出了20000000000000000000000000000000000&#xff08;35位数字&#xff09;美元的罚款 这一数字远超全球GDP总和&#xff0c;消息一出很快就登上热搜。 面对这样一个庞大的数字&#xff0c;人们不禁好奇&#xff0c;这样的数字该如何读出来&#xff1f; …

Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized

这里是Themberfue 在上一节的最后&#xff0c;我们讨论两个线程同时对一个变量累加所产生的现象 在这一节中&#xff0c;我们将更加详细地解释这个现象背后发生的原因以及该如何解决这样类似的现象 线程安全问题 public class Demo15 {private static int count 0;public …

17、论文阅读:VMamba:视觉状态空间模型

前言 设计计算效率高的网络架构在计算机视觉领域仍然是一个持续的需求。在本文中&#xff0c;我们将一种状态空间语言模型 Mamba 移植到 VMamba 中&#xff0c;构建出一个具有线性时间复杂度的视觉主干网络。VMamba 的核心是一组视觉状态空间 (VSS) 块&#xff0c;搭配 2D 选择…

JavaAPI(1)

Java的API&#xff08;1&#xff09; 一、Math的API 是一个帮助我们进行数学计算的工具类私有化构造方法&#xff0c;所有的方法都是静态的&#xff08;可以直接通过类名.调用&#xff09; 平方根&#xff1a;Math.sqrt()立方根&#xff1a;Math.cbrt() 示例&#xff1a; p…

【362】基于springboot的在线租房和招聘平台

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统在线租房和招聘平台信息管理难度大&#xff0c;容错率低&…

华为HCIP —— QinQ技术实验配置

一、QinQ的概述 1.1QinQ的概念 QinQ&#xff08;802.1Q in 802.1Q&#xff09;技术是一项扩展VLAN空间的技术&#xff0c;通过在原有的802.1Q报文基础上再增加一层802.1Q的Tag来实现。 1.2QinQ封装结构 QinQ封装报文是在无标签的以太网数据帧的源MAC地址字段后面加上两个VL…

【数据集】【YOLO】【目标检测】抽烟识别数据集 6953 张,YOLO/VOC格式标注,吸烟检测!

数据集介绍 【数据集】抽烟识别数据集 6953 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含1种分类&#xff1a;“smoking”。数据集来自国内外图片网站和视频截图。检测范围园区吸烟检测、禁烟区吸烟检测、监控吸烟检测、无人机吸烟检测等。 主页私…

赛元MCU 脱机烧录步骤

烧录设置 生成烧录配置文件 载入配置文件 下载程序到烧录器中 并 对比 脱机烧录 1、 将SC-LINK 使用外部5V电源供电 2、将烧录口对准主板烧录接口 3、busy亮红灯&#xff0c;进入烧录ing&#xff0c;烧录成功后&#xff0c;OK灯亮蓝灯 注意事项 其中工程校验和 可以作为程序…

leetcode字符串(二)-重复的子字符串

题目 459.重复的子字符串 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: …

langchain 4大组件 | AI应用开发

在人工智能的浪潮中&#xff0c;大型语言模型&#xff08;LLM&#xff09;逐渐成为推动科技进步的重要力量。而LangChain&#xff0c;作为一个专为LLM应用开发设计的框架&#xff0c;凭借其模块化和高效性&#xff0c;受到了广泛关注。本文将深入浅出地讲解LangChain中的四个基…

TensorFlow|咖啡豆识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 &#x1f37a; 要求&#xff1a; 自己搭建VGG-16网络框架调用官方的VGG-16网络框架 &#x1f37b; 拔高&#xff08;可选&#xff09;&#xff1a; 验证集准…

Jmeter5.X性能测试

Jmeter5.X性能测试 文章目录 Jmeter5.X性能测试一、掌握Http基础协议1.1 浏览器的B/S架构和C/S架构1.2 HyperText Transfer Protocol 超文本传输协议1.3 超文本传输协议Http消息体拆分讲解1.4 HTTP的九种请求方法和响应码介绍1.5 Http请求头/响应头1.6 Http常见请求/响应头cont…

信息安全工程师(81)网络安全测评质量管理与标准

一、网络安全测评质量管理 遵循标准和流程 网络安全测评应严格遵循国家相关标准和流程&#xff0c;确保测评工作的规范性和一致性。这些标准和流程通常包括测评方法、测评步骤、测评指标等&#xff0c;为测评工作提供明确的指导和依据。 选择合格的测评团队 测评团队应具备相关…

AI - 人工智能;Ollama大模型工具;Java之SpringAI(三)

AI - 人工智能&#xff1b;Java之SpringAI&#xff08;一&#xff09; AI - 人工智能&#xff1b;Java之SpringAI&#xff08;二&#xff09; 一、Ollama 官网&#xff1a;https://ollama.com/ Ollama是一个大模型部署运行工具&#xff0c;在该工具里面可以部署运行各种大模型…

力扣—不同路径(路径问题的动态规划)

文章目录 题目解析算法原理代码实现题目练习 题目解析 算法原理 状态表示 对于这种「路径类」的问题&#xff0c;我们的状态表示⼀般有两种形式&#xff1a; i. 从[i, j] 位置出发。 ii. 从起始位置出发&#xff0c;到[i, j] 位置。 这⾥选择第⼆种定义状态表⽰的⽅式&#xf…

用了Stream后,代码反而越写越丑?

使用 Stream API 可以使代码更加简洁和易读&#xff0c;但如果不恰当地使用或过度使用&#xff0c;确实可能导致代码变得复杂和难以理解。以下是一些常见的问题和改进建议&#xff1a; 常见问题 过度链式调用&#xff1a;过度链式调用 Stream 方法会导致代码行过长&#xff0c…

论文速读:简化目标检测的无源域适应-有效的自我训练策略和性能洞察(ECCV2024)

中文标题&#xff1a;简化目标检测的无源域适应&#xff1a;有效的自我训练策略和性能洞察 原文标题&#xff1a;Simplifying Source-Free Domain Adaptation for Object Detection: Effective Self-Training Strategies and Performance Insights 此篇文章为论文速读&#xff…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十. 多线程控制帧率。循环播放,QT connect 细节,

在前面&#xff0c;我们总结一下前面的代码。 在 FactoryModeForAVFrameShowSDL 构造函数中 init SDL。 通过 QT timerevent机制&#xff0c;通过startTimer(10);每隔10ms&#xff0c;就会调用timerEvent事件。 在timerEvent事件中&#xff0c;真正的去 读取数据&#xff0c…