1. 장비 착용UI 만들기

 

플레이어가 착용한 장비가 보이게 UI를 수정해주자

착용한 장비에 따라 인벤토리칸이 달라지도록해야한다.

'

 

이렇게 만들고 UI_Inventory코드를 수정하고 EquipSlot코드도 새로 만들어주자.

UI_Inventory.cs

using System.Collections.Generic;
using UnityEngine;

public class UI_Inventory : UI_Popup
{
    [SerializeField] private Transform slotContainer; // 슬롯 UI 부모 객체
    [SerializeField] private GameObject slotPrefab;   // 슬롯 UI 프리팹

    enum GameObjects
    {
        EquipSlot,
    }

    private List<ItemSlot> itemSlots = new List<ItemSlot>();

    public override void Init()
    {
        Bind<GameObject>(typeof(GameObjects));
        base.Init();
        RefreshUI(); // UI 활성화 시 즉시 인벤토리 데이터 업데이트
    }

    public void RefreshUI()
    {
        List<ItemSlot> inventory = Managers.Inventory.GetOwnedItems();
        int requiredSlotCount = inventory.Count;

        GetObject((int)GameObjects.EquipSlot).GetComponent<EquipSlot>().Init();

        // **슬롯 초기화**
        for (int i = 0; i < slotContainer.childCount; i++)
        {
            GameObject slotObj = slotContainer.GetChild(i).gameObject;
            if (i < requiredSlotCount)
            {
                slotObj.SetActive(true);
                SlotButton slotButton = slotObj.GetComponent<SlotButton>();
                slotButton.UpdateSlotUI(inventory[i]);
            }
            else
            {
                slotObj.SetActive(false); // 남는 슬롯 비활성화
            }
        }

        // **부족한 슬롯 생성**
        for (int i = slotContainer.childCount; i < requiredSlotCount; i++)
        {
            GameObject newSlot = Instantiate(slotPrefab, slotContainer);
            newSlot.SetActive(true);
            SlotButton slotButton = newSlot.GetComponent<SlotButton>();
            slotButton.UpdateSlotUI(inventory[i]);
        }
    }



    private void CreateSlotUI(ItemSlot itemSlot)
    {
        GameObject slotObj = Instantiate(slotPrefab, slotContainer);
        slotObj.SetActive(true);
        SlotButton slotButton = slotObj.GetComponent<SlotButton>();
        slotButton.UpdateSlotUI(itemSlot);

        // 슬롯 데이터 디버그 확인
        Debug.Log($"Created Slot for Item: {itemSlot.itemData.itemName}, Quantity: {itemSlot.quantity}");
    }
}

 

EquipSlot.cs

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class EquipSlot : UI_Base, IPointerClickHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
{
    [SerializeField] private Image itemIcon;          // 아이템 아이콘 표시
    [SerializeField] private TextMeshProUGUI itemName; // 아이템 이름 
    [SerializeField] private TextMeshProUGUI itemInfo;  // 아이템 설명
    [SerializeField] private TextMeshProUGUI AttackInfo; // 공격력 설명

    public ItemSlot currentItemSlot;                 // 현재 슬롯에 연결된 아이템 데이터


    public override void Init()
    {
        ItemSlot CurrentEquippedItem = Managers.Inventory.EquippedWeapon;

        if(CurrentEquippedItem != null ) 
        { 
            UpdateSlotUI(CurrentEquippedItem);
        }else
        {
            itemIcon.gameObject.SetActive(false);
            itemName.text = "장착 없음";
            itemInfo.text = "";
            AttackInfo.text = "";
        }
    }

    // 슬롯 UI 업데이트
    public void UpdateSlotUI(ItemSlot itemSlot)
    {
        currentItemSlot = itemSlot;

        if (currentItemSlot != null && currentItemSlot.itemData != null)
        {
            itemIcon.sprite = currentItemSlot.itemData.icon;
            itemIcon.gameObject.SetActive(true);
            itemName.text = currentItemSlot.itemData.itemName;
            itemInfo.text = currentItemSlot.itemData.description;
            AttackInfo.text = $"공격력: {currentItemSlot.itemData.AttackDamage}";
        }
        else
        {
            itemIcon.gameObject.SetActive(false);
            itemName.text = "장착 없음";
            itemInfo.text = "";
            AttackInfo.text = "";
        }
    }


    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("클릭 이벤트 호출!");

        UI_EquipSel uI_EquipSel = FindAnyObjectByType<UI_EquipSel>();
        if (uI_EquipSel == null)
        {
            uI_EquipSel = Managers.UI.ShowPopupUI<UI_EquipSel>();
            uI_EquipSel.gameObject.transform.SetParent(transform, false);
            Vector3 loaction = eventData.position;
            loaction.y -= 50;
            uI_EquipSel.gameObject.transform.SetPositionAndRotation(loaction, Quaternion.identity);
        }
        else
        {
            Managers.UI.ClosePopupUI(uI_EquipSel);
        }

    }
    }
}

