ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Unity 3D Object Drag & Drop
    Unity 2024. 6. 4. 09:00

    Unity에서 3D 게임을 만들다 보면 3D GameObject를 컴퓨터의 경우 마우스, 모바일의 경우 손가락으로 자유롭게 Drag & Drop 하여 원하는 위치에 놓는 기능이 필요할때가 있다

     

    위에서 서술한 기능을 나는 아래와 같이 구현하였다

     

    https://www.youtube.com/shorts/H-rxX2ozjUE

    3D Object Drag & Drop

     

     

    우선 클릭 또는 터치 했을때 내가 Drag & Drop 하고자 하는 GameObject인지 구분부터 해야한다.

    private GameObject OnClickObjUsingTag(string tag)
    {
        Vector3 touchPos = new Vector3(0, 0, 0);
    
    #if UNITY_EDITOR
        touchPos = Input.mousePosition;
    #else
        touchPos = Input.GetTouch(0).position;
    #endif
    
        Ray ray = Camera.main.ScreenPointToRay(touchPos);
        RaycastHit hitInfo;
        Physics.Raycast(ray, out hitInfo);
    
        if (hitInfo.collider != null)
        {
            GameObject hitObject = hitInfo.collider.gameObject;
            if (hitObject != null)
            {
                if (hitObject.gameObject.tag.Equals(tag))
                {
                    return hitObject;
                }
            }
        }
    
        return null;
    }

     

    내가 터치한 위치로부터 Camera.main.ScreenPointToRay 함수를 사용해 Ray를 발사하여 Ray에 맞은 GameObject가 내가 이동시키고자 하는 GameObject인지 확인한다.

    private void TouchMovedEvent()
    {
        if (_movableObj != null)
        {
            Vector3 touchPos = Vector3.zero;
    #if UNITY_EDITOR
            touchPos = Input.mousePosition;
    #else
            touchPos = Input.GetTouch(0).position;
    #endif
            Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3(touchPos.x, touchPos.y, 10));
    
            //_movableObj.transform.position = worldPos;
            _movableObj.transform.position = Vector3.MoveTowards(_movableObj.transform.position, worldPos, Time.deltaTime * 20f);
        }
    }

    내가 이동시키려고 한 GameObject가 맞다면 내가 드래그 하는 동안 해당 GameObject를 내가 터치한 위치를 World Position으로 변환시킨(Camera.main.ScreenToWorldPoint 함수) 좌표값으로 이동시킨다

     

    private void TouchEndedEvent()
    {
        if (_movableObj != null)
        {
            Ray ray = new Ray(_movableObj.transform.position, Camera.main.transform.forward);
    
            RaycastHit hitInfo;
            Physics.Raycast(ray, out hitInfo);
    
            if (hitInfo.collider != null)
            {
                Debug.Log("hit info : " + hitInfo.collider.gameObject.name);
                _movableObj.transform.position = hitInfo.collider.gameObject.transform.position;
                _movableObj.transform.position += _offset;
            }
            else
            {
                _movableObj.transform.position = _beforePosition;
            }
        }
    }

    손가락을 땠을때는 Drag 되고 있든 GameObject로부터 Camera z 방향(forward)으로 Ray를 발사하여 그 Ray에 닿은 위치로 해당 게임오브젝트를 이동시킨다

     

     

    전체코드

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    namespace UnityStudy.DragDrop
    {
        public class TouchManager : MonoBehaviour
        {
            private Vector2 _lastTouchPos = Vector2.zero;
            private Vector2 _currentTouchPos = Vector2.zero;
            private Vector3 _prePos = Vector3.zero;
    
            private Vector3 _beforePosition;
            private Vector3 _offset = new Vector3(0.0f, 1.0f, 0.0f);
    
            [SerializeField] private GameObject _movableObj;
    
            private const string _moveableTAG = "Moveable";
    
    
            private void Update()
            {
    #if UNITY_EDITOR
                _lastTouchPos = _currentTouchPos;
                _currentTouchPos = Input.mousePosition;
    
                if (Input.GetMouseButtonDown(0))
                {
                    TouchBeganEvent();
                    _prePos = Input.mousePosition;
                }
    
                if (Input.GetMouseButton(0))
                {
                    if (Input.mousePosition != _prePos) { TouchMovedEvent(); }
                    else { TouchStayEvent(); }
                }
    
                if (Input.GetMouseButtonUp(0))
                {
                    TouchEndedEvent();
                }
    #else
                // Multi-touch 방지 
                if (Input.touchCount <= 0) { return; }
    
                Touch touchInfo = Input.GetTouch(0);
                _lastTouchPos = _currentTouchPos;
                _currentTouchPos = touchInfo.position;
    
                switch (touchInfo.phase)
                {
                    case TouchPhase.Began:
                        TouchBeganEvent();
                        break;
    
                    case TouchPhase.Moved:
                        TouchMovedEvent();
                        break;
    
                    case TouchPhase.Stationary:
                        TouchStayEvent();
                        break;
    
                    case TouchPhase.Ended:
                        TouchEndedEvent();
                        break;
                }
    #endif
    
    #if UNITY_EDITOR
                // 캐릭터 Ray 확인용 
                if (_movableObj != null)
                {
                    Ray ray = new Ray(_movableObj.transform.position, Camera.main.transform.forward);
                    Debug.DrawRay(ray.origin, ray.direction * 1000, Color.red);
                }
    
    
                // TEST Code
                Vector3 touchPos = new Vector3(0, 0, 0);
    
    #if UNITY_EDITOR
                touchPos = Input.mousePosition;
    #else
                touchPos = Input.GetTouch(0).position;
    #endif
    
                Ray test_ray = Camera.main.ScreenPointToRay(touchPos);
    
                Debug.DrawRay(test_ray.origin, test_ray.direction * 1000, Color.blue);
    
    #endif
            }
    
            private void TouchBeganEvent()
            {
                _movableObj = OnClickObjUsingTag(_moveableTAG);
    
                if (_movableObj != null)
                {
                    _beforePosition = _movableObj.transform.position;
                }
            }
    
            private void TouchMovedEvent()
            {
                if (_movableObj != null)
                {
                    Vector3 touchPos = Vector3.zero;
    #if UNITY_EDITOR
                    touchPos = Input.mousePosition;
    #else
                    touchPos = Input.GetTouch(0).position;
    #endif
                    Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3(touchPos.x, touchPos.y, 10));
    
                    //_movableObj.transform.position = worldPos;
                    _movableObj.transform.position = Vector3.MoveTowards(_movableObj.transform.position, worldPos, Time.deltaTime * 20f);
                }
            }
    
            private void TouchStayEvent()
            {
    
            }
    
            private void TouchEndedEvent()
            {
                if (_movableObj != null)
                {
                    Ray ray = new Ray(_movableObj.transform.position, Camera.main.transform.forward);
    
                    RaycastHit hitInfo;
                    Physics.Raycast(ray, out hitInfo);
    
                    if (hitInfo.collider != null)
                    {
                        Debug.Log("hit info : " + hitInfo.collider.gameObject.name);
                        _movableObj.transform.position = hitInfo.collider.gameObject.transform.position;
                        _movableObj.transform.position += _offset;
                    }
                    else
                    {
                        _movableObj.transform.position = _beforePosition;
                    }
                }
    
                //_movableObj = null;
            }
    
            private GameObject OnClickObjUsingTag(string tag)
            {
                Vector3 touchPos = new Vector3(0, 0, 0);
    
    #if UNITY_EDITOR
                touchPos = Input.mousePosition;
    #else
                touchPos = Input.GetTouch(0).position;
    #endif
    
                Ray ray = Camera.main.ScreenPointToRay(touchPos);
                RaycastHit hitInfo;
                Physics.Raycast(ray, out hitInfo);
    
                if (hitInfo.collider != null)
                {
                    GameObject hitObject = hitInfo.collider.gameObject;
                    if (hitObject != null)
                    {
                        if (hitObject.gameObject.tag.Equals(tag))
                        {
                            return hitObject;
                        }
                    }
                }
    
                return null;
            }
        }
    }

    'Unity' 카테고리의 다른 글

    Unity Design Pattern - Object Pool  (2) 2024.06.03
    유니티 3D Model 파괴 효과 만들기  (0) 2024.02.26
    Unity Android Plugin 만들기  (2) 2024.01.28
    Mac에서의 classes.jar 위치  (0) 2021.10.31
    [Unity] Animator Animation 재시작 방법  (0) 2021.10.29

    댓글

Designed by Tistory.