본문 바로가기
유니티 이야기

[Unity] UI Object Drag 하는 방법

by novices 2022. 9. 1.
반응형

게임을 즐기는 유저들의 자산은 골드나 다이아몬드 또는 착용하거나 사용할 수 있는 아이템으로 되어 있습니다. 이들 중 아이템은 화폐(골드, 다이아몬드 등)와는 다른 형태로 사용해야 하기 때문에 게임 제작자는 필연적으로 유저에게 아이템을 관리할 수 있는 시스템을 제공해야 합니다. 이러한 대표적인 시스템이 인벤토리 시스템이고 이런 인벤토리를 구현하려면 마우스나 터치로 UI 오브젝트를 이동하는 기능이 꼭 필요한데요. 이번 포스팅에서는 유니티에서 제공하는 이벤트 인터페이스로 UI Object 이동 예시를 작성해 보겠습니다.

 

 

1. UI 구성

UI는 아래 사진과 같이 구성되어 있습니다.

최상단 패널(MainPanel) > 인벤토리 패널(InventoryPanel) > 내부 패널(innerPanel) > 슬롯들

패널은 모드 UI > Panel로 만들어졌으며 슬롯들은 UI > Image로  생성했습니다.

 

UI와 하이어라키 화면 이미지
UI 구성

 

슬롯들은 InnerPanel에 그리드 레이아웃 그룹 컴포넌트를 추가하여 자식으로 있는 Slot 오브젝트들을 정렬했습니다.

 

Grid Layout Group 컨포넌트 추가 이미지
Grid Layout Group 추가

 

 

2. 스크립트 설명

IconDrag.cs (이동시킬 Icon오브젝트의 Drag 이벤트를 감지하여 Icon을 제어하는 기능)

Slot.cs (Icon오브젝트의 Drop 이벤트를 감지하여 슬롯 위에 고정시키는 기능)

 

IconDrag.cs

Icon에 컴포넌트로 추가될 스크립트입니다. 주 기능은 추가된 3개의 drag 이벤트를 통해 아이콘과 입력 장치의 포인터랑 이동을 연결하고 잘못된 이동을 했을 때 Icon을 drag 전 상태로 복원하는 코드입니다.

 

using UnityEngine;
using UnityEngine.EventSystems; // Drag관련 인터페이스 사용을 위함

// 드래그 시작, 드래그 중, 드래그가 끝날 이벤트 탐지를 위한 인퍼페이스 상속
public class IconDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    //드래그 될때 이동되는 아이콘을 담는 static 변수
    //static으로 선언하는 이유는 Drop이벤트를 가진 슬롯 스크립트에서 접근하기 위함
    public static GameObject beingDraggedIcon;

    // 슬롯이 아닌 다른 오브젝트에 Icon을 드랍할 경우 원복할 위치 백업용
    Vector3 startPosition;

    // Drag중 UI 레이어에 비정상적으로 보이기 때문에
    // Icon 드래그중 변경할 부모 RactTransfom 변수
    [SerializeField] Transform onDragParent;

    // 슬롯이 아닌 다른 오브젝트에 Icon을 드랍할 경우 원복할 부모 백업용
    [HideInInspector] public Transform startParent;

    // 인터페이스 IBeginDragHandler를 상속 받았을 때 구현해야하는 콜백함수
    public void OnBeginDrag(PointerEventData eventData)
    {
        // 드래그가 시작될때 대상 Icon의 게임오브젝트를 static 변수에 할당
        beingDraggedIcon = gameObject;

        // 백업용 포지션과 부모 트랜스폼을 백업 해둔다.
        startPosition = transform.position;
        startParent = transform.parent;

        // Drop이벤트를 정상적으로 감지하기 위해 Icon RectTransform을 무시 
        GetComponent<CanvasGroup>().blocksRaycasts = false;

        // 드래그 시작할때 부모transform을 변경
        transform.SetParent(onDragParent);
    }

    // 인터페이스 IDragHandler 상속 받았을 때 구현 해야하는 콜백함수
    public void OnDrag(PointerEventData eventData)
    {
        //드래그중에는 Icon을 마우스나 터치된 포인트의 위치로 이동시킨다.
        transform.position = Input.mousePosition;
    }

    // 인터페이스 IEndDragHandler 상속 받았을 때 구현 해야하는 콜백함수
    public void OnEndDrag(PointerEventData eventData)
    {
        // 드래그 대상을 지우고 해당 Icon에 이벤트감지를 허용한다.
        beingDraggedIcon = null;
        GetComponent<CanvasGroup>().blocksRaycasts = true;

        // 혹 드랍이벤트에 따라 부모가 변경되지 않고 
        // 이동중에 할당 되었던 부모 transform과 같다면
        // Icon의 부모와 위치를 원복한다.
        if(transform.parent == onDragParent)
        {
            transform.position = startPosition;
            transform.SetParent(startParent);
        }
    }
}

 

Slot.cs

UI 구성의 Slot 게임 오브젝트들에 추가될 스크립트입니다. 주 기능은 슬롯들의 transform영역 안에 포인트 드롭 이벤트가 발생할 때 빈 슬롯이면 자식으로 장착하는 기능입니다.  드롭 이벤트에 의해 drag 중인 Icon이 새로운 부모를 찾지 못한다면 IconDrag.cs의 OnEndDrag 함수 내에 작성된 원복 코드로 원래 있던 자리로 돌아가게 됩니다.

 

using UnityEngine;
using UnityEngine.EventSystems; // IDropHandler 상속을 위한
public class Slot : MonoBehaviour, IDropHandler // 드랍이벤트 감지를 위한 상속
{
    GameObject Icon()
    {
        // 슬롯에 아이템(자식 트랜스폼)이 있으면 아이템의 gameobject를 리턴
        // 슬롯에 아이템(자식 트랜스폼)이 없다면 null을 리턴
        if(transform.childCount > 0)
            return transform.GetChild(0).gameObject;
        else
            return null;
    }
    
    // IDropHandler 인터페이스 상속시 구현해야 되는 콜백 함수
    // 이 스크립트가 컨포넌트로 추가 된 게임 오브젝트 RactTransform내에
    // 포인터 드랍이 발생하면 실행되는 콜백함수
    public void OnDrop(PointerEventData eventData) 
    {
        // 슬롯이 비어있다면 Icon을 자식으로 추가 위치변경 함.
        if(Icon() == null)
        {
            IconDrag.beingDraggedIcon.transform.SetParent(transform);
            IconDrag.beingDraggedIcon.transform.position = transform.position;
        }
    }
}

 

 

3. 테스트용 Icon 만들기

이 포스팅에서는 Item에 대한 데이터를 다루지 않아서 Icon라 표기하지만 사실 아이템에 해당되는 부분입니다. 첫 번째 슬롯에 UI > Image 오브젝트를 생성하고 "Icon"이라 이름을 변경하였습니다. 아이콘으로 표시될 별 이미지는 sprite에 할당하였고 IconDrag 컨포넌트에는 드래그 중 변경될 부모 transform을 참조하였습니다. 마지막으로 Canvas Group컨포넌트를 추가합니다. Canvas Group의 존재 이유는 드래그 중 포인터의 감지를 차단하는 Icon을 무시하기 위함입니다.

 

Icon 구성 및 설정 방법 이미지
Icon 구성 화면

 

 

4.  실행 결과

인벤토리의 이동 기능 또는 재미있는 머지 게임에도 활용이 가능할 것 같습니다. 다음에는 이번 포스팅을 확장해서 아이템을 병합하는 내용을 작성해 보겠습니다.

 

실행결과 gif
실행 결과

 

 

반응형

댓글