본문 바로가기

팀프로젝트

[03] 인벤토리 기능

인벤토리에는 무슨 기능이 있어야 할까?

그걸 떠올리기 위해 특정 상황을 생각해보자. 가장 먼저 흔한 상황은 아이템을 획득하는 상황이다.

 

아이템을 획득하면, 인벤토리의 빈 슬롯에 아이템이 들어가서 자리잡게 된다. 그렇다면 인벤토리는 슬롯이 비어있는지 확인하는 기능이 필요할 것이고, 슬롯에 아이템을 추가하는 기능이 필요하다. 

 

그러니 가장 먼저 떠오르는 인벤토리의 기능으로는 두가지가 있다.

1. 슬롯이 비어있는지 확인

2. 슬롯에 아이템을 추가.

 

슬롯이 비어있는지 확인하는 것은 간단하다. 우리는 인벤토리를 List<ItemSlot>으로 구성했으므로, 인벤토리 길이만큼 돌면서 슬롯에 있는 아이템의 ID를 확인해보면 된다. 

이렇게 하면 비어있는 것 말고도 특정 아이템이 있는지, 있다면 어느 위치에 있는지에 대한 정보를 알 수 있다. 이것을 FindItem()라고 하자.

 

그러면 다음은 슬롯에 아이템을 추가하는 것인데, 이건 다소 복잡하다. 경우가 나뉘어져 있기 때문이다. 빈 슬롯이라면 기[02]에서 만들었던 슬롯의 SetItem을 사용하면 금방 되지만, 이미 같은 아이템이 인벤토리에 있을 경우와 인벤토리가 꽉 차 있을 경우가 있다.

 

그러니 여기서는 순서도를 한 번 그려보자.

땅에 있는 아이템을 주웠을 때, 위와 같은 판정으로 아이템이 인벤토리에서 어떻게 동작하는지 확인되는 것이다. 동일한 아이템인지 확인하는 것은 FindItem으로 한다지만, 중첩해서 들고다닐 수 있는 지 아닌 지는 아이템 데이터 베이스에서 따로 읽어올 필요가 있겠다.

또 수량 증가만 하는 경우도 있으니 ItemSlot에 Amount만 증가시키는 함수를 따로 만들어주자.

 

이것으로 아이템을 획득하는 경우는 끝. 그런데 획득하는 경우가 있다면 버리는 경우도 당연히 있어야한다. 보통은 버린다-는 개념보다는 Drop, 땅에 떨어트린다는 것이 일반적이다.

 

하지만 일단은... 게임 내에서 아이템을 버릴 일이 생길지 안 생길지 모르므로 선언만 해놓도록 하자.

public class Inventory : MonoBehaviour
{
    [HideInInspector]
    public List<ItemSlot> InventorySlots;
    [SerializeField]
    private GameObject inventorySlotPrefab;
    [SerializeField]
    private int inventorySize;
    
    public void InitializeInventory()
    {
    }
    //특정 ID 아이템 획득
    public virtual void AddItem(int itemID, int amount)
    {
    }
    public virtual void RemoveItem(int index, int amount)
    {
    }
    //ID로 검색해서 아이템 위치(index) 반환, 0으로 검색하면 빈칸찾기. -1 반환은 같은게 없다.
    public virtual int FindItem(int itemID)
    {
    }
    public int FindItemAmountWithIndex(int index)
    {
    }
}

그렇게 총 정리를 하면, 인벤토리 슬롯을 가지고 있는 인벤토리는

초기화, 아이템 줍기, 아이템 지우기, 아이템 위치 찾기, 위치 기반 아이템 수량 찾기를 가지고 있게된다.

 

그 다음으로는 아이템과, 아이템 슬롯이다.

아이템이 필드에 떨어져 있는(물체로 구현된 상태)와 슬롯에 들어가 있는 상태는 서로 다르다. 우선은 인벤토리에 들어가 있는 아이템 슬롯을 이야기하자.

 

아이템이 슬롯에 들어가 있을 때의 정보(데이터 베이스에서 읽어와서 저장할 것)이 어떻게 되는가?

1. 아이템 ID와 이름

2. 아이템 아이콘

3. 한 슬롯에 아이템 겹칠 수 있는지

4. 아이템 수량 

5. 마우스를 올려놨을 때 나오는 아이템 설명이 있다.

 

이 같은 정보들을 아이템 슬롯이 가진다. 필드에 있는 아이템을 주웠을 때, ID를 읽어와서 아이템 데이터베이스를 기반으로 슬롯을 세팅하는 것이다.

    public int itemID;
    public string itemName;
    public string itemDescription;
    public int itemAmount;
    public Image itemIcon;
    public bool canCount;

그 다음은 아이템의 종류에 상관없이 슬롯으로서 하는 기능이다. 

슬롯에 마우스를 올려놨을 때 나오는 설명. 이것은 마우스 포인터 이벤트에 관련되어 있다. IPointerEnterHandler와 IPointerExitHandler를 통해 마우스가 슬롯에 들어오면 설명을 띄우고, 나가면 설명창을 지우는 것이다.

 

그리고 또 무엇이 필요할까? 바로 인벤토리의 슬롯 간 위치 교체가 필요하다. 드래그를 통해 아이템의 위치를 원하는 대로 정렬할 수 있어야한다. 그러기 위해서 드래그를 관장하는 IBeginDragHandler, IEndDragHandler, IDragHandler가 필요하다.

 

그 다음은 아이템 버리기. 위에서 Item을 Remove하는 것만 명시해놓았는데, 우클릭을 통해 아이템 슬롯 -> 아이템 과정을 거쳐서 소환할 예정이다. 우클릭을 통해 아이템을 버릴 예정이니 IPointerClickHandler역시 필요하다.

 

그래서 아이템 슬롯은 다음과 같이 속성을 상속받는다.

public class ItemSlot : MonoBehaviour, IPointerEnterHandler, 
    IPointerExitHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IPointerClickHandler

 

그 다음은 바로 아이템.

아이템->슬롯과 슬롯->아이템을 오고가기 위해서 아이템은 슬롯과 한 가지 이상의 고유한 값을 공유해야한다. 이번에는 ID를 사용했다.

    public int GetItemID()
    {
        return itemID;
    }

이렇게 아이템 -> 슬롯은 아이템 자체에서 자신의 ID를 제공하는 것으로. 슬롯 -> 아이템은 아이템 매니저에서 만들기로 했다.