Unity uGUI에서 image 나 button을 Drag and Drop 할 때
IBeginDragHandler, IDragHandler, IEndDragHandler 의 세가지 인터페이스를 이용 하여 쉽게 구현 가능 하다.
OnBeginDrag:
마우스 버튼이 클릭 되면
우선 화면에 따라다는 오브젝트를 생성 하고
( dragItemPrefab : 실제 옮겨질 대상이 아니고 이 것을 이용 해서 대상을 표현 하고
원래 대상은 그냥 보이는 상태로 하던지 안 보이게 하던지 하면 된다.
실제 대상을 이동 하게 하면 여러가지 생각 할 것이 많아 짐. )
OnDrag: 드래그 되고 있는 오브젝트를 마우스를 따라 다니게 하게 하면 된다.
이 때,
RectTransformUtility.ScreenPointToLocalPointInRectangle 을 사용 하여
마우스 포지션으로 부터 UI 오브젝트의 localPosition으로 변환 하여 적용 하면 쉽게 이동 시킬 수 있다.
Canvas.RenderMode 가 Screen Space - Overlay 일 경우 :
currentItem.transform.position = eventData.position;
로 해도 상관 없지만
Canvas.RenderMode 가 Screen Space - Camera 인 경우 :
eventData.position을 현재 캔버스에 맞게 변환 해서 사용 해야 한다.
Vector2 rectPosition = new();
RectTransformUtility.ScreenPointToLocalPointInRectangle(this.transform as RectTransform, mousePosition, canvas.worldCamera, out rectPosition);
참고)
Top Canvas 찾기 :
Unity Editor 말고 Script에서 UI가 적용 되고 있는 최상위 Canvas를 코드로 찾을 때 아래 메소드를 사용 한다.
transform.root.GetComponentInChildren<Canvas>();
var topCanvas = transform.root.GetComponentInChildren<Canvas>();
추가적으로 Canvas 프라퍼티 중에
canvas.isRootCanvas
canvas.rootCanvas
이런 것도 유용 할 수 있다.
OnEndDrag: 마우스 버튼이 해제 되면 이때 따라다니던 대체 오브젝트를 없애거나 안 보이게 하고
나머지 실제 원본 대상을 옮길지 말지 결정 하여 이동 처리 하면 된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class DragAndDrop : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public Canvas canvas;
public DragItem dragItemPrefab;
DragItem currentItem;
public void OnBeginDrag(PointerEventData eventData)
{
var enterObject = eventData.pointerEnter;
var rayResults = eventData.pointerCurrentRaycast;
CreateDragItem();
currentItem.Show(true);
MoveTo(currentItem.transform as RectTransform, eventData.position);
print($"{this.transform.name} OnBeginDrag : {eventData.pointerDrag.transform.name}: {eventData.position}");
print($"rayResults : {rayResults}");
}
public void OnDrag(PointerEventData eventData)
{
MoveTo(currentItem.transform as RectTransform, eventData.position);
print($"{this.transform.name} OnDrag : {eventData.pointerDrag.transform.name}: mouse {eventData.position}");
var rayResults = eventData.pointerCurrentRaycast;
print($"rayResults tag: {rayResults.gameObject.tag} : {rayResults.ToString()}");
}
public void OnEndDrag(PointerEventData eventData)
{
MoveTo(currentItem.transform as RectTransform, eventData.position);
DestroyDragItem();
print($"{this.transform.name} OnEndDrag : {eventData.pointerDrag.transform.name}: {eventData.position}");
}
void MoveTo(RectTransform rectItem, Vector2 mousePosition)
{
if( rectItem == null)
{
print("Drag RectTransfrom is Null");
return;
}
//RectTransformUtility.RectangleContainsScreenPoint()
Vector2 rectPosition = new();
RectTransformUtility.ScreenPointToLocalPointInRectangle(this.transform as RectTransform, mousePosition, canvas.worldCamera, out rectPosition);
//rectItem.anchoredPosition = rectPosition;
rectItem.localPosition = rectPosition;
print($"Rect Position {rectPosition}");
}
void CreateDragItem()
{
DestroyDragItem();
if (currentItem == null)
{
// rectTransform의 scale이 100이 안 되고 1이 되게 하려면 worldPositionStays = false여야 한다.
// Object Pool 로 변경 하자.
currentItem = Instantiate(dragItemPrefab, this.transform, false) as DragItem;
}
}
void DestroyDragItem()
{
if (currentItem != null)
{
// Object Pool 로 변경 하자.
Destroy(currentItem.gameObject);
currentItem = null;
}
}
}
'Unity3D' 카테고리의 다른 글
DLL 의존성 확인 | DLL dependency checking (0) | 2023.01.11 |
---|---|
[Unity] transform.root.GetComponentInChildren<Canvas>() | How do you get the parent canvas? (0) | 2022.12.24 |
Unity Shader.Find의 리턴값이 Null 일 경우 해결 (0) | 2022.10.14 |
유니티 에디터 로그 파일 위치 찾기 쉬운 방법 | Unity Editor Log File Location (0) | 2022.08.22 |
유니티에서 모두 재설치 해도 라이센스 활성화 안 될 때 해결 방법 (1) | 2022.07.25 |