📁 개발 히스토리

유니티 - 인벤토리 구현하기(5)

일단몸통박치기 2025. 2. 24. 17:43

 

유니티 - 인벤토리 구현하기(2) 편에서 구현해놨던 GainItem의 함수를

좀 더 깔끔하고 명확하게 리팩토링하기로 했다.

 

💡 : 우선 이미 같은 아이템이 인벤토리에 있다면 그쪽에 추가하고 HotbarSlot에도 BagSlot에도 없으면
       빈 슬롯을 찾아서 그곳에 추가하도록 해야겠다.

public void GainItem(int Itemnum, int Itemcount = 1)
    {
        int index = HotbarSlots.FindIndex(x => x.CurrentItem.ItemNum == Itemnum);
        if(index != -1)
        {
            HotbarSlots[index].AddCount(Itemcount);
            return;
        }

        index = BagSlots.FindIndex(x => x.CurrentItem.ItemNum == Itemnum);
        if (index != -1)
        {
            BagSlots[index].AddCount(Itemcount);
            return;
        }
        else
        {
            index = HotbarSlots.FindIndex(x => x.IsItemExist == false);

            if(index != -1)
            {
                HotbarSlots[index].SetItem(Datas.ItemDatas.Find(x => x.ItemNum == Itemnum));
                return;
            }

            index = BagSlots.FindIndex(x => x.IsItemExist == false);

            if (index != -1)
            {
                BagSlots[index].SetItem(Datas.ItemDatas.Find(x => x.ItemNum == Itemnum));
                return;
            }
            else
            {
                Debug.LogError("가방에 더이상 공간이 없습니다.");
            }
        }
    }

    public void LoseItem(int Itemnum, int Itemcount = 1)
    {

    }

이쪽이 기존의 스크립트.

 

 

다시 곰곰히 아이템 획득 시 작동해야하는 요소들을 고민해봤다.

 

우선 인벤토리에 이런 상태의 아이템이 들어있다고 치자.

이 상태에서 5개짜리 당근 뭉치를 획득할경우,

 

 

이렇게 인벤토리 내의 위쪽 상자부터 최대 갯수인 99개를 채우고

남은 당근은 새 슬롯에 저장되어야한다.

 

 

그러기 위해선 위 그림과 같은 순서로 슬롯을 순회하며

1. If 같은 아이템이 있다면

➡  획득한 아이템을 99개까지 더하고

2.  If 그래도 남은 아이템이 있다면

➡  이어서 순회.

3.  If 모두 순회한 뒤에도 남은 아이템이 있다면

➡  빈슬롯을 찾아서 아이템을 추가해야한다.

 

그런데 또 슬롯 List는 가장 윗줄과 아랫줄로 나누어 두었기 때문에

List<IV_Slot>과 아이템 번호, 갯수를 받아 알아서 수색 및 합산하는 함수를 추가했다.

 

 

우선 빈 슬롯을 찾아 IV_Slot을 반환해주는 함수부터 작성했다.

    public IV_Slot FindEmptySlot()
    {
        int index = HotbarSlots.FindIndex(x => x.IsItemExist == false);

        if (index != -1)
        {
            return HotbarSlots[index];
        }

        index = BagSlots.FindIndex(x => x.IsItemExist == false);

        if (index != -1)
        {
            return BagSlots[index];
        }
        else
        {
            Debug.LogError("가방에 더이상 공간이 없습니다.");
            return null;
        }
    }

 

 

다음은 List과 아이템 번호, 갯수를 인자로 받아

동일 아이템을 가지고 있는 슬롯에 갯수를 더하고

남은 갯수는 int로 반환하게끔 작성한 AddToSameItem 함수.

 

    public int AddToSameItem(List<IV_Slot> Slots, int Num, int Count)
    {
        if (Count <= 0) return 0;

        for(int i = 0; i < Slots.Count; i++)
        {
            if (!Slots[i].IsItemExist) continue;

            if(Slots[i].CurrentItem.Num == Num)
            {
                Count = Slots[i].AddCount(Count);
                if (Count <= 0) return 0;
            }
        }
        return Count;
    }

 

 

