using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; [Serializable] public class InventoryItemStack { public InventoryItemType itemType; [Min(0)] public int count; } [Serializable] public class InventoryItemChangedEvent : UnityEvent { } /// /// 실제 아이템 개수를 관리하는 중심 스크립트입니다. /// UI를 직접 수정하지 않고, 아이템 개수 변경 이벤트만 알려줍니다. /// [DisallowMultipleComponent] public class InventoryManager : MonoBehaviour { [Header("Initial Items")] [SerializeField] private List initialItems = new List(); [Header("Events")] public InventoryItemChangedEvent onItemCountChanged; public UnityEvent onInventoryChanged; [Header("Debug")] [SerializeField] private bool showDebugLog = true; private readonly Dictionary itemCounts = new Dictionary(); public event Action ItemCountChanged; public event Action InventoryChanged; private void Awake() { InitializeFromInspector(); } private void Start() { NotifyAllItemsChanged(); } private void InitializeFromInspector() { itemCounts.Clear(); foreach (InventoryItemType itemType in Enum.GetValues(typeof(InventoryItemType))) itemCounts[itemType] = 0; for (int i = 0; i < initialItems.Count; i++) { InventoryItemStack stack = initialItems[i]; if (stack == null) continue; itemCounts[stack.itemType] = Mathf.Max(0, stack.count); } } public void AddItem(InventoryItemType itemType) { AddItem(itemType, 1); } public void AddItem(InventoryItemType itemType, int amount) { if (amount <= 0) return; int newCount = GetItemCount(itemType) + amount; SetItemCount(itemType, newCount); if (showDebugLog) Debug.Log($"[InventoryManager] {itemType} +{amount} => {newCount}"); } public bool RemoveItem(InventoryItemType itemType) { return RemoveItem(itemType, 1); } public bool RemoveItem(InventoryItemType itemType, int amount) { if (amount <= 0) return false; int current = GetItemCount(itemType); if (current < amount) { if (showDebugLog) Debug.LogWarning($"[InventoryManager] {itemType} 부족: 현재 {current}, 필요 {amount}"); return false; } SetItemCount(itemType, current - amount); return true; } public void SetItemCount(InventoryItemType itemType, int count) { int clampedCount = Mathf.Max(0, count); int previousCount = GetItemCount(itemType); if (previousCount == clampedCount) return; itemCounts[itemType] = clampedCount; NotifyItemChanged(itemType, clampedCount); } public int GetItemCount(InventoryItemType itemType) { if (itemCounts.TryGetValue(itemType, out int count)) return count; return 0; } public bool HasItem(InventoryItemType itemType) { return GetItemCount(itemType) > 0; } public bool HasItem(InventoryItemType itemType, int requiredAmount) { return GetItemCount(itemType) >= Mathf.Max(1, requiredAmount); } public void ClearInventory() { foreach (InventoryItemType itemType in Enum.GetValues(typeof(InventoryItemType))) itemCounts[itemType] = 0; NotifyAllItemsChanged(); } public IReadOnlyDictionary GetAllItemCounts() { return itemCounts; } private void NotifyItemChanged(InventoryItemType itemType, int count) { ItemCountChanged?.Invoke(itemType, count); InventoryChanged?.Invoke(); onItemCountChanged?.Invoke(itemType, count); onInventoryChanged?.Invoke(); } private void NotifyAllItemsChanged() { foreach (KeyValuePair pair in itemCounts) { ItemCountChanged?.Invoke(pair.Key, pair.Value); onItemCountChanged?.Invoke(pair.Key, pair.Value); } InventoryChanged?.Invoke(); onInventoryChanged?.Invoke(); } #if UNITY_EDITOR private void OnValidate() { if (initialItems == null) return; for (int i = 0; i < initialItems.Count; i++) { if (initialItems[i] != null) initialItems[i].count = Mathf.Max(0, initialItems[i].count); } } #endif }