Unity 從UI中拖拽對(duì)象放置并拖動(dòng)效果 附demo
需求:點(diǎn)擊UI,在場(chǎng)景中生成3D對(duì)象,對(duì)象跟隨鼠標(biāo)移動(dòng),放置后可再次拖拽對(duì)象,改變其位置。做了一個(gè)小Demo,如下圖所示:
實(shí)現(xiàn)大致思路:
- 射線碰撞檢測(cè)
- 對(duì)象空間坐標(biāo)變換(世界坐標(biāo)->屏幕坐標(biāo)、屏幕坐標(biāo)->世界坐標(biāo))
首先為要生成3D對(duì)象的UI添加一個(gè)鼠標(biāo)監(jiān)聽事件,腳本如下:
SelectImage.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class SelectImage : MonoBehaviour,IPointerDownHandler{ //需要被實(shí)例化的預(yù)制 public GameObject inistatePrefab; //實(shí)例化后的對(duì)象 private GameObject inistateObj; // Use this for initialization void Start () { if (inistatePrefab==null)return; //實(shí)例化預(yù)制 inistateObj=Instantiate(inistatePrefab) as GameObject; inistateObj.SetActive(false); } //實(shí)現(xiàn)鼠標(biāo)按下的接口 public void OnPointerDown(PointerEventData eventData) { inistateObj.SetActive(true); //將當(dāng)前需要被實(shí)例化的對(duì)象傳遞到管理器中 SelectObjManager.Instance.AttachNewObject(inistateObj); } }
將腳本掛載到UI對(duì)象上。
創(chuàng)建一個(gè)對(duì)象放置管理器,用于處理拖動(dòng)的放置的邏輯:
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軸距攝像機(jī)的長(zhǎng)度 public float _zDistance = 50f; //對(duì)象的縮放系數(shù) public float _scaleFactor=1.2f; //地面層級(jí) public LayerMask _groundLayerMask; int touchID; bool isDragging = false; bool isTouchInput = false; //是否是有效的放置(如果放置在地面上返回True,否則為False) bool isPlaceSuccess = false; //當(dāng)前要被放置的對(duì)象 public GameObject currentPlaceObj = null; //坐標(biāo)在Y軸上的偏移量 public float _YOffset=0.5F; void Awake () { _instance = this; } void Update () { if (currentPlaceObj == null) return; if (CheckUserInput()){ MoveCurrentPlaceObj(); }else if (isDragging){ CheckIfPlaceSuccess(); } } /// <summary> ///檢測(cè)用戶當(dāng)前輸入 /// </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> ///讓當(dāng)前對(duì)象跟隨鼠標(biāo)移動(dòng) /// </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> ///在指定位置化一個(gè)對(duì)象 /// </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; //改變這個(gè)對(duì)象的Layer為Drag,以便后續(xù)拖動(dòng)檢測(cè) obj.layer=LayerMask.NameToLayer("Drag"); } /// <summary> ///檢測(cè)是否放置成功 /// </summary> void CheckIfPlaceSuccess(){ if (isPlaceSuccess){ CreatePlaceObj(); } isDragging=false; currentPlaceObj.SetActive(false); currentPlaceObj=null; } /// <summary> /// 將要?jiǎng)?chuàng)建的對(duì)象傳遞給當(dāng)前對(duì)象管理器 /// </summary> /// <param name="newObject"></param> public void AttachNewObject(GameObject newObject){ if (currentPlaceObj){ currentPlaceObj.SetActive(false); } currentPlaceObj=newObject; } }
腳本中都有詳細(xì)注釋,我就不多解釋了。
創(chuàng)建一個(gè)腳本,用于處理放置成功后,再次改變位置的邏輯:
DragObject.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DragObject : MonoBehaviour { //只針對(duì)指定的層級(jí)進(jìn)行拖動(dòng) public LayerMask _dragLayerMask; //指定當(dāng)前要拖動(dòng)的對(duì)象 public Transform currentTransform; //是否可以拖動(dòng)當(dāng)前對(duì)象 public bool isDrag = false; //用于存儲(chǔ)當(dāng)前需要拖動(dòng)的對(duì)象在屏幕空間中的坐標(biāo) Vector3 screenPos = Vector3.zero; //當(dāng)前需要拖動(dòng)對(duì)象的坐標(biāo)相對(duì)于鼠標(biāo)在世界空間坐標(biāo)中的偏移量 Vector3 offset = Vector3.zero; void Update () { if (Input.GetMouseButtonDown (0)) { //將鼠標(biāo)輸入點(diǎn)轉(zhuǎn)化為一條射線 Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition); RaycastHit hitinfo; //如果當(dāng)前對(duì)象與指定的層級(jí)發(fā)生碰撞,表示當(dāng)前對(duì)象可以被拖動(dòng) if (Physics.Raycast (ray, out hitinfo, 1000f, _dragLayerMask)) { isDrag = true; //將當(dāng)前需要拖動(dòng)的對(duì)象賦值為射線碰撞到的對(duì)象 currentTransform = hitinfo.transform; //將當(dāng)前對(duì)象的世界坐標(biāo)轉(zhuǎn)化為屏幕坐標(biāo) screenPos = Camera.main.WorldToScreenPoint (currentTransform.position); //將鼠標(biāo)的屏幕坐標(biāo)轉(zhuǎn)換為世界空間坐標(biāo),再與當(dāng)前要拖動(dòng)的對(duì)象計(jì)算兩者的偏移量 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); //鼠標(biāo)的屏幕空間坐標(biāo)轉(zhuǎn)化為世界坐標(biāo),并加上偏移量 var currentPos = Camera.main.ScreenToWorldPoint (currentScreenPos) + offset; currentTransform.position = currentPos; } } if (Input.GetMouseButtonUp (0)) { isDrag = false; currentTransform = null; } } }
主要是一些坐標(biāo)空間的變換和計(jì)算。
多余的我就不說了,腳本中都有很詳細(xì)的注釋,Demo地址掃碼后當(dāng)前文章末尾獲取。
到此這篇關(guān)于Unity 從UI中拖拽對(duì)象放置并拖動(dòng)的文章就介紹到這了,更多相關(guān)Unity UI拖拽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Unity UGUI實(shí)現(xiàn)簡(jiǎn)單拖拽圖片功能
- Unity工具類ScrollView實(shí)現(xiàn)拖拽滑動(dòng)翻頁
- Unity UI拖拽模型選擇功能
- Unity3D實(shí)現(xiàn)物體旋轉(zhuǎn)縮放移動(dòng)效果
- Unity向量按照某一點(diǎn)進(jìn)行旋轉(zhuǎn)
- Unity實(shí)現(xiàn)旋轉(zhuǎn)扭曲圖像特效
- Unity實(shí)現(xiàn)物體沿自身的任意軸向旋轉(zhuǎn)
- Unity實(shí)現(xiàn)人物旋轉(zhuǎn)和移動(dòng)效果
- Unity實(shí)現(xiàn)繞任意軸任意角度旋轉(zhuǎn)向量
- Unity UI實(shí)現(xiàn)拖拽旋轉(zhuǎn)
相關(guān)文章
C#基于時(shí)間輪調(diào)度實(shí)現(xiàn)延遲任務(wù)詳解
在很多.net開發(fā)體系中開發(fā)者在面對(duì)調(diào)度作業(yè)需求的時(shí)候一般會(huì)選擇三方開源成熟的作業(yè)調(diào)度框架來滿足業(yè)務(wù)需求,但是有些時(shí)候可能我們只是需要一個(gè)簡(jiǎn)易的延遲任務(wù)。本文主要分享一個(gè)簡(jiǎn)易的基于時(shí)間輪調(diào)度的延遲任務(wù)實(shí)現(xiàn),需要的可以參考一下2022-12-12C#實(shí)現(xiàn).net頁面之間傳值傳參方法匯總
這篇文章主要介紹了C#實(shí)現(xiàn).net頁面之間傳值傳參方法,實(shí)例匯總了幾類常見的傳值傳參的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10C#后端接收form-data,創(chuàng)建實(shí)體類教程
這篇文章主要介紹了C#后端接收form-data,創(chuàng)建實(shí)體類教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Unity編輯器預(yù)制體工具類PrefabUtility常用函數(shù)和用法
這篇文章主要為大家介紹了Unity編輯器預(yù)制體工具類PrefabUtility常用函數(shù)及用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(3)
這篇文章介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì),文章主要內(nèi)容是關(guān)于購票、座位顏色狀態(tài)的改變及場(chǎng)次座位狀態(tài)的顯示,需要的朋友可以參考下2015-11-11C#絕對(duì)路徑拼接相對(duì)路徑的實(shí)例代碼
C#絕對(duì)路徑拼接相對(duì)路徑的實(shí)例代碼,需要的朋友可以參考一下2013-03-03