🛠️ 오늘 한 작업

  • 인벤토리 기능을 실제로 동작하게 만드는 작업을 진행했습니다.
  • 인벤토리에 아이템을 직접 넣어서 UI에 표시되는지 확인했습니다.
  • 아이템 추가, 제거, 슬롯 이동/교환 같은 기본 기능을 추가했습니다.
  • 계획했던 장비창까지 완전히 마무리하지는 못했지만, 아이템 장착 흐름은 어느 정도 확인했습니다.

 

📌 오늘 계획

오늘은 정말로 인벤토리 기능을 제대로 진행해보는 것을 목표로 잡았습니다.

가능하면 장비창까지 이어서 작업하고 싶었지만, 막상 시작해보니 인벤토리 쪽 구조를 다시 정리해야 할 부분이 많았습니다.

  • 인벤토리 기능 구현
  • 아이템을 인벤토리에 넣어서 표시 확인
  • ItemSlot 구조 수정
  • 드래그 앤 드롭 관련 스크립트 수정
  • 가능하면 장비창까지 연결

처음에는 기능을 이어서 붙이면 될 줄 알았는데, 실제로 작업하다 보니 기존 구조로는 애매한 부분이 보여서 다시 원점으로 돌아간 느낌이었습니다.

그래도 아예 진전이 없던 건 아니고, 인벤토리에 아이템을 넣고 확인하는 단계까지는 진행했습니다.

많이 한게 없긴 하네요;; (계획만 항상 많아요 ㅋㅋㅋ)

 

이미지는 나중에 추가했습니다(참고용)

🎒 인벤토리 슬롯 제한 정리

먼저 인벤토리에서 실제로 사용할 수 있는 슬롯 수를 다시 정리했습니다.

기존에는 기본 슬롯 수와 가방 보너스 슬롯을 단순히 더하는 방식이었는데, 이번에는 최대 슬롯 수를 넘지 않도록 Mathf.Clamp로 제한했습니다.

Inventory.cs - 사용 가능한 슬롯 수 제한

public int ActiveSlotCount => Mathf.Clamp(BaseSlotCount + BagBonusSlots, 0, MaxSlots);

가방으로 슬롯이 늘어나는 구조가 있기 때문에, 슬롯 수가 최대치를 넘어가지 않게 막는 처리가 필요했습니다.

또 잠긴 슬롯인지 확인하는 IsLockedSlot을 추가해서, 아이템 이동이나 제거를 할 때 잠긴 슬롯을 건드리지 않도록 했습니다.

Inventory.cs - 잠긴 슬롯 확인

public bool IsLockedSlot(int index) => index >= ActiveSlotCount;

이런 부분은 눈에 확 보이는 기능은 아니지만, 나중에 버그를 막기 위해 필요한 기초 작업이라고 생각했습니다.

 

➕ 아이템 추가 기능

오늘 가장 중요한 작업은 인벤토리에 아이템을 추가하는 기능이었습니다.

AddItem에서는 아이템 ID를 기준으로 CommonItemData를 찾고, 해당 아이템의 MaxStack을 기준으로 기존 스택에 먼저 채운 뒤 빈 슬롯에 새로 넣는 방식으로 구현했습니다.

Inventory.cs - 아이템 추가 흐름

public bool AddItem(int itemId, int amount)
{
    if (amount <= 0) return true;

    if (!CommonItemData.tableDic.TryGetValue(itemId, out var baseData))
    {
        Debug.LogError($"inventory addItem failed {itemId}");
        return false;
    }

    int maxStack = Mathf.Max(1, baseData.MaxStack);

    if (maxStack > 1)
    {
        for (int i = 0; i < ActiveSlotCount && amount > 0; i++)
        {
            if (slots[i] == null) continue;
            if (slots[i].itemId != itemId) continue;
            if (slots[i].count >= maxStack) continue;

            int space = maxStack - slots[i].count;
            int add = Mathf.Min(space, amount);
            slots[i].count += add;
            amount -= add;
        }
    }

    for (int i = 0; i < ActiveSlotCount && amount > 0; i++)
    {
        if (slots[i] != null) continue;

        int add = Mathf.Min(maxStack, amount);
        slots[i] = new ItemStack(itemId, add);
        amount -= add;
    }

    EventManager.TriggerEvent(EventKey.InventoryChanged);
    return amount == 0;
}

이 기능이 들어가면서 이제 인벤토리에 테스트 아이템을 직접 넣어볼 수 있게 됐습니다.

