
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();
}
}
}
이렇게 해주면 인벤토리가 잘 작동하는 것을 볼 수 있다.


'게임공부 > Unity' 카테고리의 다른 글
[C#][디자인 패턴]State 패턴 (0) | 2025.01.09 |
---|---|
[Unity]최적화 관련 팁 (0) | 2025.01.08 |
[C#][Unity][나만의 탑뷰 게임 만들기]6. 인벤토리 시스템 만들기 (2) | 2024.12.28 |
[C#][Unity][나만의 탑뷰 게임 만들기]5. 저장시스템 기초만들기 (1) | 2024.12.22 |
[C#][Unity][나만의 탑뷰 게임 만들기]4. 아이템 시스템 만들기 (0) | 2024.12.18 |