Unity scriptable object inventory ui

using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

public class InventoryUI : MonoBehaviour
{
    [Header("Data")]
    [SerializeField] private InventoryData inventoryData;

    [Header("UI (Canvas yang sudah ada)")]
    [SerializeField] private InventorySlot slotPrefab;
    [SerializeField] private Transform slotParent;
    [Tooltip("Hapus slot placeholder yang sudah ada di slotParent saat mulai")]
    [SerializeField] private bool clearExistingSlots = true;

    [Header("Deteksi item")]
    [SerializeField] private float scanInterval = 0.5f;

    private readonly Dictionary<int, InventorySlot> slots = new Dictionary<int, InventorySlot>();
    private readonly Dictionary<Item, int> trackedItems = new Dictionary<Item, int>();
    private readonly List<Item> destroyedBuffer = new List<Item>();

    private static readonly FieldInfo ItemIdField =
        typeof(Item).GetField("itemId", BindingFlags.NonPublic | BindingFlags.Instance);

    private float scanTimer;

    private void Start()
    {
        if (clearExistingSlots)
        {
            foreach (Transform child in slotParent)
                Destroy(child.gameObject);
        }

        ScanItems();
        Refresh();
    }

    private void Update()
    {
        bool changed = false;
        destroyedBuffer.Clear();

        foreach (KeyValuePair<Item, int> pair in trackedItems)
        {
            if (pair.Key == null)
            {
                AddToInventory(pair.Value, 1);
                destroyedBuffer.Add(pair.Key);
                changed = true;
            }
        }

        foreach (Item key in destroyedBuffer)
            trackedItems.Remove(key);

        if (changed) Refresh();

        scanTimer += Time.deltaTime;
        if (scanTimer >= scanInterval)
        {
            scanTimer = 0f;
            ScanItems();
        }
    }

    private void ScanItems()
    {
        Item[] items = FindObjectsByType<Item>(FindObjectsSortMode.None);
        foreach (Item item in items)
        {
            if (trackedItems.ContainsKey(item)) continue;
            int id = (int)ItemIdField.GetValue(item);
            trackedItems.Add(item, id);
        }
    }

    private void AddToInventory(int itemId, int amount)
    {
        ItemInventoryData data = inventoryData.ItemList.Find(i => i.ItemId == itemId);
        if (data == null)
        {
            Debug.LogWarning($"ItemId {itemId} tidak ada di InventoryData.");
            return;
        }
        data.ItemCount = Mathf.Max(0, data.ItemCount + amount);
    }

    public void Refresh()
    {
        int order = 0;

        foreach (ItemInventoryData item in inventoryData.ItemList)
        {
            bool hasSlot = slots.TryGetValue(item.ItemId, out InventorySlot slot);

            if (item.ItemCount <= 0)
            {
                if (hasSlot)
                {
                    Destroy(slot.gameObject);
                    slots.Remove(item.ItemId);
                }
                continue;
            }

            if (!hasSlot)
            {
                slot = Instantiate(slotPrefab, slotParent);
                slots.Add(item.ItemId, slot);
            }

            slot.ItemIcon.sprite = item.ItemIcon;
            slot.ItemCount.text = item.ItemCount.ToString();
            slot.transform.SetSiblingIndex(order++);
        }
    }
}
`
1 Like

A wall of code because??

2 Likes