인벤토리 만들기 3 (작성중)

Tom·2024년 11월 11일
0

같은 종류의 아이템을 여러개 획득하면 보통 슬롯 하나에 배정하고 보유중인 갯수를 숫자로 알려준다. 각각의 아이템이 하나의 슬롯을 차지하고있으면 포션같은 소모품을 표시하는데에 쓸데없이 낭비되는 슬롯이 엄청 많아질거니까.그래서 같은 아이템을 획득하는 시점에 이미 인벤토리에 같은 아이템이 있는지를 확인하고 이미 존재한다면 새로 슬롯에 아이템을 배정하는것이 아닌 원래 있던 슬롯 아이템의 갯수를 늘려주는 기능을 추가해봤다.

보유아이템 갯수를 보여주는 인벤토리

일단 기존 인벤토리 아이템 프리펩 우하단에 현재 보유중인 수량을 알려줄 텍스트를 추가했다. 그리고 인벤토리에 아이템을 추가하는 시점에 인벤토리에 리스트나 해시맵에 이미 존재하는 아이템인지 판별하고 저 숫자를 올려주기만 하면 될 것 같다.

일단 지금 만들어져있는 인벤토리의 기능을 살펴보니 같은 ID의 아이템이 인벤토리에 추가되었을때 분별하기 위해 ID에 인벤토리에 추가된 시점을 더해 유니크한 아이디를 만들어서 사용하고 있다. 근데 같은 아이템은 그냥 한 인벤토리칸에서 처리할 예정이니 이 기능은 필요가 없어져 따로 빼놓기로 했다. 그리고 같은 종류의 아이템은 동일한 ID를 공유할테니 ID와 수량을 매핑한 딕셔너리을 사용하면 쉽게 아이템 리스트를 관리할 수 있을듯.

이라고 생각했는데 현재 인벤토리 구조가 인벤토리 -> 슬롯 -> 아이템의 구조로 되어있고 인벤토리에서 어떤 슬롯에 어떤 아이템을 가지고 있는지 확인할 방법이 없어서 확인하려고 매핑을 두번이나 해줘야했다. 딕셔너리를 두개나 썼음...
계획대로 동작하게 만드는데에는 성공했으나

	private Dictionary<Item, InventoryItem> itemInventoryMap = new Dictionary<Item, InventoryItem>();
	private Dictionary<InventoryItem, int> inventoryQuantityMap = new Dictionary<InventoryItem, int>();
    public void AddItemToInventoryByID(int itemId)
    {
        Item newItem = ItemManager.Instance.GetItemById(itemId);
        if (itemInventoryMap.ContainsKey(newItem))
        {
            InventoryItem existingItem = itemInventoryMap[newItem];

            existingItem.SetItemCount(++inventoryQuantityMap[existingItem]);
        }
        else
        {
            InventorySlot firstEmptySlot = FindFirstEmptySlot();

            if (firstEmptySlot == null)
            {
                Debug.Log("인벤토리가 꽉찻슴.");
                return;
            }

            GameObject instantiatedItem = Instantiate(inventoryItemPrefab);
            InventoryItem inventoryItem = instantiatedItem.GetComponent<InventoryItem>();

            if (inventoryItem != null)
            {
                inventoryItem.SetItem(newItem);
                instantiatedItem.transform.SetParent(firstEmptySlot.transform);
                instantiatedItem.transform.localPosition = Vector3.zero;

                itemInventoryMap[newItem] = inventoryItem;
                inventoryQuantityMap[inventoryItem] = 1;
            }
        }
    }

아이템을 인벤토리아이템에 매핑하고, 또 그걸 개수에 매핑하는 더러운 구조가 되어버렸다. 슬롯에서 아이템 갯수 관리를 하면 좀 더 깨끗해질까? 분명 뭔가 구조가 잘못되었어.

의존성은 아래에서 위로 흐르면 안된다

인벤토리 아이템의 코드를 다시 살펴봤다. 모든 아이템은 소속되어있는 인벤토리를 알고있고, 드래그 종료시에 인벤토리의 현재 포인터가 가리키는 슬롯으로 부모를 변경하게 된다. 인벤토리 아이템이 상위 시스템을 알고 있다는거고, 인벤토리가 수정될 때마다 아이템의 구조도 변경이 필요한 복잡한 구조였던 것이다. 스왑도 아이템 자체에서 해줄 게 아니라 상위 레벨에서 해줘야 하는 작업이었는데 너무 늦게 깨달아버림. 그래서 이벤트 기반으로 인벤토리 아이템을 수정해봤다.

using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class InventoryItem : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler
{
    [SerializeField] private Item item;
    [SerializeField] private Image image;

    [SerializeField] private bool isDragging = false;
    //[SerializeField] private Inventory inventory; 너가 이걸 왜 알아야돼
    //[SerializeField] private InventorySlot prevSlot; 이것도 인벤토리 레벨에서 관리
    [SerializeField] private int itemCount = 1;
    [SerializeField] private TextMeshProUGUI itemCountText; 

    private void Start()
    {
        //inventory = GetComponentInParent<Inventory>();
        image.sprite = Resources.Load<Sprite>($"Test/{item.name}");
        itemCountText.gameObject.SetActive( false );
    }


    public void OnBeginDrag(PointerEventData eventData)
    {
        isDragging = true;
        image.raycastTarget = false;
        //prevSlot = transform.GetComponentInParent<InventorySlot>();
        //transform.SetParent(inventory.hoveringItemTransform);
    }

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

    public void OnEndDrag(PointerEventData eventData)
    {
        onEndDrag?.Invoke(this);
        isDragging = false;
        image.raycastTarget = true;

        //if (inventory.currentPointingSlot != null)
        //{
        //    InventorySlot currentSlot;
        //    currentSlot = inventory.currentPointingSlot;

        //    if (!currentSlot.IsEmpty)
        //    {
        //        SwapItem(prevSlot, currentSlot);
        //    }

        //    transform.SetParent(currentSlot.transform);
        //}
        //else
        //{
        //    transform.SetParent(prevSlot.transform);
        //}
        //transform.localPosition = Vector3.zero;
    }
    public void SetItem(Item _item)
    {
        this.item = _item;
    }

    private void SwapItem(InventorySlot prevSlot, InventorySlot nextSlot)
    {
        InventoryItem otherItem = nextSlot.transform.GetComponentInChildren<InventoryItem>();

        if (otherItem != null)
        {
            otherItem.transform.SetParent(prevSlot.transform);
            otherItem.transform.localPosition = Vector3.zero;
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        ItemUIData itemUIData = new ItemUIData(item.name, item.description);
        UIManager.Instance.OpenUI<ItemUI>(itemUIData);
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.GetCurrentUI().CloseUI();
    }
}

일단 부모를 아이템 자체에서 설정해주는 부분을 모두 덜어냈음. 이제 아이템은 드래그시 이동만 수행한다.

profile
여기 글은 보통 틀린 경우가 많음

0개의 댓글

관련 채용 정보