이 과정에서 Slot의 AddCount 함수도 수정했는데

기존에 99개가 넘을 경우 ToDo로 비워뒀던 구간을 추가하고

넘친 갯수를 반환하게끔 수정했다.

 

    public int AddCount(int Added)
    {
        if (CurrentItem.Type == IV_Item.ItemType.Equip || CurrentItem.Type == IV_Item.ItemType.Tool) return -1;

        if(CurrentItem.Count + Added > 99)
        {
            int remains = CurrentItem.Count + Added - 99;
            CurrentItem.Count = 99;
            ItemCount.text = CurrentItem.Count.ToString();

            return remains;
        }

        CurrentItem.Count += Added;

        ItemCount.text = CurrentItem.Count.ToString();
        return 0;
    }

    public void ReduceCount(int Reduced)
    {
        if (CurrentItem.Count - Reduced <= 0)
        {
            // 1개 미만으로 줄어들 경우 슬롯 초기화
            IsItemExist = false;
            ItemImg.color = new Color(1, 1, 1, 0);
            ItemCount.text = "";

            CurrentItem.Count = 0;
            CurrentItem.Num = -1;
            return;
        }

        CurrentItem.Count -= Reduced;

        ItemCount.text = CurrentItem.Count.ToString();
    }

 

 

요기서 또 가벼운 이슈를 해결했는데

모든 아이템이 인벤토리 한칸에 겹쳐지는 것은 아니다.

 

도구나 장비 등은 1개가 슬롯 1칸을 차지하게 하고 싶었기 때문에

아이템에 속성을 추가했다.

 

[System.Serializable]
public class IV_Item
{
    public int Num;
    public string Name;
    public string Descript;
    public int Count;
    public Sprite Sprite;
    public ItemType Type;
    public Equipment EquipType;

    public enum ItemType
    {
        Normal,
        Useable,
        Equip,
        Tool,
        none
    }

    public enum Equipment
    {
        none,
        Head,
        Shirt,
        Pants,
        Shoe,
        Necklace,
        Ring
    }
}

 

 

ItemType을 통해 일반, 사용가능한(포션이나 음식 등), 장비, 도구 등으로 나누고

장비의 경우 같은 파츠를 여러개 장착하지 못하도록

머리, 상의, 하의, 신발, 목걸이, 반지로 나누었다.

 

 

그리고 마지막으로 GainItem을 새로 작성한 함수로 수정해준다!

 

    public void GainItem(int Itemnum, int Itemcount = 1)
    {
        if (!Datas.IsStackable(Itemnum))
        {
            IV_Slot NewSlot = FindEmptySlot();
            if (NewSlot != null)
            {
                NewSlot.SetItem(DeepCopyItem(Itemnum, Itemcount));
                HUDSynchronize();
            }
            return;
        }

        Itemcount = AddToSameItem(HotbarSlots, Itemnum, Itemcount);

        if (Itemcount <= 0)
        {
            HUDSynchronize();
            return;
        }

        Itemcount = AddToSameItem(BagSlots, Itemnum, Itemcount);

        if (Itemcount <= 0)
        {
            HUDSynchronize();
            return;
        }
        else
        {
            IV_Slot NewSlot = FindEmptySlot();
            if(NewSlot != null)
            {
                NewSlot.SetItem(DeepCopyItem(Itemnum, Itemcount));
                HUDSynchronize();
            }
        }
    }

 

가장 위에서부터 보자면

우선 스택 가능한 아이템이 아니라면 빈 슬롯을 찾아 추가한다.

다음은 HotbarSlot에서 같은 아이템을 찾아 합산하고

남은 아이템이 있다면 BagSlot에서도 진행,

여전히 남은 아이템은 빈 슬롯을 찾아 추가한다!

 

 

 

 

정확히 작동하는 모습.