Unity에서 3D 게임을 만들다 보면 3D GameObject를 컴퓨터의 경우 마우스, 모바일의 경우 손가락으로 자유롭게 Drag & Drop 하여 원하는 위치에 놓는 기능이 필요할때가 있다
위에서 서술한 기능을 나는 아래와 같이 구현하였다
https://www.youtube.com/shorts/H-rxX2ozjUE
우선 클릭 또는 터치 했을때 내가 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] PostProcessing (0) | 2024.07.11 |
---|---|
[Unity] Animator Component의 Root Motion 이란? (0) | 2024.07.10 |
Unity Design Pattern - Object Pool (2) | 2024.06.03 |
유니티 3D Model 파괴 효과 만들기 (0) | 2024.02.26 |
Unity Android Plugin 만들기 (2) | 2024.01.28 |