본문 바로가기
유니티/팁, 정보 노트

[Unity]EventSystem을 이용해 아이템UI 드래그 및 다른 슬롯에 등록하기(IDragHandler, IDropHandler)

by 개발펭귄 2019. 9. 27.

여러 방법이 있지만 이게 가장 간단한 방법 같아서 정리한다.

아이템 사용 이런거는 없고 단수

 

  • 드래그, 드랍할 UI오브젝트에 Drag관련 인터페이스가 포함된 스크립트를 추가

 

예시)

public class ItemDragHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler

 

그리고 인터페이스에 해당하는 함수를 구현해주면 된다.

 

드래그해서 마우스를 따라다니게 하고 싶으므로 IDragHandler의 OnDrag함수를 구현해주면 된다.

예)

public void OnDrag(PointerEventData eventData)
{
    transform.position = eventData.position;
}

참고로 eventData.position 말고 Input.mousePosition 을 써도 된다.

아이템을 놓았을 때 제자리로 돌아가게 하고 싶다하면 IEndDragHandler의 OnEndDrag를 처리해주면 된다.

 

 

  • UI 가려질 때

위 예시 이미지와는 다르게 움직이면 다른 UI에 가려진다.

UI의 hierarchy 때문에 발생하는 문젠데 방법은 여러가지 있다.

1. 코드상에서 setsibling 같은 함수를 이용해 순서를 정해주는 방법

2. 캔버스를 여러개 두어 캔버스 간의 order를 정해놓는 것

3. 해당 오브젝트를 드래그할때만 Canvas 바로 아래의 자식으로 놓는 방법

 

여기서 나는 3번을 택해서 작업했다.

 

예시)

public void OnBeginDrag(PointerEventData eventData)
{
    _startParent = transform.parent;
    transform.SetParent(GameObject.FindGameObjectWithTag("UI Canvas").transform);
}

 

이런식으로 놓고 드래그가 끝날 때는 다시 원래대로 돌려주는 것을 잊지말자.

 

public void OnEndDrag(PointerEventData eventData)
{
    transform.SetParent(_startParent);
    transform.localPosition = Vector3.zero;
}

 

  • OnDrop 이벤트 발생안할 때(못 받을 때)

위처럼 하고나면 몇몇 UI에는 OnDrop 이벤트가 발생하지 않을 것이다.

결론부터 말하면 Raycast 문제다.

드래그하고 있는 오브젝트를 Canvas 바로 밑으로 올려 해당 오브젝트보다 하위에 존재하는 UI들이 반응하지 않는다.

 

흰색이 드래그 되고 있는 UI 오브젝트고 갈색이 OnDrop 이벤트를 받을 오브젝트다.

위 사진은 발생이 안되는 경우로 흰색이 갈색보다 위에 있어서 안된다.

 

흰색이 갈색보다 아래에 있을 때는 된다.

 

 

UI관련된 그래픽 컴포넌트들은 GraphicRaycast라고 따로 받는 레이캐스트가 존재한다.

UI관련 오브젝트(예를 들면 Image)에 raycastTarget이라고 적힌 옵션이 있을 것이다.

이걸 에디터에서 바로 꺼주면 드래그가 안되니 코드 상에서 잠시 꺼주면 된다.

 

1. 드래그 시작 -> 해당 그래픽 컴포넌트 raycast 꺼주기

2. 드래그 끝났을 때 -> 다시 raycast 켜주기

 

이러한 방식이 맘에 들지 않는다면 직접 GraphciRaycaster를 이용해 우리가 3d게임에서 raycast로 오브젝트를 검출하듯이 똑같이 UI도 태그나 다양한 방식을 이용해 검출해서 사용하면 된다.

 

나는 전자를 선택해 이렇게 했다.

예시)

public void OnBeginDrag(PointerEventData eventData)
{
    _itemBeingDragged = gameObject.GetComponentInParent().GetItem();
    _startParent = transform.parent;
    transform.SetParent(GameObject.FindGameObjectWithTag("UI Canvas").transform);
    GetComponent().raycastTarget = false;
}

 

public void OnEndDrag(PointerEventData eventData)
{
    transform.SetParent(_startParent);
    transform.localPosition = Vector3.zero;
    _itemBeingDragged = null;
    GetComponent().raycastTarget = true;
}

 

  • 다른 슬롯에서 OnDrop 구현

OnDrop 이벤트를 받을 다른 슬롯창에서 구현해주면 된다. 

참고로 Drag할 아이템은 하나여서 관련 클래스쪽에서 static으로 선언했다. (public static Item _itemBeingDragged;)

 

다른 슬롯의 코드 예시다.

예시)

public Image _icon;
public void OnDrop(PointerEventData eventData)
{
    var item = ItemDragHandler._itemBeingDragged;
    if (item != null)
    {
    _icon.sprite = item.icon;
    _icon.enabled = true;
    }
}

 

결과 이미지

 

프로젝트 소스는 github에서 확인 가능하다.

https://github.com/AntarticPenguin/ProjectF/tree/master/Assets/01.Scripts/Item

 

AntarticPenguin/ProjectF

Contribute to AntarticPenguin/ProjectF development by creating an account on GitHub.

github.com

틀린 부분 지적은 언제나 환영입니다.