Receber por email
← Voltar para o catálogo

inventory-system

Inventory, equipment, and crafting patterns — ScriptableObject item definitions, slot-based inventory, equipment system, crafting recipes, UI binding. Load when implementing item management.

20estrelas
Atualizado há 6 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add XeldarAlz/everything-claude-unity

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/inventory-system/svg)](https://www.skillteca.com.br/skills/inventory-system)
#ai

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Inventory, Equipment, and Crafting System

Patterns for building a complete item management pipeline: define items as ScriptableObjects, store them in a slot-based inventory, equip gear, craft new items, and bind everything to UI.

Item Definition (ScriptableObject)

Every item in the game is defined as a ScriptableObject asset. This keeps data out of code, lets designers create items in the editor, and makes save/load straightforward (reference by ID, not by full object).

using UnityEngine;

public enum ItemType
{
    Consumable,
    Equipment,
    Material,
    QuestItem,
    Currency
}

public enum EquipmentSlotType
{
    None,
    Head,
    Body,
    Weapon,
    Shield,
    Accessory
}

[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item Definition")]
public class ItemDefinition : ScriptableObject
{
    [Header("Identity")]
    public string itemId;           // Unique ID for save/load: "sword_iron_01"
    public string displayName;
    [TextArea(2, 4)]
    public string description;
    public Sprite icon;

    [Header("Stacking")]
    public bool isStackable = true;
    public int maxStackSize = 99;

    [Header("Type")]
    public ItemType itemType;
    public EquipmentSlotType equipSlot = EquipmentSlotType.None;

    [Header("Stats (for equipment)")]
    public int attackBonus;
    public int defenseBonus;
    public int healthBonus;
    public int speedBonus;

    [Header("Usage (for consumables)")]
    public int healAmount;
    public int manaRestoreAmount;

    [Header("Economy")]
    public int buyPrice;
    public int sellPrice;
}

Naming convention for itemId: Use snake_case with category prefix. Examples: sword_iron_01, potion_health_small, mat_wood_plank. This makes save files human-readable and debugging easier.

Item Registry

Maintain a central registry so you can look up an ItemDefinition by its itemId. This is essential for save/load (you save the ID string, then reconstruct the reference on load).

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "ItemRegistry", menuName = "Inventory/Item Registry")]
public class ItemRegistry : ScriptableObject
{
    [SerializeField] private List<ItemDefinition> allItems;

    private Dictionary<string, ItemDefinition> _lookup;

    public void Initialize()
    {
        _lookup = new Dictionary<string, ItemDefinition>();
        foreach (var item in allItems)
        {
            if (_lookup.ContainsKey(item.itemId))
            {
                Debug.LogWarning($"Duplicate item ID: {item.itemId}");
                continue;
            }
            _lookup[item.itemId] = item;
        }
    }

    public ItemDefinition GetById(string itemId)
    {
        if (_lookup == null) Initialize();
        _lookup.TryGetValue(itemId, out var item);
        return item;
    }
}

Load all items into the registry at startup or use Resources.LoadAll<ItemDefinition>("Items/") if you prefer automatic discovery over an explicit list.

Inventory Slot

Each slot holds a reference to an item definition and a stack count. Null item means the slot is empty.

using System;

[Serializable]
public class InventorySlot
{
    public ItemDefinition item;
    public int count;

    public bool IsEmpty => item == null || count <= 0;

    public InventorySlot()
    {
        item = null;
        count = 0;
    }

    public InventorySlot(ItemDefinition item, int count)
    {
        this.item = item;
        this.count = count;
    }

    public void Clear()
    {
        item = null;
        count = 0;
    }
}

Inventory Class

The core inventory: a fixed-size array of slots with add, remove, and query methods. Raises an event whenever contents change so UI can react.

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

[Serializable]
public class Inventory
{
    [SerializeField] private int maxSlots = 20;
    [SerializeField] private List<InventorySlot> slots;

    public int MaxSlots => maxSlots;
    public IReadOnlyList<InventorySlot> Slots => slots;

    /// <summary>
    /// Fired whenever the inventory contents change.
    /// The int parameter is the slot index that changed (-1 for bulk operations).
    /// </summary>
    public event Action<int> OnChanged;

    public Inventory(int maxSlots)
    {
        this.maxSlots = maxSlots;
        slots = new List<InventorySlot>(maxSlots);
        for (int i = 0; i < maxSlots; i++)
            slots.Add(new InventorySlot());
    }

    /// <summary>
    /// Add an item. Returns the number of items that could NOT be added (overflow).
    /// </summary>
    public int Add(ItemDefinition item, int amount = 1)
    {
        if (item == null || amount <= 0) return amount;

        int remaining = amount;

        // First pass: stack onto existing slots with the same item
        if (item.isStackable)
        {
            for (int i = 0; i < slots.Count && remaining > 0; i++)
            {
                if (slots[i].item == item && slots[i].count < item.maxStackSize)
                {
                    int spaceInSlot = item.maxStackSize - slots[i].count;
                    int toAdd = Mathf.Min(remaining, spaceInSlot);
                    slots[i].count += toAdd;
                    remaining -= toAdd;
                    OnChanged?.Invoke(i);
                }
            }
        }

        // Second pass: place into empty slots
        for (int i = 0; i < slots.Count && remaining > 0; i++)
        {
            if (slots[i].IsEmpty)
            {
                int toAdd = item.isStackable
                    ? Mathf.Min(remaining, item.maxStackSize)
                    : 1;
                slots[i].item = item;
                slots[i].count = toAdd;
                remaining -= toAdd;
                OnChanged?.Invoke(i);
            }
        }

        return remaining; // 0 means everything fit
    }

    /// <summary>
    /// Remove a quantity of an item. Returns the number actually removed.
    /// </summary>
    public int Remove(ItemDefinition item, int amount = 1)
    {
        if (item == null || amount <= 0) return 0;

        int toRemove = amount;

        for (int i = 0; i < slots.Count && toRemove > 0; i++)
        {
            if (slots[i].item == item)
            {
                int removeFromSlot = Mathf.Min(toRemove, slots[i].count);
                slots[i].count -= removeFromSlot;
                toRemove -= removeFromSlot;

                if (slots[i].count <= 0)
                    slots[i].Clear();

                OnChanged?.Invoke(i);
            }
        }

        return amount - toRemove;
    }

    public bool HasItem(ItemDefinition item, int amount = 1)
    {
        return GetCount(item) >= amount;
    }

    public int GetCount(ItemDefinition item)
    {
        int total = 0;
        foreach (var slot in slots)
        {
            if (slot.item == item)
                total += slot.count;
        }
        return total;
    }

    /// <summary>
    /// Swap the contents of two slots (for drag-and-drop rearranging).
    /// </summary>
    public void SwapSlots(int indexA, int indexB)
    {
        if (indexA < 0 || indexA >= slots.Count || indexB < 0 || indexB >= slots.Count) return;

        var temp = new InventorySlot(slots[indexA].item, slots[indexA].count);
        slots[indexA].item = slots[indexB].item;
        slots[indexA].count = slots[indexB].count;
        slots[indexB].item = temp.item;
        slots[indexB].count = temp.count;

        OnChanged?.Invoke(indexA);
        OnChanged?.Invoke(indexB);
    }
}

Equipment System

Equipment slots accept only items of the matching EquipmentSlotType. Equipping an item removes it from inventory and places it in the equipment slot; unequipping does the reverse.

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

[Serializable]
public class EquipmentSystem
{
    private Di
Compartilhar X LinkedIn