Unity 从UI中拖拽对象放置并拖动
需求:点击UI,在场景中生成3D对象,对象跟随鼠标移动,放置后可再次拖拽对象,改变其位置。做了一个小Demo,如下图所示:
实现大致思路:
- 射线碰撞检测
- 对象空间坐标变换(世界坐标->屏幕坐标、屏幕坐标->世界坐标)
首先为要生成3D对象的UI添加一个鼠标监听事件,脚本如下:
SelectImage.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class SelectImage : MonoBehaviour,IPointerDownHandler{//需要被实例化的预制public GameObject inistatePrefab;//实例化后的对象private GameObject inistateObj;// Use this for initializationvoid Start () {if (inistatePrefab==null)return;//实例化预制inistateObj=Instantiate(inistatePrefab) as GameObject;inistateObj.SetActive(false);}//实现鼠标按下的接口public void OnPointerDown(PointerEventData eventData){inistateObj.SetActive(true);//将当前需要被实例化的对象传递到管理器中SelectObjManager.Instance.AttachNewObject(inistateObj);}
}
将脚本挂载到UI对象上。
创建一个对象放置管理器,用于处理拖动的放置的逻辑:
SelectObjManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class SelectObjManager : MonoBehaviour {private static SelectObjManager _instance;public static SelectObjManager Instance {get { return _instance; }}//物体z轴距摄像机的长度public float _zDistance = 50f;//对象的缩放系数public float _scaleFactor=1.2f;//地面层级public LayerMask _groundLayerMask;int touchID;bool isDragging = false;bool isTouchInput = false;//是否是有效的放置(如果放置在地面上返回True,否则为False)bool isPlaceSuccess = false;//当前要被放置的对象public GameObject currentPlaceObj = null;//坐标在Y轴上的偏移量public float _YOffset=0.5F;void Awake () {_instance = this;}void Update () {if (currentPlaceObj == null) return;if (CheckUserInput()){MoveCurrentPlaceObj();}else if (isDragging){CheckIfPlaceSuccess();}}/// <summary>///检测用户当前输入/// </summary>/// <returns></returns>bool CheckUserInput () {#if !UNITY_EDITOR&&(UNITY_ANDROID||UNITY_IOS)if (Input.touches.Length > 0) {if (!isTouchInput) {isTouchInput = true;touchID = Input.touches[0].fingerId;return true;} else if (Input.GetTouch (touchID).phase == TouchPhase.Ended) {isTouchInput = false;return false;} else {return true;}}return false;#elsereturn Input.GetMouseButton (0);#endif}/// <summary>///让当前对象跟随鼠标移动/// </summary>void MoveCurrentPlaceObj () {isDragging = true;Vector3 point;Vector3 screenPosition;#if !UNITY_EDITOR&&(UNITY_ANDROID||UNITY_IOS)Touch touch = Input.GetTouch (touchID);screenPosition = new Vector3 (touch.position.x, touch.position.y, 0);#elsescreenPosition = Input.mousePosition;#endifRay ray = Camera.main.ScreenPointToRay (screenPosition);RaycastHit hitInfo;if (Physics.Raycast (ray, out hitInfo, 1000, _groundLayerMask)) {point = hitInfo.point;isPlaceSuccess = true;} else {point = ray.GetPoint (_zDistance);isPlaceSuccess = false;}currentPlaceObj.transform.position = point+new Vector3(0,_YOffset,0);currentPlaceObj.transform.localEulerAngles = new Vector3 (0, 60, 0);}/// <summary>///在指定位置化一个对象/// </summary>void CreatePlaceObj(){GameObject obj=Instantiate(currentPlaceObj) as GameObject;obj.transform.position=currentPlaceObj.transform.position;obj.transform.localEulerAngles=currentPlaceObj.transform.localEulerAngles;obj.transform.localScale*=_scaleFactor;//改变这个对象的Layer为Drag,以便后续拖动检测obj.layer=LayerMask.NameToLayer("Drag");}/// <summary>///检测是否放置成功/// </summary>void CheckIfPlaceSuccess(){if (isPlaceSuccess){CreatePlaceObj();}isDragging=false;currentPlaceObj.SetActive(false);currentPlaceObj=null;}/// <summary>/// 将要创建的对象传递给当前对象管理器/// </summary>/// <param name="newObject"></param>public void AttachNewObject(GameObject newObject){if (currentPlaceObj){currentPlaceObj.SetActive(false);}currentPlaceObj=newObject;}
}
脚本中都有详细注释,我就不多解释了。
创建一个脚本,用于处理放置成功后,再次改变位置的逻辑:
DragObject.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class DragObject : MonoBehaviour {//只针对指定的层级进行拖动public LayerMask _dragLayerMask;//指定当前要拖动的对象public Transform currentTransform;//是否可以拖动当前对象public bool isDrag = false;//用于存储当前需要拖动的对象在屏幕空间中的坐标Vector3 screenPos = Vector3.zero;//当前需要拖动对象的坐标相对于鼠标在世界空间坐标中的偏移量Vector3 offset = Vector3.zero;void Update () {if (Input.GetMouseButtonDown (0)) {//将鼠标输入点转化为一条射线Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);RaycastHit hitinfo;//如果当前对象与指定的层级发生碰撞,表示当前对象可以被拖动if (Physics.Raycast (ray, out hitinfo, 1000f, _dragLayerMask)) {isDrag = true;//将当前需要拖动的对象赋值为射线碰撞到的对象currentTransform = hitinfo.transform;//将当前对象的世界坐标转化为屏幕坐标screenPos = Camera.main.WorldToScreenPoint (currentTransform.position);//将鼠标的屏幕坐标转换为世界空间坐标,再与当前要拖动的对象计算两者的偏移量offset = currentTransform.position - Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPos.z));} else {isDrag = false;}}if (Input.GetMouseButton (0)) {if (isDrag == true) {var currentScreenPos = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPos.z);//鼠标的屏幕空间坐标转化为世界坐标,并加上偏移量var currentPos = Camera.main.ScreenToWorldPoint (currentScreenPos) + offset;currentTransform.position = currentPos;}}if (Input.GetMouseButtonUp (0)) {isDrag = false;currentTransform = null;}}
}
主要是一些坐标空间的变换和计算。
多余的我就不说了,脚本中都有很详细的注释,Demo地址扫码后当前文章末尾获取。
更多内容,欢迎关注:
Unity 从UI中拖拽对象放置并拖动相关推荐
- unity 原生UI 拖拽跟随鼠标移动
unity 拖拽某个UI移动时有三个方法:,例如是image类型的UI,要想实现图片跟随着鼠标移动需要以下操作: 第一个方法:在Update函数中执行 if(Input.GetMouseBut ...
- Unity跨平台UI解决方案:可能是最全的FairyGUI系列教程.Part2
回顾 上一节详情请看这里:Unity跨平台UI解决方案:可能是最全的FairyGUI系列教程.Part1 上一节介绍了:FairyGUI编辑器使用(控制台,纹理集....).元件.图片.动画.占位.装 ...
- Unity之UI和登陆界面与暂停界面
Unity----UI和登陆界面与暂停界面 接触了Unity制作不管是程序还是游戏都避免不了UI的制作,但是在网上搜的UI制作的学习过程,额-一言难尽,就像是拼图一样在那一块块搜索然后再将它拼装起来, ...
- Unity引擎UI模块知识Tree
Unity引擎在4.6版本之前是没有内置的UI解决方案的.当时最流行的就是NGUI的框架,目前主流的UI解决方案就是NGUI和UGUI,近几年来,更是以UGUI为主,同时也有团队开始使用FairyGU ...
- 【PPT】2010/2013/2016实现在演示过程中拖拽图片/形状
如果有需要在PPT演示过程中简单拖拽一些元素的功能,那么这篇文章绝对能帮助你 在上一篇文章分泌蛋白过程操作动画中提及到实现PPT演示过程中拖拽元素的方法,这篇写出详细过程. 先说明几点: ...
- Unity | Unity中UI框架的实现与使用
文章目录 0 前言 1 程序结构 2 工具类:UIPanelInfo.cs 3 PanelType枚举类以及BasePanel类 4 UIManager类 5 UIPanelJson文件 5 使用方法 ...
- Unity自定义UI组件(十一) 雷达图、属性图
前言 借用梦想世界宠物属性图 想必大家都在游戏中见过属性图用于展示多种属性的数值,可以较为直观的对比某种属性的缺陷或者是哪种属性有优势.在三维可视化领域也会遇到类似的属性对比,用属性图来展示最为合适. ...
- unity使ui面向镜头_pihqcam面向相机的软件ui
unity使ui面向镜头 Note: This article is part of a series of articles aimed at describing the complete pro ...
- Unity EvenTrigerer UI交互组件
Unity EvenTrigerer UI交互组件 Event Trigerer组件介绍 方便之处 事件选择 使用方法 1.拖拽法 代码添加 接口法 Event Trigerer组件介绍 该组件作用与 ...
最新文章
- js从0开始构思表情插件
- 吴恩达机器学习Ex2
- Python果然不得了,数独都能轻松解决?python秒解数独了解下?
- 机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(四)
- Python 获取当前文件夹所有文件名并写入到excel文件中
- Debug method
- LeetCode 225. Implement Stack using Queues
- 浅谈Java中的各种锁
- 什么是创新型人才,创新型企业?
- Servlet 浅析
- 【sklearn第十三讲】Naive Bayes分类器
- 《Think Python》第15章学习笔记
- 【小米手机ROOT记录】
- 如何在html上放小游戏,如何在网页插入小游戏
- monthly rollup和security only的区别
- python爬虫爬取某网站全站图片案列(源码全给可白漂,仅供学习使用,切勿用作非法用途)
- 平凡而经典的36句人生格言
- mes系统如何管理企业生产
- 快速打开文件命令行的三种方法
- mysql数据库建站教程视频,Mysql数据库基础入门(附视频教程)