Unity 从UI中拖拽对象放置并拖动效果 附demo
需求:点击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 initialization void 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; #else return 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); #else screenPosition = Input.mousePosition; #endif Ray 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拖拽内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09- 这篇文章主要介绍了c#从数据库里取得数据并异步更新ui的方法,大家参考使用吧...2020-06-25
No module named ‘win32gui‘ 的解决方法(踩坑之旅)
这篇文章主要介绍了No module named ‘win32gui‘ 的解决方法(踩坑之旅),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18- 这篇文章主要介绍了解决vant-UI库修改样式无效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-03
- 这篇文章主要为大家详细介绍了vue+element ui实现锚点定位,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-06-29
- 本文主要介绍了element表格行列拖拽的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-02
- 由于业务需要,要求实现树形菜单,且菜单数据由后台返回,下面这篇文章主要给大家介绍了关于js如何构造elementUI树状菜单的数据结构的相关资料,需要的朋友可以参考下...2021-05-13
- 这篇文章主要为大家详细介绍了easyUI下拉列表点击事件的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2017-05-22
详解element-ui 表单校验 Rules 配置 常用黑科技
这篇文章主要介绍了element-ui 表单校验 Rules 配置 常用黑科技,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-11- 这篇文章主要为大家详细介绍了Unity时间戳的使用方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- SwiftUI是一种使用Swift语言在苹果设备上构建用户界面的创新且简单的方式,下面这篇文章主要给大家介绍了关于SwiftUI图片缩放、拼图等处理的相关资料,需要的朋友可以参考下...2021-08-23
jQuery EasyUI编辑DataGrid用combobox实现多级联动
本文给大家分享jQuery EasyUI编辑DataGrid用combobox实现多级联动效果的实例代码,代码简单易懂,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧...2016-09-01- 这篇文章主要介绍了js实现div在页面拖动效果,涉及JavaScript动态操作页面元素与数值计算的相关技巧,需要的朋友可以参考下...2016-05-05
javascript轻量级库createjs使用Easel实现拖拽效果
这篇文章主要介绍了javascript轻量级库createjs使用Easel实现拖拽效果的相关资料,需要的朋友可以参考下...2016-02-21jQuery Easyui使用(二)之可折叠面板动态加载无效果的解决方法
这篇文章主要介绍了jQuery Easyui使用之可折叠面板动态加载无效果的解决方案,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧...2016-08-24- 这篇文章主要介绍了一百多行代码实现react拖拽hooks,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-21
- 这篇文章主要为大家详细介绍了C#控件Picturebox实现鼠标拖拽功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- 这篇文章主要为大家详细介绍了jQuery UI结合Ajax创建可定制的Web界面,如何利用Ajax和jQuery UI创建具有各种定制功能的高度可定制的UI,感兴趣的小伙伴们可以参考一下...2016-06-24
解析element-ui中upload组件传递文件及其他参数的问题
这篇文章主要介绍了element-ui中upload组件如何传递文件及其他参数,分析一下我使用element-ui遇到的问题以及解决方法,需要的朋友可以参考下...2021-11-10如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上
这篇文章主要介绍了如何解决easyui自定义标签 datagrid edit combobox 手动输入保存不上,需要的朋友可以参考下...2015-12-28