Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

개발일기

유니티#20 인벤토리 UI, 클릭 핸들러 본문

Unity

유니티#20 인벤토리 UI, 클릭 핸들러

kimjw7815 2025. 5. 2. 15:14

인벤토리 슬롯은 24칸으로 늘려줬다. 8의 배수니까.

인벤토리 생성도 퀵슬롯과 거의 똑같이 해줬다. 단, 퀵슬롯에서는 slots가 RectTransform[]이었던 것에 반해, 인벤토리에서는 slots가 InventorySlot[]이었기 때문에, InventorySlot에 rectTransform 속성을 추가해주어 처리했다.

그리고 배치가 간단하고 수월했다. 극좌표계 저리가 절대좌표계 만세

중간에 클릭 핸들러라는 놈이 보일텐데, 저 놈이 오늘의 주인공이 될 녀석이다.

// Assets/Scripts/PlayerSystemManager/InventoryManager.cs
public class InventoryManager : MonoBehaviour
{
    void CreateInventory()
    {
        for (int i = 0; i < inventorySize.x * inventorySize.y; i++)
        {
            GameObject slot = Instantiate(inventoryPrefab, inventoryParent.transform);
            RectTransform rt = slot.GetComponent<RectTransform>();

            Vector2 pos = new Vector2(200 * (i % 8) - 700, -200 * (i / 8) + 200);
            rt.anchoredPosition = pos;

            slots[i].rectTransform = rt;

            // 클릭 핸들러 추가
            var clickHandler = slot.AddComponent<InventorySlotClickHandler>();
            clickHandler.slotIndex = i;
            clickHandler.inventoryManager = this;
        }
    }

    void UpdateInventory()
    {
        for (int i = 0; i < inventorySize.x * inventorySize.y; i++)
        {
            Image slotImage = slots[i].rectTransform.Find("Icon").GetComponent<Image>();
            if (slots[i].itemId != 0)
            {
                Item item = GetItemById(slots[i].itemId);
                if (item != null)
                {
                    slotImage.sprite = item.icon;
                    slotImage.enabled = true;
                }
            }
            else
            {
                slotImage.sprite = null;
                slotImage.enabled = false;
            }

            TextMeshProUGUI text = slots[i].rectTransform.Find("ItemQuantity").GetComponent<TextMeshProUGUI>();
            int quantity = slots[i].quantity;
            text.text = (quantity == 0 ? "" : $"{quantity}");
        }
    }
}
// Assets/Scripts/PlayerSystemManager/InventorySlotClickHandler.cs
using UnityEngine;
using UnityEngine.EventSystems;

public class InventorySlotClickHandler : MonoBehaviour, IPointerDownHandler, IPointerEnterHandler
{
    public int slotIndex;
    public InventoryManager inventoryManager;

    public void OnPointerDown(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            inventoryManager.fromSlotNum = slotIndex;
            inventoryManager.toSlotNum = slotIndex;
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        if (Input.GetMouseButton(0)) // 드래그 중일 때만
        {
            inventoryManager.toSlotNum = slotIndex;
        }
    }
}

구현해줘야 하는 기능은 마우스 드래그&드랍이다. 이 때, 바꿔야할 fromSlot과 toSlot의 정보를 저장해주고, 이 두 슬롯의 정보를 교환해줘야 한다. 또한, 마우스 버튼이 눌렸을 때 / 눌린 상태일 때 / 떼어졌을 때를 구분해서 처리해야 한다.

Unity Editor 상에서 Hierarchy의 Canvas에 컴포넌트로 Graphic Raycaster가 있고, 자식 오브젝트로 EventSystem이 있고, 누를 UI 대상의 Image 컴포넌트 속성 중 Raycas Target이 true이면 OnPointerDown, OnPointerEnter로 각 상황을 처리할 수 있다.

주석으로 달아둔 '클릭 핸들러 추가' 부분은 위의 해당 스크립트를 소환하는 각각의 오브젝트에 할당해주는 부분인 것이다.

그렇게 fromSlotNum과 toSlotNum이 확보가 된다면, 각 슬롯의 정보만 교환해주면 끝.

// Assets/Scripts/PlayerSystemManager/InventoryManager.cs
public class InventoryManager : MonoBehaviour
{
	void SwapItem(int fromNum, int toNum)
    {
        if (fromNum == toNum) return;

        // 아이템 정보만 교환
        int tempId = slots[fromNum].itemId;
        int tempQty = slots[fromNum].quantity;

        slots[fromNum].itemId = slots[toNum].itemId;
        slots[fromNum].quantity = slots[toNum].quantity;

        slots[toNum].itemId = tempId;
        slots[toNum].quantity = tempQty;

        // UI 업데이트
        UpdateInventory();
    }
}

 

여담) 내가 보기에 퀵슬롯이랑 인벤토리 코드 통합할 수 있을 것 같긴 한데 귀찮고 막 그르네

안 하는 게 나을 것 같기도