코드 및 공부/데이터 관리

유니티 조합 시스템 - 슬롯 이용

ekrxjvpvj0110 2024. 12. 24. 20:41

유니티 버전 - 2022.3.17f1

 

 

 

 

 

목차


  • 전재 조건과 목표
  • 코드 및 설명

 

 

 

 

 

전재 조건


해당 기능을 이용하여 슬롯에 퍼져있는 아이템들을 정렬하고, 필요한 개수만큼 슬롯 아이템의 개수를 감소시킨뒤 결과물을 반환하도록 할 수 있습니다

 

 

 

1. CraftRecipeSO / NeedItems / ItemSo의 구조는 다음과 같습니다

만들고자 하는 아이템의 So

 

재료로 사용되는 아이템과 개수

 

ItemCode를 이용하여 기능을 수행하기때문에 반드시 필요, 모든 아이템의 기본이 되는 클래스

 

 

 

2. 슬롯의 구성은 다음과 같습니다

itemSo와 itemCount는 반드시 필요

 

 

 

3. 인벤토리의 구성은 다음과 같습니다

public Slot[] inventorySlots = new Slot[30];

 

 

 

 

 

코드 및 설명


먼저 코드의 구조를 살펴보겠습니다

 

 

 

외부에서 아이템을 조합해달라고 요청이 들어오면 현재 인벤토리의 모든 아이템을 정리하여 충분한 아이템이 있는지 확인하고 있다면 결과 아이템을 지급하는 형태입니다

 

 

 

Slots 배열은 싱글톤인 Managers.Data에서 관리되고 있기에 편의성을 위해 프로퍼티를 선언해줍니다

public class CraftingSystem : MonoBehaviour
{
    private Slot[] slots => Managers.Data.inventorySlots;

 

 

 

외부에서 호출해줄 매서드입니다, 결과 아이템에대한 정보를 요구하고 있습니다

public void CreateItem(CraftRecipeSO p_CraftRecipeSo)
{
    ProcessSortingSlots(p_CraftRecipeSo);
}

 

 

 

ProcessSortingSlots()


퍼져있는 아이템을 딕셔너리를 이용하여 정리하여줍니다, 왜냐하면 slots[0] 에 나무 아이템이 10개 있으면서, 동시에 slots[12] 에 나무 아이템이 20개 있을 수 도 있기때문입니다, 만약 slots[i] 번째의 단일 비교로만 아이템 개수가 충분한지 판단한다면, 필요한 아이템 개수로 15개를 요구하였을때 false가 반환되기에 나무의 총 개수를 통해 판단하도록 하기위해 itemcode를 키 값으로하여 itemcode가 같다면 개수를 증가시켜 주었습니다

private void ProcessSortingSlots(CraftRecipeSO p_CraftRecipeSo)
{
    Dictionary<int, Slot> sortedSlots = new Dictionary<int, Slot>();

    foreach (Slot slot in slots)
    {
        if (slot.itemCount == 0) break;
        // slot이 비어있을경우 itemSo == null이기때문에 검사하여주는 역할, (itemSo == null) == (itemCount == 0)

        if (sortedSlots.ContainsKey(slot.itemSo.itemCode))
        {
            sortedSlots[slot.itemSo.itemCode].itemCount += slot.itemCount;
            // 만약 wood라는 아이템이 20개, 30개씩 떨어져 있다면 합쳐서 50개의 숫자로 만들어줌
        }
        else
        {
            sortedSlots.Add(slot.itemSo.itemCode, slot);
            // 만약 wood라는 아이템이 없다면 itemCode를 이용하여 새로 추가
        }
    }

    if (sortedSlots.Count >= p_CraftRecipeSo.needItems.Length)
    // 인벤토리에 보유하고 있는 아이템의 개수가 필요한 아이템의 개수보다 적다면 실행 X
    {
        ProcessCheckEnoughItems(sortedSlots, p_CraftRecipeSo);
    }
}

 

 

 

ProcessCheckEnoughItems()


아이템 코드별로 개수가 정렬되어 있는 딕셔너리를 통해 p_CraftRecipeSO.needItems 배열의 materialItem의 아이템 코드와 비교하여 인벤토리에 존재하는지 판단합니다

 

만약 충분하다면 count를 1 올려, needItems[i] 가 충족되었음을 나타내어 줍니다

 

그리고 count가 p_CraftRecipeSO.needItems.Length 보다 크다는 것은 정렬된 딕셔너리의 아이템이 필요한 아이템들을 모두 보유하고있다는 말과 같으므로 이후 실제 데이터에서 재료로 소모되어야 하는 아이템들을 감소시켜주는 역할을 수행하도록 해줍니다

private void ProcessCheckEnoughItems(Dictionary<int, Slot> p_SlotsDic, CraftRecipeSO p_CraftRecipeSO)
{
    int count = 0;

    foreach (NeedItems item in p_CraftRecipeSO.needItems)
    {
        if (p_SlotsDic.TryGetValue(item.materialItem.itemCode, out Slot slot))
        {
            if (slot.itemCount >= item.materialAmount)
            {
                count++; // 아이템의 개수가 필요 아이템 개수보다 많으면 증가
            }
        }

        if (count >= p_CraftRecipeSO.needItems.Length)
        {
            ProcessMakeItem(p_CraftRecipeSO);
        }
    }
}

 

 

 

ProcessMakeItem()


실제 소모되어야 하는 아이템들을 감소시켜주고 만들고자 했던 아이템을 추가시켜주어야 합니다,

 

for 문 다음에 나오는 두 번의 if 문은, 빈 슬롯을 계산하지 않도록 하는 것과, slot에 있는 아이템 코드와 materialItem의 아이템 코드가 다르다면 계산하지 않도록 하는 것 입니다

 

needItemCount는 이번에 감소시켜야할 아이템 개수의 총 개수를 넣고, 이어지는 for문에서 slots[i]에 존재하는 아이템의 개수만큼만 뺄 수 있도록 하기위해 필요합니다

private void ProcessMakeItem(CraftRecipeSO p_CraftRecipeSO)
{
    foreach (NeedItems item in p_CraftRecipeSO.needItems)
    {
        int needItemCount = item.materialAmount;

        for (int i = 0; i < slots.Length; i++)
        {
            if (slots[i].itemCount == 0) continue;

            if (slots[i].itemSo.itemCode != item.materialItem.itemCode) continue;

            if (slots[i].itemCount - item.materialAmount < 0)
            // slot[i]에서 충분한 수량이 없다면 다음 slot[i]에서 이어서 빼줌
            {
                needItemCount -= slots[i].itemCount;

                slots[i].itemCount -= slots[i].itemCount;
            }
            else
            {
            // slot[i]에서 충분한 수량이 있다면 모두 빼줌
                slots[i].itemCount -= needItemCount;
            }
        }
    }

    GameManager.Instance.CharacterM.inventory.AcquireItem(p_CraftRecipeSO.resultItem);
    // 아이템 추가 로직, 원하는 방식으로 추가시켜주면 됨(foreach문이 종료된 후)
}