(유니티) 창고 아이템 옮기기 기능

티원·2025년 11월 10일

UI창고 드래그드랍 시연 영상
플레이어의 인벤토리와 창고 사이에 아이템을 옮긴다면

유니티에서 제공하는 EventSystems 에서 제공하는 인터페이스를 써서 실습

코드

  1. 드래그가능한장소(Panel)에 넣는 스크립트
public class DropZone : MonoBehaviour, IDropHandler
{
    public void OnDrop(PointerEventData eventData)
    {
        //온 드롭이 발동되었을때 마우스 드래깅 중인 컨텐츠가 존재했다면
        if(eventData.pointerDrag != null)
        {
            //드래그중이던 대상의 부모를 이거로 바꾼다
            eventData.pointerDrag.transform.SetParent(transform);
        }
    }
}
  1. 드래그하는 이미지에 넣는 스크립트
public class DragableImage : MonoBehaviour, IBeginDragHandler, IDragHandler,IEndDragHandler
{
    //드래깅을 당할 수 있는 모든 UI오브젝트들이 들고 있을 내용
    //원래라면 EventSystem에서 UI인지 체크하거나 레이 쏴서 UI 확인하는? 어려운 과정이 필요하지만 정의된 인터페이스 사용
    //드래깅 3가지 스탭을 위해 인터페이스 추가. 드래깅 시작, 드래깅 중, 드래그 종료 ,IBeginDragHandler 등 

    private Transform originalParent; //원래 부모 패널
    private Image image;
    private CanvasGroup canvasGroup;
    [SerializeField] GameObject cubePrefab; //인스펙터로 넣어줄 프리팹

    private void Start()
    {
        image = GetComponent<Image>(); //드래그중에 이미지 색상을 바꾼다던가 가능(코드에는 없음)
        canvasGroup = gameObject.AddComponent<CanvasGroup>(); //컴포넌트 코드로 추가, 물론 미리 추가해놓고 가져와도 됨
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        //1. 원래 부모를 기억
        originalParent = transform.parent;
        //2. 위에서 기억 미리 해놨으니 이제 집을 나온다. 최상위 계층으로 이동(드래그 원활하게 해줌)
        transform.SetParent(originalParent.root); //최상위 계층인 Canvas를 부모로 적용
        //3. 드래깅 중인 이미지를 반투명
        canvasGroup.alpha = 0.5f;
        //4. 레이케스트 블라킹을 끔 //드롭 영역 감지가 원활하도록, 자기자신 감지가 잘되도록
        canvasGroup.blocksRaycasts = false; //드롭 영역 감지가 수월하도록
    }

    //드래그 중일땐, 위치정보 등 드래깅에 필요한 모든 정보가 eventData에 들어있음
    public void OnDrag(PointerEventData eventData)
    {
        transform.position = eventData.position; //마우스 위치로 따라감
    }
    //마우스 떼버리면? 
    public void OnEndDrag(PointerEventData eventData)
    {
        // 패널에 놓기,이미지남기기, 아니면 돌아간다
        canvasGroup.alpha = 1f; //반투명 이미지 원복
        canvasGroup.blocksRaycasts = true; //다시 감지 가능하게

        /*
        //아래코드 주석 해제하면 드래그한 오브젝트 위치에 게임오브젝트 생성함
        if(!IsDroppedOnUI(eventData))
        {
            SpawnCubeAtMoustPosition();
            Destroy(gameObject); //이건 만약 UI 이미지 없애버릴거면
        }
        else
        {
            transform.SetParent(originalParent);
        }
        */
        
        //드롭이 감지되지 않았다면 원래 위치로 복귀 
        //조건에 맞으면 변경하는 코드는 DropZone.cs에서 함
        if(transform.parent == originalParent.root)
        {
            transform.SetParent(originalParent);
        }
        
    }

    //UI에 드롭시켰는지 판단할 메서드
    private bool IsDroppedOnUI(PointerEventData eventData)
    {
        //포인터엔터는 (터치 혹은) 마우스가 닿아있는 UI 오브젝트를 가리킴
        //드롭 시점에 마우스가 UI위에 있다면 그 UI의 게임오브젝트가 담기고
        //아무 UI위에 없으면 널이 담김
        return eventData.pointerEnter != null &&
            eventData.pointerEnter.transform.IsChildOf(originalParent.root);
    }
    private void SpawnCubeAtMoustPosition()
    {
        Vector2 mousePos = Mouse.current.position.ReadValue(); //마우스 위치 받아올 수 있음 (유니티6)
        Ray ray = Camera.main.ScreenPointToRay(mousePos);
        RaycastHit hit;
        if(Physics.Raycast(ray, out hit))
        {
            Instantiate(cubePrefab,hit.point,Quaternion.identity);
        }
    }
}

PointerEventData 클래스

유니티엔진에서 사용되는 UnityEngine.EventSystems 클래스중 하나
UI요소에 대한 포인터(moust/touch) 입력 관련 정보를 처리하기위해 사용

if(eventData.pointerDrag != null) //드래그 상태였다면
transform.position = eventData.position; //마우스 위치로 따라감
eventData.pointerEnter //포인터가 어떤 UI요소 안으로 진입 하였는지
eventData.pointerEnter.transform //해당 요소에 접근하는듯

마우스 이벤트 순서와 종류

  1. IPointerDown : 마우스 버튼 누름
  2. IBeginDragHandler : 드래그 시작
  3. IDragHandler : 드래그 진행
  4. IPointerUp : 마우스 버튼 떼기
  5. IEndDragHandler : 드래그 종료
  6. IDropHandler : 드롭 대상 처리

필요한 오브젝트와 스크립트

  1. 이미지
  2. 이미지를 넣을 장소 (Panel)

이미지에는 C#스크립트로 IBeginDragHandler, IDragHandler, IEndDragHandler 를 상속받는 스크립트 정의
드래그 시작, 드래그중, 드래그 끝을 체크하는 메서드를 상속받아서 코드를 작성한다

이미지를 넣을 Panel에는 IDropHandler 를 상속받는 스크립트 정의
마우스를 놓았을때 Panel끼리 해당 이미지를 넣을 수 있도록 한다
패널에 Grid Layout Group을 넣어서 이미지가 정렬될 수 있게끔 (스크립트로도 가능하긴 함)

0개의 댓글