유니티 인벤토리 드래그 앤 드롭 기능 구현해보기

김보근·2025년 6월 9일

Unity

목록 보기
106/113

🎮유니티 인벤토리 드래그 앤 드롭 기능 구현해보기

오늘은 갑자기 게임 인벤토리에서 아이템을 드래그해서 다른 슬롯으로 옮기는 기능을 직접 구현해보고 싶어졌다.
많은 게임들에서 인벤토리 아이템을 마우스로 드래그해서 위치를 바꾸는 기능이 당연하게 들어가 있는데, 내가 직접 만들어 본 적은 없었다.
마침 ScriptableObject로 아이템을 만들어둔 게 있어서, 그걸 이용해서 간단한 드래그 앤 드롭 시스템을 구현해봤다.

📦 아이템 데이터 구조 (ScriptableObject)

아이템 하나하나를 ScriptableObject로 만들어 관리하도록 했다.
이렇게 하면 아이템 데이터를 에셋으로 따로 관리할 수 있어서 인스펙터에서 편하게 세팅할 수 있다.

[CreateAssetMenu(fileName = "Item", menuName = "ScriptableObject/ItemData")]
public class ItemData : ScriptableObject
{
    public enum ItemType { Melee, Range }

    [Header("Main Info")]
    public ItemType Type;
    public int itemId;
    public string itemName;
    public string itemDescription;
    public Sprite itemIcon;
}

🎯 목표

각 인벤토리 슬롯은 아이템 데이터를 보관하고 있어야 한다.

드래그를 시작하면 아이콘이 마우스를 따라다닌다.

드롭하면 두 슬롯의 아이템을 서로 교환한다.

🧩 InventorySlot.cs – 슬롯 로직

UI 상의 한 슬롯을 담당하는 스크립트를 작성했다. 이 스크립트는 드래그 이벤트를 처리하고 아이템 데이터를 바꿔주는 역할을 한다.

▸ 인터페이스 구현
유니티의 UI 이벤트를 감지하기 위해 다음 인터페이스들을 구현한다:

IBeginDragHandler, IDragHandler, IEndDragHandler: 드래그 관련 이벤트

IDropHandler: 드롭 이벤트 처리

// 유니티 UI 시스템과 이벤트 시스템 관련 네임스페이스
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

// 인벤토리 슬롯 하나를 담당하는 클래스
// 드래그 앤 드롭 이벤트를 처리하기 위해 여러 인터페이스를 구현
public class InventorySlot : MonoBehaviour, 
    IBeginDragHandler, IDragHandler, IEndDragHandler, IDropHandler
{
    // 슬롯에 표시될 아이템 아이콘 이미지
    public Image itemIcon;

    // 현재 슬롯에 저장된 아이템 데이터 (ScriptableObject)
    public ItemData itemData;

    // 드래그한 아이콘을 표시하기 위해 사용하는 Canvas 참조
    private Canvas canvas;

    // 드래그 중 생성되는 아이콘 오브젝트
    private GameObject draggingIcon;

    // 초기화: 상위에서 Canvas 컴포넌트를 찾아 저장하고, 슬롯 UI를 업데이트
    void Start() {
        canvas = GetComponentInParent<Canvas>();
        UpdateSlotUI();
    }

    // 아이템 데이터를 슬롯에 할당하고 UI도 갱신
    public void SetItem(ItemData newItem) {
        itemData = newItem;
        UpdateSlotUI();
    }

    // 슬롯 UI를 아이템 데이터에 맞춰 갱신
    private void UpdateSlotUI() {
        // 아이템이 있으면 아이콘 표시, 없으면 비활성화
        itemIcon.sprite = itemData ? itemData.itemIcon : null;
        itemIcon.enabled = itemData != null;
    }

    // 드래그 시작 시 호출: 아이템 아이콘이 따라다니도록 새 오브젝트 생성
    public void OnBeginDrag(PointerEventData eventData) {
        // 아이템이 없으면 드래그 안 함
        if (itemData == null) return;

        // 드래그 중 보일 아이콘 오브젝트 생성
        draggingIcon = new GameObject("Dragging Icon");
        draggingIcon.transform.SetParent(canvas.transform, false); // Canvas 하위에 생성

        // 아이콘 이미지 추가
        var img = draggingIcon.AddComponent<Image>();
        img.sprite = itemData.itemIcon;
        img.raycastTarget = false; // 드래그 중 raycast를 막지 않도록 설정

        // 드래그 아이콘 위치를 마우스 위치로 설정
        draggingIcon.transform.position = eventData.position;
    }

    // 드래그 중 호출: 드래그 아이콘이 마우스를 따라다니게 함
    public void OnDrag(PointerEventData eventData) {
        if (draggingIcon != null)
            draggingIcon.transform.position = eventData.position;
    }

    // 드래그 끝났을 때 호출: 드래그 아이콘 삭제
    public void OnEndDrag(PointerEventData eventData) {
        if (draggingIcon != null)
            Destroy(draggingIcon);
    }

    // 다른 슬롯 위에 드래그해서 드롭했을 때 호출
    public void OnDrop(PointerEventData eventData) {
        // 드래그된 오브젝트가 슬롯인지 확인
        var draggedSlot = eventData.pointerDrag?.GetComponent<InventorySlot>();

        // 다른 슬롯이면 아이템 교환
        if (draggedSlot != null && draggedSlot != this) {
            SwapItems(draggedSlot);
        }
    }

    // 두 슬롯의 아이템 데이터를 교환하는 함수
    private void SwapItems(InventorySlot otherSlot) {
        // 현재 슬롯의 아이템을 임시 저장
        var tempData = itemData;

        // 다른 슬롯의 아이템을 현재 슬롯에 설정
        SetItem(otherSlot.itemData);

        // 임시 저장한 아이템을 다른 슬롯에 설정
        otherSlot.SetItem(tempData);
    }
}

🧪 구현하면서 느낀 점

드래그 중 아이콘을 따로 생성해서 마우스를 따라다니게 하는 방식이 깔끔했다.

itemData == null 체크를 안 하면 빈 슬롯 드래그 시 오류가 생긴다.

드래그 중에는 raycastTarget = false로 설정해서 드롭 이벤트가 막히지 않도록 해야 했다.

아이템 간 교환은 SetItem()으로 간단하게 처리할 수 있었다.

📌 다음에 추가하고 싶은 기능

아이템 설명 툴팁 (hover 시 표시)

우클릭해서 아이템 사용하기

아이템 버리기 기능

장비 슬롯과 일반 슬롯 구분

✅ 마무리

사실 막상 해보니 생각보다 어렵진 않았고, 유니티 UI 이벤트 시스템만 잘 이해하면 쉽게 구현할 수 있었다.
다음엔 이걸 기반으로 장비 시스템이나, 인벤토리 저장/로드까지 확장해보고 싶다.
오늘은 여기까지!

profile
게임개발자꿈나무

0개의 댓글