아직 완성된 인벤토리는 아니지만, 아이템 데이터와 인벤토리 슬롯이 실제로 연결되는 걸 확인할 수 있었다는 점에서 의미가 있었습니다.

 

🧪 테스트용 아이템 넣기

GameManager에서는 임시로 플레이어 1 인벤토리에 가방 슬롯을 추가하고, 테스트용 아이템을 넣어 확인했습니다.

GameManager.cs - 테스트용 아이템 추가

InventoryPlayer1.EquipBag(20);
InventoryPlayer1.AddItem(30000, 1);
InventoryPlayer1.AddItem(30001, 1);
InventoryPlayer1.AddItem(31000, 50);

지금은 테스트를 위해 직접 넣어둔 상태라 나중에는 제거하거나 다른 초기화 방식으로 바꿔야 합니다.

그래도 오늘 단계에서는 실제 아이템이 인벤토리에 들어가고 UI에 표시되는지 확인하는 게 우선이라, 임시 데이터로 확인하는 방식이 필요했습니다.

 

➖ 아이템 제거와 슬롯 이동

아이템을 넣는 것만으로는 인벤토리 기능이라고 보기 어렵기 때문에, 제거와 슬롯 이동 기능도 같이 추가했습니다.

특정 슬롯에서 일정 수량만 제거하는 RemoveSlot을 만들고, 슬롯 간 아이템을 바꾸는 MoveOrSwap도 추가했습니다.

Inventory.cs - 슬롯 제거

public bool RemoveSlot(int index, int amount)
{
    if (index < 0 || index >= MaxSlots) return false;
    if (IsLockedSlot(index)) return false;
    if (slots[index] == null) return false;
    if (amount > slots[index].count) return false;
    if (amount <= 0) return true;

    slots[index].count -= amount;
    if (slots[index].count <= 0) slots[index] = null;

    EventManager.TriggerEvent(EventKey.InventoryChanged);
    return true;
}

Inventory.cs - 슬롯 이동 / 교환

public bool MoveOrSwap(int start, int end)
{
    if (start < 0 || start >= MaxSlots) return false;
    if (end < 0 || end >= MaxSlots) return false;
    if (IsLockedSlot(end) || IsLockedSlot(start)) return false;

    if (slots[start] == null) return false;

    var temp = slots[start];
    slots[start] = slots[end];
    slots[end] = temp;

    EventManager.TriggerEvent(EventKey.InventoryChanged);
    return true;
}

 

🖱️ ItemSlot 버튼 처리

ItemSlot 쪽에는 버튼 참조를 추가하고, 잠긴 슬롯일 때는 버튼이 눌리지 않도록 처리했습니다.

ItemSlot.cs - 잠긴 슬롯 버튼 비활성화

[SerializeField] private Button button;

public void SetLocked(bool locked)
{
    button.interactable = !locked;

    if (lockSlot != null) lockSlot.SetActive(locked);
    if (slotIcon != null) slotIcon.enabled = !locked;
    if (countTXT != null) countTXT.gameObject.SetActive(!locked);

    if (locked) SetEmpty();
}

잠긴 슬롯이 시각적으로만 막혀 있고 실제로 클릭이 가능하면 나중에 이상한 입력 버그가 생길 수 있습니다.

그래서 잠긴 슬롯은 UI 표시뿐만 아니라 버튼 입력도 같이 막는 방향으로 수정했습니다.

 

📌 오늘의 회고

오늘 목표는 인벤토리 기능을 제대로 진행하고, 가능하면 장비창까지 이어가는 것이었습니다.

결과적으로 장비창까지 많이 진행하지는 못했지만, 인벤토리에 아이템을 직접 넣고 확인하는 단계까지는 왔습니다.

구조를 다시 바꾸느라 또 원점으로 돌아간 것 같은 느낌도 있었지만, 그래도 아이템 추가, 제거, 슬롯 이동 같은 기본 기능이 생기면서 인벤토리가 조금씩 실제 기능처럼 보이기 시작했습니다.

아직은 WIP 상태라 완성됐다고 보기는 어렵습니다. 특히 드래그 앤 드롭과 장비창 연결은 더 손봐야 합니다.

그래도 오늘은 “아이템을 인벤토리에 넣어서 확인했다”는 점에서 의미가 있었습니다. 이제 다음에는 이 흐름을 장비창이나 퀵슬롯 쪽으로 어떻게 연결할지 봐야겠습니다.