그리고 단일 책임 원칙을 지키고 중앙화된 아이템 관리를 하기 위해  플레이어가 장착한 무기도 인벤토리 매니저에서 관리하도록 수정해주었다.

InventoryManager.cs

using System.Collections.Generic;
using UnityEngine;

public class InventoryManager : MonoBehaviour
{
    [SerializeField] private Transform slotContainer; // 슬롯 UI 부모 객체
    [SerializeField] private GameObject slotPrefab;   // 슬롯 UI 프리팹
    private List<ItemSlot> inventory = new List<ItemSlot>();
    private Dictionary<int, ItemData> itemDataCache = new Dictionary<int, ItemData>();

    public ItemSlot EquippedWeapon { get; private set; }

    public void Init()
    {
        inventory = new List<ItemSlot>();
        slotPrefab = Resources.Load<GameObject>("Prefabs/Item");
        CacheItemData();
        EquippedWeapon = null;
    }

    private void CacheItemData()
    {
        ItemData[] items = Resources.LoadAll<ItemData>("Items");
        foreach (var item in items)
        {
            if (!itemDataCache.ContainsKey(item.itemID))
            {
                itemDataCache.Add(item.itemID, item);
            }
        }
    }

    public ItemData FindItemDataByID(int itemID)
    {
        if (itemDataCache.TryGetValue(itemID, out ItemData itemData))
        {
            return itemData;
        }

        Debug.LogWarning($"ItemData를 찾을 수 없습니다: ID = {itemID}");
        return null;
    }

    public void EquipWeapon(ItemData itemData)
    {
        if (EquippedWeapon != null)
        {
            Debug.LogWarning("이미 무기가 장착되어 있습니다.");
            return;
        }

        ItemSlot slot = inventory.Find(s => s.itemData.itemID == itemData.itemID);
        if (slot != null)
        {
            slot.quantity--;
            if (slot.quantity <= 0)
            {
                inventory.Remove(slot);
            }

            EquippedWeapon = new ItemSlot { itemData = itemData, quantity = 1 };
            Debug.Log($"무기 '{itemData.itemName}' 장착 완료.");
        }
        else
        {
            Debug.LogWarning("장착하려는 무기가 인벤토리에 없습니다.");
        }

        RefreshUI();
    }

    public void UnEquipWeapon()
    {
        if (EquippedWeapon == null)
        {
            Debug.LogWarning("장착된 무기가 없습니다.");
            return;
        }

        TryAddItem(EquippedWeapon.itemData, 1);
        Debug.Log($"무기 '{EquippedWeapon.itemData.itemName}' 해제 완료.");
        EquippedWeapon = null;

        RefreshUI();
    }

    public bool TryAddItem(ItemData itemData, int count = 1)
    {
        ItemSlot slot = inventory.Find(s => s.itemData.itemID == itemData.itemID);

        if (itemData.itemType == Define.ItemType.Equipment)
        {
            if (slot != null && slot.quantity >= 1)
            {
                Debug.LogWarning("이미 인벤토리에 무기가 있습니다.");
                return false;
            }
        }

        if (inventory.Count >= 30)
        {
            Debug.LogWarning("인벤토리 용량이 초과되었습니다.");
            return false;
        }

        if (slot != null)
        {
            slot.quantity += count;
        }
        else
        {
            inventory.Add(new ItemSlot { itemData = itemData, quantity = count });
        }

        RefreshUI();
        return true;
    }

