需求:点击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中拖拽对象放置并拖动相关推荐

  1. unity 原生UI 拖拽跟随鼠标移动

    unity 拖拽某个UI移动时有三个方法:,例如是image类型的UI,要想实现图片跟随着鼠标移动需要以下操作: 第一个方法:在Update函数中执行     if(Input.GetMouseBut ...

  2. Unity跨平台UI解决方案:可能是最全的FairyGUI系列教程.Part2

    回顾 上一节详情请看这里:Unity跨平台UI解决方案:可能是最全的FairyGUI系列教程.Part1 上一节介绍了:FairyGUI编辑器使用(控制台,纹理集....).元件.图片.动画.占位.装 ...

  3. Unity之UI和登陆界面与暂停界面

    Unity----UI和登陆界面与暂停界面 接触了Unity制作不管是程序还是游戏都避免不了UI的制作,但是在网上搜的UI制作的学习过程,额-一言难尽,就像是拼图一样在那一块块搜索然后再将它拼装起来, ...

  4. Unity引擎UI模块知识Tree

    Unity引擎在4.6版本之前是没有内置的UI解决方案的.当时最流行的就是NGUI的框架,目前主流的UI解决方案就是NGUI和UGUI,近几年来,更是以UGUI为主,同时也有团队开始使用FairyGU ...

  5. 【PPT】2010/2013/2016实现在演示过程中拖拽图片/形状

    如果有需要在PPT演示过程中简单拖拽一些元素的功能,那么这篇文章绝对能帮助你    在上一篇文章分泌蛋白过程操作动画中提及到实现PPT演示过程中拖拽元素的方法,这篇写出详细过程.    先说明几点: ...

  6. Unity | Unity中UI框架的实现与使用

    文章目录 0 前言 1 程序结构 2 工具类:UIPanelInfo.cs 3 PanelType枚举类以及BasePanel类 4 UIManager类 5 UIPanelJson文件 5 使用方法 ...

  7. Unity自定义UI组件(十一) 雷达图、属性图

    前言 借用梦想世界宠物属性图 想必大家都在游戏中见过属性图用于展示多种属性的数值,可以较为直观的对比某种属性的缺陷或者是哪种属性有优势.在三维可视化领域也会遇到类似的属性对比,用属性图来展示最为合适. ...

  8. unity使ui面向镜头_pihqcam面向相机的软件ui

    unity使ui面向镜头 Note: This article is part of a series of articles aimed at describing the complete pro ...

  9. Unity EvenTrigerer UI交互组件

    Unity EvenTrigerer UI交互组件 Event Trigerer组件介绍 方便之处 事件选择 使用方法 1.拖拽法 代码添加 接口法 Event Trigerer组件介绍 该组件作用与 ...

最新文章

  1. js从0开始构思表情插件
  2. 吴恩达机器学习Ex2
  3. Python果然不得了,数独都能轻松解决?python秒解数独了解下?
  4. 机器学习实战(用Scikit-learn和TensorFlow进行机器学习)(四)
  5. Python 获取当前文件夹所有文件名并写入到excel文件中
  6. Debug method
  7. LeetCode 225. Implement Stack using Queues
  8. 浅谈Java中的各种锁
  9. 什么是创新型人才,创新型企业?
  10. Servlet 浅析
  11. 【sklearn第十三讲】Naive Bayes分类器
  12. 《Think Python》第15章学习笔记
  13. 【小米手机ROOT记录】
  14. 如何在html上放小游戏,如何在网页插入小游戏
  15. monthly rollup和security only的区别
  16. python爬虫爬取某网站全站图片案列(源码全给可白漂,仅供学习使用,切勿用作非法用途)
  17. 平凡而经典的36句人生格言
  18. mes系统如何管理企业生产
  19. 快速打开文件命令行的三种方法
  20. mysql数据库建站教程视频,Mysql数据库基础入门(附视频教程)

热门文章

  1. 【OD矩阵】《城市公交IC卡·数据分析方法及应用》基于换乘点的上车点识别
  2. 到底什么是ISDN呢?
  3. 电脑里有两个edge浏览器怎么办?
  4. 7、SHA1加密算法
  5. 宁德时代和车企的博弈
  6. centos7部署smokeping,简单的yum直接安装
  7. MoveWindow的问题
  8. 字符串 String
  9. TS—枚举Enum用法
  10. 今年32岁女生,刚开始自学 java,给自己一年时间有出路吗?