欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Unity 從UI中拖拽對象放置并拖動效果 附demo

 更新時間:2021年05月28日 16:49:36   作者:Sun.ME  
最近新接了個需求,要求模擬場景并生成3D對象,對象可以跟隨鼠標(biāo)移動效果,今天小編把我實現(xiàn)的demo分享到腳本之家平臺,對Unity UI拖拽相關(guān)知識感興趣的朋友跟隨小編一起學(xué)習(xí)吧

需求:點擊UI,在場景中生成3D對象,對象跟隨鼠標(biāo)移動,放置后可再次拖拽對象,改變其位置。做了一個小Demo,如下圖所示:

image

實現(xiàn)大致思路:

  • 射線碰撞檢測
  • 對象空間坐標(biāo)變換(世界坐標(biāo)->屏幕坐標(biāo)、屏幕坐標(biāo)->世界坐標(biāo))

首先為要生成3D對象的UI添加一個鼠標(biāo)監(jiān)聽事件,腳本如下:

SelectImage.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class SelectImage : MonoBehaviour,IPointerDownHandler{
    //需要被實例化的預(yù)制
    public GameObject inistatePrefab;
    //實例化后的對象
    private GameObject inistateObj;

    // Use this for initialization
    void Start () {
        if (inistatePrefab==null)return;
        //實例化預(yù)制
        inistateObj=Instantiate(inistatePrefab) as GameObject;
        inistateObj.SetActive(false);
    }
    //實現(xiàn)鼠標(biāo)按下的接口
    public void OnPointerDown(PointerEventData eventData)
    {
        inistateObj.SetActive(true);

        //將當(dāng)前需要被實例化的對象傳遞到管理器中
        SelectObjManager.Instance.AttachNewObject(inistateObj);
    }
}

將腳本掛載到UI對象上。

創(chuà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ī)的長度
    public float _zDistance = 50f;
    //對象的縮放系數(shù)
    public float _scaleFactor=1.2f;
    //地面層級
    public LayerMask _groundLayerMask;
    int touchID;
    bool isDragging = false;
    bool isTouchInput = false;
    //是否是有效的放置(如果放置在地面上返回True,否則為False)
    bool isPlaceSuccess = false;
    //當(dāng)前要被放置的對象
    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>
    ///檢測用戶當(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)前對象跟隨鼠標(biāo)移動
    /// </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,以便后續(xù)拖動檢測
        obj.layer=LayerMask.NameToLayer("Drag");
    }
    /// <summary>
    ///檢測是否放置成功
    /// </summary>
    void CheckIfPlaceSuccess(){
        if (isPlaceSuccess){
            CreatePlaceObj();
        }
        isDragging=false;
        currentPlaceObj.SetActive(false);
        currentPlaceObj=null;
    }
    /// <summary>
    /// 將要創(chuàng)建的對象傳遞給當(dāng)前對象管理器
    /// </summary>
    /// <param name="newObject"></param>
    public void AttachNewObject(GameObject newObject){
        if (currentPlaceObj){
            currentPlaceObj.SetActive(false);
        }
        currentPlaceObj=newObject;
    }
}

腳本中都有詳細(xì)注釋,我就不多解釋了。

創(chuàng)建一個腳本,用于處理放置成功后,再次改變位置的邏輯:

DragObject.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DragObject : MonoBehaviour {
    //只針對指定的層級進(jìn)行拖動
    public LayerMask _dragLayerMask;
    //指定當(dāng)前要拖動的對象
    public Transform currentTransform;
    //是否可以拖動當(dāng)前對象
    public bool isDrag = false;
    //用于存儲當(dāng)前需要拖動的對象在屏幕空間中的坐標(biāo)
    Vector3 screenPos = Vector3.zero;
    //當(dāng)前需要拖動對象的坐標(biāo)相對于鼠標(biāo)在世界空間坐標(biāo)中的偏移量
    Vector3 offset = Vector3.zero;
    void Update () {

        if (Input.GetMouseButtonDown (0)) {
            //將鼠標(biāo)輸入點轉(zhuǎn)化為一條射線
            Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hitinfo;
            //如果當(dāng)前對象與指定的層級發(fā)生碰撞,表示當(dāng)前對象可以被拖動
            if (Physics.Raycast (ray, out hitinfo, 1000f, _dragLayerMask)) {
                isDrag = true;
                //將當(dāng)前需要拖動的對象賦值為射線碰撞到的對象
                currentTransform = hitinfo.transform;
                //將當(dāng)前對象的世界坐標(biāo)轉(zhuǎn)化為屏幕坐標(biāo)
                screenPos = Camera.main.WorldToScreenPoint (currentTransform.position);
                //將鼠標(biāo)的屏幕坐標(biāo)轉(zhuǎn)換為世界空間坐標(biāo),再與當(dāng)前要拖動的對象計算兩者的偏移量
                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)空間的變換和計算。

多余的我就不說了,腳本中都有很詳細(xì)的注釋,Demo地址掃碼后當(dāng)前文章末尾獲取。

到此這篇關(guān)于Unity 從UI中拖拽對象放置并拖動的文章就介紹到這了,更多相關(guān)Unity UI拖拽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#基于時間輪調(diào)度實現(xiàn)延遲任務(wù)詳解

    C#基于時間輪調(diào)度實現(xiàn)延遲任務(wù)詳解

    在很多.net開發(fā)體系中開發(fā)者在面對調(diào)度作業(yè)需求的時候一般會選擇三方開源成熟的作業(yè)調(diào)度框架來滿足業(yè)務(wù)需求,但是有些時候可能我們只是需要一個簡易的延遲任務(wù)。本文主要分享一個簡易的基于時間輪調(diào)度的延遲任務(wù)實現(xiàn),需要的可以參考一下
    2022-12-12
  • C#實現(xiàn).net頁面之間傳值傳參方法匯總

    C#實現(xiàn).net頁面之間傳值傳參方法匯總

    這篇文章主要介紹了C#實現(xiàn).net頁面之間傳值傳參方法,實例匯總了幾類常見的傳值傳參的方法,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • C#后端接收form-data,創(chuàng)建實體類教程

    C#后端接收form-data,創(chuàng)建實體類教程

    這篇文章主要介紹了C#后端接收form-data,創(chuàng)建實體類教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • WinForm中快捷鍵與組合按鍵的設(shè)置方法

    WinForm中快捷鍵與組合按鍵的設(shè)置方法

    WinForm中快捷鍵與組合按鍵的設(shè)置,第一種方法。。代碼復(fù)雜,操作簡單的快捷鍵,另外一種簡單快捷鍵的方法,大家可以參考下
    2013-02-02
  • C#使用正則表達(dá)式

    C#使用正則表達(dá)式

    這篇文章介紹了C#使用正則表達(dá)式的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • Unity編輯器預(yù)制體工具類PrefabUtility常用函數(shù)和用法

    Unity編輯器預(yù)制體工具類PrefabUtility常用函數(shù)和用法

    這篇文章主要為大家介紹了Unity編輯器預(yù)制體工具類PrefabUtility常用函數(shù)及用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • C#影院售票系統(tǒng)畢業(yè)設(shè)計(3)

    C#影院售票系統(tǒng)畢業(yè)設(shè)計(3)

    這篇文章介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計,文章主要內(nèi)容是關(guān)于購票、座位顏色狀態(tài)的改變及場次座位狀態(tài)的顯示,需要的朋友可以參考下
    2015-11-11
  • C#面向?qū)ο缶幊讨欣锸咸鎿Q原則的示例詳解

    C#面向?qū)ο缶幊讨欣锸咸鎿Q原則的示例詳解

    在面向?qū)ο缶幊讨?,SOLID?是五個設(shè)計原則的首字母縮寫,旨在使軟件設(shè)計更易于理解、靈活和可維護(hù)。本文將通過實例詳細(xì)講講C#面向?qū)ο缶幊讨欣锸咸鎿Q原則,需要的可以參考一下
    2022-07-07
  • C#絕對路徑拼接相對路徑的實例代碼

    C#絕對路徑拼接相對路徑的實例代碼

    C#絕對路徑拼接相對路徑的實例代碼,需要的朋友可以參考一下
    2013-03-03
  • C#遍歷DataSet控件實例總結(jié)

    C#遍歷DataSet控件實例總結(jié)

    這篇文章主要介紹了C#遍歷DataSet控件的用法,以實例形式總結(jié)歸納了常見的遍歷方法,具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2014-10-10

最新評論