Unity drag and drop the object from the UI, place and drag the effect, and attach a demo

Time:2021-12-31

Requirements: click the UI to generate 3D objects in the scene. The objects move with the mouse. After placement, you can drag the objects again to change their position. A small demo is made, as shown in the following figure:

image

General idea of realization:

  • X-ray collision detection
  • Object space coordinate transformation (world coordinates – > screen coordinates, screen coordinates – > world coordinates)

First, add a mouse listening event for the UI to generate 3D objects. The script is as follows:

SelectImage.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class SelectImage : MonoBehaviour,IPointerDownHandler{
    //Prefab to be instantiated
    public GameObject inistatePrefab;
    //Instantiated object
    private GameObject inistateObj;

    // Use this for initialization
    void Start () {
        if (inistatePrefab==null)return;
        //Instantiation prefabrication
        inistateObj=Instantiate(inistatePrefab) as GameObject;
        inistateObj.SetActive(false);
    }
    //Interface for mouse down
    public void OnPointerDown(PointerEventData eventData)
    {
        inistateObj.SetActive(true);

        //Pass the object to be instantiated to the manager
        SelectObjManager.Instance.AttachNewObject(inistateObj);
    }
}

Mount the script on the UI object.

Create an object placement manager to handle the logic of dragged placement:

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; }
    }
    //Length of object Z wheelbase camera
    public float _zDistance = 50f;
    //The scaling factor of the object
    public float _scaleFactor=1.2f;
    //Ground level
    public LayerMask _groundLayerMask;
    int touchID;
    bool isDragging = false;
    bool isTouchInput = false;
    //Is it a valid placement (returns true if placed on the ground, false otherwise)
    bool isPlaceSuccess = false;
    //Current object to be placed
    public GameObject currentPlaceObj = null;
    //The offset of the coordinate on the Y axis
    public float _YOffset=0.5F;

    void Awake () {
        _instance = this;
    }
    void Update () {
        if (currentPlaceObj == null) return;

        if (CheckUserInput()){
            MoveCurrentPlaceObj();
        }else if (isDragging){
            CheckIfPlaceSuccess();
        }
    }
    /// <summary>
    ///Detect current user input
    /// </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>
    ///Make the current object follow the mouse
    /// </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>
    ///Localize an object at a specified location
    /// </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;
        //Change the layer of this object to drag for subsequent drag detection
        obj.layer=LayerMask.NameToLayer("Drag");
    }
    /// <summary>
    ///Check whether the placement is successful
    /// </summary>
    void CheckIfPlaceSuccess(){
        if (isPlaceSuccess){
            CreatePlaceObj();
        }
        isDragging=false;
        currentPlaceObj.SetActive(false);
        currentPlaceObj=null;
    }
    /// <summary>
    ///Passes the object to be created to the current object manager
    /// </summary>
    /// <param name="newObject"></param>
    public void AttachNewObject(GameObject newObject){
        if (currentPlaceObj){
            currentPlaceObj.SetActive(false);
        }
        currentPlaceObj=newObject;
    }
}

There are detailed comments in the script, so I won’t explain more.

Create a script to handle the logic of changing the position again after successful placement:

DragObject.cs

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

public class DragObject : MonoBehaviour {
    //Drag only at the specified level
    public LayerMask _dragLayerMask;
    //Specifies the current object to drag
    public Transform currentTransform;
    //Can I drag the current object
    public bool isDrag = false;
    //Used to store the coordinates of the object currently to be dragged in screen space
    Vector3 screenPos = Vector3.zero;
    //The offset of the coordinates of the object currently to be dragged relative to the mouse in world space coordinates
    Vector3 offset = Vector3.zero;
    void Update () {

        if (Input.GetMouseButtonDown (0)) {
            //Convert the mouse input point to a ray
            Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hitinfo;
            //If the current object collides with the specified level, it means that the current object can be dragged
            if (Physics.Raycast (ray, out hitinfo, 1000f, _dragLayerMask)) {
                isDrag = true;
                //Assign the object currently to be dragged as the object to which the ray collides
                currentTransform = hitinfo.transform;
                //Converts the world coordinates of the current object to screen coordinates
                screenPos = Camera.main.WorldToScreenPoint (currentTransform.position);
                //Convert the screen coordinates of the mouse into world space coordinates, and then calculate the offset between them and the object to be dragged
                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);
                //The screen space coordinates of the mouse are converted to world coordinates and offset is added
                var currentPos = Camera.main.ScreenToWorldPoint (currentScreenPos) + offset;
                currentTransform.position = currentPos;
            }
        }
        if (Input.GetMouseButtonUp (0)) {
            isDrag = false;
            currentTransform = null;
        }
    }
}

Mainly some coordinate space transformation and calculation.

I won’t say anything superfluous. There are very detailed comments in the script. The demo address is obtained at the end of the current article after scanning the code.

This is the end of this article about unity dragging and dropping objects from the UI. For more information about unity UI dragging and dropping, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!