    public void RemoveItem(ItemData itemData, int count = 1)
    {
        ItemSlot slot = inventory.Find(s => s.itemData.itemID == itemData.itemID);
        if (slot != null)
        {
            slot.quantity -= count;
            if (slot.quantity <= 0)
            {
                inventory.Remove(slot);
                Debug.Log($"아이템 '{itemData.itemName}'이(가) 인벤토리에서 제거되었습니다.");
            }
            else
            {
                Debug.Log($"아이템 '{itemData.itemName}'의 수량이 {slot.quantity}로 줄었습니다.");
            }
        }
        else
        {
            Debug.LogWarning($"제거하려는 아이템 '{itemData.itemName}'이(가) 인벤토리에 없습니다.");
        }

        RefreshUI();
    }

    public void RefreshUI()
    {
        UI_WeaponSel uI_WeaponSel = FindAnyObjectByType<UI_WeaponSel>();
        UI_EquipSel uI_EquipSel = FindAnyObjectByType<UI_EquipSel>();
        if(uI_WeaponSel != null)
        {
            Managers.UI.ClosePopupUI(uI_WeaponSel);
        }else if(uI_EquipSel != null)
        {
            Managers.UI.ClosePopupUI(uI_EquipSel);
        }

        UI_Inventory inventoryUI = Managers.UI.GetTopPopupUI() as UI_Inventory;
        
        if (inventoryUI != null)
        {
            inventoryUI.RefreshUI();
        }
    }

    public List<ItemSlot> GetOwnedItems()
    {
        return inventory;
    }

    public void SaveInventory(ref SaveData saveData)
    {
        List<SerializedItemSlot> serializedInventory = new List<SerializedItemSlot>();
        foreach (var slot in inventory)
        {
            serializedInventory.Add(new SerializedItemSlot
            {
                itemID = slot.itemData.itemID,
                quantity = slot.quantity
            });
        }

        saveData.inventoryData = serializedInventory;

        saveData.equippedWeaponID = EquippedWeapon?.itemData.itemID ?? -1;
    }

    public void LoadInventory(SaveData saveData)
    {
        if (saveData.inventoryData == null) return;

        inventory.Clear();
        foreach (var serializedSlot in saveData.inventoryData)
        {
            ItemData itemData = FindItemDataByID(serializedSlot.itemID);
            if (itemData != null)
            {
                inventory.Add(new ItemSlot { itemData = itemData, quantity = serializedSlot.quantity });
            }
        }

        if (saveData.equippedWeaponID != -1)
        {
            ItemData weaponData = FindItemDataByID(saveData.equippedWeaponID);
            if (weaponData != null)
            {
                EquippedWeapon = new ItemSlot { itemData = weaponData, quantity = 1 };
                Debug.Log($"무기 '{weaponData.itemName}' 장착 복원.");
            }
        }

        RefreshUI();
    }
}

 

RefreshUI에서 만약 장착이나 장착해제 UI가 떠있는 상태라면 인벤토리 UI가 최상단이 아니기 때문에 꺼주고 최상단 UI를 불러와서 Refresh를 진행하도록 해주었다. 

이에 맞춰서 장착해제와 장착의 UI의 코드도 수정해줬다.

UI_WeaponSel.cs

using UnityEngine.EventSystems;
using UnityEngine.UI;

public class UI_WeaponSel : UI_Popup
{
    public enum Buttons
    {
        EquipButton,
        RemoveButton,
    }

    public override void Init()
    {
        Bind<Button>(typeof(Buttons));
        GetButton((int)Buttons.EquipButton).gameObject.AddUIEvent(EquipWeapon);
    }

    void EquipWeapon(PointerEventData eventData)
    {
        SlotButton slotButton = transform.parent.GetComponent<SlotButton>();
        if (slotButton != null)
        {
            Managers.Inventory.EquipWeapon(slotButton.currentItemSlot.itemData);
            Managers.Inventory.RefreshUI();
        }
    }
}

 

SlotButton.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class UI_EquipSel : UI_Popup
{
    public enum Buttons
    {
        UnequipButton,
        RemoveButton,
    }

    public override void Init()
    {
        Bind<Button>(typeof(Buttons));

        GetButton((int)Buttons.UnequipButton).gameObject.AddUIEvent(UnequipWeapon);
    }

    void UnequipWeapon(PointerEventData eventData)
    {
        EquipSlot currentItem = transform.parent.gameObject.GetComponent<EquipSlot>();
        if (currentItem != null)
        {
            Managers.Inventory.UnEquipWeapon();
            Managers.Inventory.RefreshUI();
        }
    }
}

 

이렇게 해주면 인벤토리가 잘 작동하는 것을 볼 수 있다.

+ Recent posts