tutoriales.com

Creando un Sistema de Inventario Modular en Unity para RPGs y Juegos de Aventura

Este tutorial te guiará paso a paso en la creación de un sistema de inventario robusto y flexible en Unity, esencial para cualquier RPG o juego de aventura. Cubriremos la estructura de datos para ítems, la lógica de ranuras y una interfaz de usuario interactiva, permitiéndote gestionar el equipo y los objetos de tu jugador de manera eficiente.

Intermedio25 min de lectura36 views12 de marzo de 2026Reportar error

¡Bienvenido, aventurero! 🎮 ¿Estás listo para llevar tu juego de Unity al siguiente nivel con un sistema de inventario que tus jugadores amarán? Un buen inventario es el corazón de muchos RPGs y juegos de aventura, permitiendo a los jugadores recolectar, usar y gestionar sus tesoros. En este tutorial, construiremos un sistema modular y extensible que podrás adaptar a casi cualquier tipo de juego.

🎯 ¿Qué aprenderemos en este tutorial?

Al finalizar esta guía, habrás aprendido a:

  • Diseñar la estructura de datos para ítems genéricos y específicos.
  • Implementar la lógica para ranuras de inventario y gestión de ítems.
  • Crear una interfaz de usuario (UI) dinámica para mostrar el inventario.
  • Integrar tu sistema con la interacción del jugador.
  • Establecer las bases para un sistema modular y escalable.
💡 Consejo: Te recomendamos tener conocimientos básicos de C# y el editor de Unity antes de comenzar. ¡Pero no te preocupes, explicaremos todo detalladamente!

📖 1. Entendiendo la Arquitectura: Componentes Clave

Antes de sumergirnos en el código, es crucial entender los pilares de nuestro sistema de inventario. Piensa en él como un conjunto de piezas que trabajan juntas.

Item Base (ScriptableObject) Inventario (MonoBehaviour) Ranura UI (MonoBehaviour) Item en el Mundo (GameObject) Gestor de UI (MonoBehaviour) Contiene Controla Representa Actualiza Definición

1.1. ✨ ScriptableObject para Definir Ítems

Los ScriptableObjects son una herramienta poderosa en Unity para almacenar datos sin estar atados a un GameObject. Son perfectos para definir las propiedades de nuestros ítems (nombre, icono, descripción, tipo, etc.) porque pueden ser creados como assets en tu proyecto y reutilizados por múltiples instancias de ítems.

1.2. 🎒 El Inventario (Sistema Central)

Será el cerebro de nuestro sistema. Un componente MonoBehaviour que se adjuntará al jugador. Se encargará de:

  • Almacenar la lista de ítems actuales.
  • Gestionar añadir/eliminar ítems.
  • Notificar a la UI cuando el inventario cambie.
  • Guardar y cargar el estado del inventario.

1.3. 🖼️ La Ranura UI (Representación Visual)

Cada ranura en la interfaz de usuario de nuestro inventario será un GameObject con un script MonoBehaviour que mostrará el icono, la cantidad y el nombre de un ítem. También manejará la interactividad (clic, arrastrar y soltar).

1.4. 🖥️ El Gestor de UI del Inventario

Este script controlará todo el panel del inventario, generando las ranuras UI dinámicamente, abriendo/cerrando el panel y actuando como un puente entre la lógica del inventario y la interfaz visual.

1.5. 🔍 Ítems en el Mundo (Pickups)

Los ítems que el jugador puede recoger en el juego serán GameObjects con un componente que haga referencia al ScriptableObject de su definición y permita la interacción.


🛠️ 2. Creando la Estructura de Datos para Ítems

Comenzaremos definiendo cómo serán nuestros ítems. Crearemos un ScriptableObject base y luego algunas variaciones.

Crea una nueva carpeta Scripts/Inventory.

2.1. ItemBase.cs (La Plantilla del Ítem)

Este será el ScriptableObject base para todos nuestros ítems. Contendrá las propiedades comunes a todos ellos.

using UnityEngine;

[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item Base")]
public class ItemBase : ScriptableObject
{
    [Header("Item Information")]
    public string itemName = "New Item";
    public Sprite itemIcon = null;
    [TextArea(3, 5)]
    public string itemDescription = "A generic item.";
    public bool isStackable = true; // ¿Se puede apilar?
    public int maxStackSize = 1; // Tamaño máximo de la pila

    [Header("Gameplay Effects")]
    // Aquí puedes añadir propiedades para efectos de juego, como daño, curación, etc.
    public int value = 0; // Valor del item

    // Métodos virtuales para sobrescribir en ítems específicos
    public virtual void Use()
    {
        Debug.Log("Using " + itemName);
        // Lógica común de uso para todos los ítems
    }

    public virtual void OnPickup()
    {
        Debug.Log("Picked up " + itemName);
        // Lógica cuando se recoge el item
    }

    public virtual void OnDrop()
    {
        Debug.Log("Dropped " + itemName);
        // Lógica cuando se suelta el item
    }
}
🔥 Importante: La propiedad `[CreateAssetMenu]` nos permite crear instancias de este `ScriptableObject` directamente desde el menú contextual del proyecto en Unity.

2.2. ConsumableItem.cs (Un Ítem Específico)

Ahora, crearemos un ítem que herede de ItemBase y tenga funcionalidad específica, como un consumible que cure al jugador.

using UnityEngine;

[CreateAssetMenu(fileName = "New Consumable Item", menuName = "Inventory/Consumable Item")]
public class ConsumableItem : ItemBase
{
    [Header("Consumable Properties")]
    public int healthRestored = 0;
    public float duration = 0f; // Para efectos a lo largo del tiempo

    public override void Use()
    {
        base.Use(); // Llama al método base
        Debug.Log("Player health restored by " + healthRestored);
        // Aquí añadirías la lógica para curar al jugador
        // GameManager.Instance.Player.RestoreHealth(healthRestored);
        Debug.Log("Consumed: " + itemName);
    }
}
¿Por qué usar ScriptableObjects para ítems? Los ScriptableObjects son ideales para ítems porque:
  • Reutilización: Puedes crear un solo asset de "Espada Larga" y referenciarlo en múltiples GameObjects o ranuras de inventario sin duplicar datos.
  • Rendimiento: Al ser assets, se cargan una vez en memoria y se comparten, reduciendo el consumo de recursos.
  • Diseño de Datos: Permiten a los diseñadores crear y ajustar ítems fácilmente sin tocar código.
  • Modularidad: Facilitan la creación de nuevos tipos de ítems heredando de una base común.

2.3. Creando Assets de Ítems

En tu ventana Project de Unity, navega a una carpeta como Assets/Items. Haz clic derecho, ve a Create > Inventory y selecciona Item Base o Consumable Item. Nombra tu primer ítem, por ejemplo, PocionSalud. Configura su icono (puedes arrastrar una imagen), descripción, si es apilable y la cantidad de salud que restaura si es una poción.

Paso Hecho


🎒 3. Implementando la Lógica del Inventario Core

Ahora vamos a construir el componente principal que gestionará los ítems. Necesitamos una forma de almacenar ítems y de añadir/eliminar.

3.1. InventorySlot.cs (Representación Lógica de una Ranura)

Cada InventorySlot no es una UI, sino un objeto de C# que contendrá una referencia a un ItemBase y su cantidad. Esto es crucial para la lógica interna.

using UnityEngine;

// La clase [System.Serializable] permite que esta clase sea visible en el Inspector de Unity
[System.Serializable]
public class InventorySlot
{
    public ItemBase item; // Referencia al ScriptableObject del item
    public int quantity; // Cantidad de este item en la ranura

    public InventorySlot(ItemBase item, int quantity)
    {
        this.item = item;
        this.quantity = quantity;
    }

    // Constructor por defecto para ranuras vacías
    public InventorySlot()
    {
        this.item = null;
        this.quantity = 0;
    }

    public bool IsEmpty => item == null; // Propiedad para verificar si la ranura está vacía

    public void AddQuantity(int amount)
    {
        quantity += amount;
    }

    public void RemoveQuantity(int amount)
    {
        quantity -= amount;
        if (quantity <= 0)
        {
            ClearSlot();
        }
    }

    public void ClearSlot()
    {
        item = null;
        quantity = 0;
    }

    public void AssignItem(ItemBase newItem, int newQuantity)
    {
        item = newItem;
        quantity = newQuantity;
    }
}

3.2. InventoryManager.cs (El Cerebro del Inventario)

Este script será un MonoBehaviour que se adjuntará a nuestro jugador o a un GameObject de gestión global. Gestionará la colección de ranuras InventorySlot.

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

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }

    [Header("Inventory Settings")]
    [SerializeField] private int inventorySize = 20;
    public List<InventorySlot> inventorySlots; // La lista de ranuras de nuestro inventario

    // Eventos para notificar a la UI cuando el inventario cambia
    public event Action OnInventoryChanged;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            // DontDestroyOnLoad(gameObject); // Opcional: para que el inventario persista entre escenas
        }
        else
        {
            Destroy(gameObject);
            return;
        }

        InitializeInventory();
    }

    private void InitializeInventory()
    {
        inventorySlots = new List<InventorySlot>(inventorySize);
        for (int i = 0; i < inventorySize; i++)
        {
            inventorySlots.Add(new InventorySlot()); // Inicializar con ranuras vacías
        }
    }

    // Añadir un item al inventario
    public bool AddItem(ItemBase itemToAdd, int quantityToAdd = 1)
    {
        if (itemToAdd == null) return false;

        // 1. Intentar apilar el item en una ranura existente si es stackable
        if (itemToAdd.isStackable)
        {
            foreach (InventorySlot slot in inventorySlots)
            {
                if (!slot.IsEmpty && slot.item == itemToAdd && slot.quantity < itemToAdd.maxStackSize)
                {
                    int remainingSpace = itemToAdd.maxStackSize - slot.quantity;
                    int amountToStack = Mathf.Min(quantityToAdd, remainingSpace);

                    slot.AddQuantity(amountToStack);
                    quantityToAdd -= amountToStack;

                    if (quantityToAdd <= 0)
                    {
                        OnInventoryChanged?.Invoke(); // Notificar cambio
                        return true;
                    }
                }
            }
        }

        // 2. Si quedan items por añadir o no es stackable, buscar una ranura vacía
        while (quantityToAdd > 0)
        {
            InventorySlot emptySlot = GetEmptySlot();
            if (emptySlot == null)
            {
                Debug.LogWarning("Inventory is full! Could not add all items: " + itemToAdd.itemName);
                OnInventoryChanged?.Invoke(); // Notificar cambio (aunque no se haya añadido todo)
                return false; // No hay espacio
            }

            if (itemToAdd.isStackable)
            {
                int amountToAddInSlot = Mathf.Min(quantityToAdd, itemToAdd.maxStackSize);
                emptySlot.AssignItem(itemToAdd, amountToAddInSlot);
                quantityToAdd -= amountToAddInSlot;
            }
            else
            {
                emptySlot.AssignItem(itemToAdd, 1);
                quantityToAdd--;
            }
        }

        OnInventoryChanged?.Invoke(); // Notificar cambio
        return true;
    }

    // Eliminar un item del inventario
    public bool RemoveItem(ItemBase itemToRemove, int quantityToRemove = 1)
    {
        if (itemToRemove == null) return false;

        // Implementa lógica para encontrar y remover items.
        // Puede ser por ranura específica o buscando en todo el inventario.
        // Por simplicidad, aquí buscamos el primero que coincida.
        for (int i = inventorySlots.Count - 1; i >= 0; i--)
        {
            InventorySlot slot = inventorySlots[i];
            if (!slot.IsEmpty && slot.item == itemToRemove)
            {
                if (slot.quantity > quantityToRemove)
                {
                    slot.RemoveQuantity(quantityToRemove);
                    OnInventoryChanged?.Invoke();
                    return true;
                }
                else
                {
                    quantityToRemove -= slot.quantity;
                    slot.ClearSlot();
                    if (quantityToRemove <= 0)
                    {
                        OnInventoryChanged?.Invoke();
                        return true;
                    }
                }
            }
        }

        Debug.LogWarning("Could not remove all items. Item not found or not enough quantity: " + itemToRemove.itemName);
        return false;
    }

    // Usar un item de una ranura específica
    public void UseItem(InventorySlot slot)
    {
        if (slot != null && !slot.IsEmpty)
        {
            slot.item.Use(); // Llama al método Use del ItemBase (o su override)
            // Si es un consumible, reduce la cantidad. Si es equipable, no.
            // Aquí una lógica simple para consumibles:
            if (slot.item is ConsumableItem)
            {
                slot.RemoveQuantity(1);
                OnInventoryChanged?.Invoke(); // Notificar cambio después de usar
            }
        }
    }

    // Obtener la primera ranura vacía
    private InventorySlot GetEmptySlot()
    {
        foreach (InventorySlot slot in inventorySlots)
        {
            if (slot.IsEmpty)
            {
                return slot;
            }
        }
        return null; // No hay ranuras vacías
    }

    // Obtener un item de una ranura específica por índice
    public ItemBase GetItemInSlot(int index)
    {
        if (index >= 0 && index < inventorySlots.Count)
        {
            return inventorySlots[index].item;
        }
        return null;
    }

    // Intercambiar items entre ranuras (para arrastrar y soltar en UI)
    public void SwapItems(int index1, int index2)
    {
        if (index1 < 0 || index1 >= inventorySlots.Count || index2 < 0 || index2 >= inventorySlots.Count)
        {
            Debug.LogWarning("Invalid slot index for swapping.");
            return;
        }

        InventorySlot slot1 = inventorySlots[index1];
        InventorySlot slot2 = inventorySlots[index2];

        // Intercambio simple de contenido
        ItemBase tempItem = slot1.item;
        int tempQuantity = slot1.quantity;

        slot1.AssignItem(slot2.item, slot2.quantity);
        slot2.AssignItem(tempItem, tempQuantity);

        OnInventoryChanged?.Invoke();
    }
}
50% Lógica Base Completada

3.3. Configurando el InventoryManager en Unity

  1. Crea un GameObject vacío en tu escena y nómbralo _InventoryManager.
  2. Adjunta el script InventoryManager.cs a este GameObject.
  3. Ajusta el Inventory Size en el Inspector (e.g., a 20 ranuras).
📌 Nota: Puedes ver la lista `Inventory Slots` en el Inspector, aunque estará vacía al inicio. Esta es la representación lógica de tu inventario.

🖼️ 4. Creando la Interfaz de Usuario (UI) del Inventario

La UI es donde el jugador interactuará con el inventario. Necesitamos un panel principal y ranuras individuales.

4.1. Diseño del Canvas y Panel Principal

  1. En Unity, crea un Canvas (Haz clic derecho en la jerarquía > UI > Canvas).
  2. Asegúrate de que el Render Mode del Canvas sea Screen Space - Camera y arrastra tu cámara principal a Render Camera.
  3. Cambia UI Scale Mode a Scale With Screen Size para que la UI se adapte a diferentes resoluciones (e.g., 1920x1080).
  4. Dentro del Canvas, crea un Empty Object (click derecho > UI > Panel) y nómbralo InventoryPanel. Este será el contenedor de todas nuestras ranuras. Desactívalo inicialmente.

4.2. InventorySlotUI.cs (La Interfaz Visual de una Ranura)

Este script controlará la apariencia y la interactividad de cada ranura individual en la UI.

using UnityEngine;
using UnityEngine.UI;
using TMPro; // Si usas TextMeshPro
using UnityEngine.EventSystems;

public class InventorySlotUI : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    [Header("UI Elements")]
    [SerializeField] private Image itemIcon; // Imagen del icono del item
    [SerializeField] private TextMeshProUGUI itemQuantityText; // Texto para la cantidad (si usas TextMeshPro)
    // [SerializeField] private Text itemQuantityText; // Si usas el Text legacy

    public int slotIndex { get; private set; }
    private InventoryManager inventoryManager;
    private ItemBase currentItem; // El item actualmente en esta ranura

    public void Initialize(int index, InventoryManager manager)
    {
        slotIndex = index;
        inventoryManager = manager;
        UpdateSlotUI(); // Asegura que la UI se actualice al inicializarse
    }

    public void UpdateSlotUI()
    {
        InventorySlot slotData = inventoryManager.inventorySlots[slotIndex];
        currentItem = slotData.item;

        if (!slotData.IsEmpty)
        {
            itemIcon.sprite = slotData.item.itemIcon;
            itemIcon.enabled = true;
            if (slotData.item.isStackable && slotData.quantity > 1)
            {
                itemQuantityText.text = slotData.quantity.ToString();
                itemQuantityText.enabled = true;
            }
            else
            {
                itemQuantityText.enabled = false;
            }
        }
        else
        {
            itemIcon.sprite = null;
            itemIcon.enabled = false;
            itemQuantityText.enabled = false;
        }
    }

    // Lógica para clics (usar item, abrir menú contextual, etc.)
    public void OnPointerClick(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            Debug.Log($"Clicked slot {slotIndex}: {currentItem?.itemName ?? "Empty"}");
            if (currentItem != null)
            {
                inventoryManager.UseItem(inventoryManager.inventorySlots[slotIndex]);
            }
        }
        else if (eventData.button == PointerEventData.InputButton.Right)
        {
            Debug.Log($"Right-clicked slot {slotIndex}");
            // Implementar menú contextual: usar, soltar, equipar, etc.
        }
    }

    // Lógica de arrastrar y soltar (Drag & Drop)
    // Para simplificar, implementaremos un drag & drop básico para intercambiar ítems.
    // Necesitarás un GameObject temporal para el icono que se arrastra.

    private GameObject draggedItemIcon;

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (currentItem != null)
        {
            draggedItemIcon = new GameObject("DraggedItemIcon");
            Image dragImage = draggedItemIcon.AddComponent<Image>();
            dragImage.sprite = itemIcon.sprite;
            dragImage.rectTransform.sizeDelta = itemIcon.rectTransform.sizeDelta; // Mantener tamaño
            dragImage.raycastTarget = false; // Importante para no bloquear el Raycast de la ranura de destino

            draggedItemIcon.transform.SetParent(this.transform.root); // Ponerlo en la raíz del Canvas
            draggedItemIcon.transform.position = eventData.position;
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (draggedItemIcon != null)
        {
            draggedItemIcon.transform.position = eventData.position;
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (draggedItemIcon != null)
        {
            Destroy(draggedItemIcon); // Destruir el icono arrastrado

            // Intentar soltar en otra ranura
            GameObject targetGameObject = eventData.pointerCurrentRaycast.gameObject;
            if (targetGameObject != null)
            {
                InventorySlotUI targetSlot = targetGameObject.GetComponent<InventorySlotUI>();
                if (targetSlot != null && targetSlot != this)
                {
                    inventoryManager.SwapItems(this.slotIndex, targetSlot.slotIndex);
                    Debug.Log($"Swapped item from slot {this.slotIndex} to {targetSlot.slotIndex}");
                }
            }
        }
    }
}
⚠️ Advertencia: Para que el `TextMeshProUGUI` funcione, debes importar TextMeshPro. Ve a `Window > TextMeshPro > Import TMP Essential Resources`.

4.3. Creando el Prefab de la Ranura UI

  1. Dentro de InventoryPanel en el Canvas, crea un UI > Image y nómbralo InventorySlotPrefab.
  2. Ajusta su tamaño (e.g., Width: 64, Height: 64).
  3. Dentro de InventorySlotPrefab, crea un UI > Image (icono) y nómbralo ItemIcon. Ajusta su Rect Transform para que ocupe todo el padre.
  4. Dentro de InventorySlotPrefab, crea un UI > Text - TextMeshPro y nómbralo ItemQuantityText. Anclalo a la esquina inferior derecha y ajusta su tamaño y fuente para que muestre el número de forma legible.
  5. Adjunta el script InventorySlotUI.cs a InventorySlotPrefab.
  6. Arrastra ItemIcon al campo Item Icon y ItemQuantityText al campo Item Quantity Text en el Inspector de InventorySlotUI.
  7. Arrastra InventorySlotPrefab desde la jerarquía a tu carpeta Assets/Prefabs para convertirlo en un prefab. Elimina la instancia de la jerarquía.

4.4. InventoryUIController.cs (Gestor de la UI del Inventario)

Este script creará las ranuras a partir del prefab y mantendrá la UI actualizada.

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

public class InventoryUIController : MonoBehaviour
{
    [Header("UI References")]
    [SerializeField] private GameObject inventoryPanel; // El panel principal del inventario
    [SerializeField] private GameObject slotParent; // El GameObject que contendrá todas las ranuras
    [SerializeField] private GameObject inventorySlotUIPrefab; // Nuestro prefab de ranura UI

    private InventoryManager inventoryManager;
    private List<InventorySlotUI> uiSlots = new List<InventorySlotUI>();

    private void Start()
    {
        inventoryManager = InventoryManager.Instance;
        if (inventoryManager == null)
        {
            Debug.LogError("InventoryManager not found!");
            enabled = false; // Deshabilitar este script si no hay manager
            return;
        }

        inventoryManager.OnInventoryChanged += UpdateAllSlotUIs; // Suscribirse al evento de cambio de inventario
        GenerateUISlots();
        inventoryPanel.SetActive(false); // Asegúrate de que el inventario esté cerrado al inicio
    }

    private void OnDestroy()
    {
        if (inventoryManager != null)
        {
            inventoryManager.OnInventoryChanged -= UpdateAllSlotUIs;
        }
    }

    private void Update()
    {
        // Puedes usar una tecla para abrir/cerrar el inventario
        if (Input.GetKeyDown(KeyCode.I))
        {
            ToggleInventoryUI();
        }
    }

    private void GenerateUISlots()
    {
        // Limpiar ranuras existentes antes de generar nuevas (útil para pruebas o cambios de tamaño)
        foreach (Transform child in slotParent.transform)
        {
            Destroy(child.gameObject);
        }
        uiSlots.Clear();

        for (int i = 0; i < inventoryManager.inventorySlots.Count; i++)
        {
            GameObject slotGO = Instantiate(inventorySlotUIPrefab, slotParent.transform);
            InventorySlotUI uiSlot = slotGO.GetComponent<InventorySlotUI>();
            uiSlot.Initialize(i, inventoryManager);
            uiSlots.Add(uiSlot);
        }
        UpdateAllSlotUIs(); // Actualizar inmediatamente después de generar
    }

    public void UpdateAllSlotUIs()
    {
        for (int i = 0; i < uiSlots.Count; i++)
        {
            uiSlots[i].UpdateSlotUI();
        }
        Debug.Log("Inventory UI Updated!");
    }

    public void ToggleInventoryUI()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        // Aquí podrías pausar el juego, cambiar el cursor, etc.
    }

    // Este método se podría llamar desde un botón de la UI para cerrar el inventario
    public void CloseInventoryUI()
    {
        if (inventoryPanel.activeSelf)
        {
            inventoryPanel.SetActive(false);
        }
    }
}

4.5. Configurando el InventoryUIController en Unity

  1. Crea un GameObject vacío en el Canvas y nómbralo _InventoryUIController.
  2. Adjunta el script InventoryUIController.cs a este GameObject.
  3. En el Inspector, arrastra:
    • InventoryPanel al campo Inventory Panel.
    • El GameObject que contendrá las ranuras (puedes crear un Empty dentro del InventoryPanel y nombrarlo SlotContainer) al campo Slot Parent.
    • Tu prefab InventorySlotPrefab al campo Inventory Slot UI Prefab.
Paso 1: Crear Canvas y Panel Principal.
Paso 2: Crear Prefab de Ranura UI.
Paso 3: Configurar Gestor de UI.
Paso 4: Vincular eventos de actualización.

🔍 5. Creando Ítems Recogibles en el Mundo

Necesitamos una forma de que el jugador interactúe con los ítems en el entorno y los añada a su inventario.

5.1. ItemPickup.cs (Componente de Ítem Recogible)

Este script se adjuntará a cualquier GameObject que represente un ítem en el mundo real que el jugador pueda recoger.

using UnityEngine;

public class ItemPickup : MonoBehaviour
{
    [Header("Item to Pickup")]
    public ItemBase itemDefinition; // Referencia al ScriptableObject del item
    public int quantity = 1;

    private void OnTriggerEnter(Collider other)
    {
        // Asume que el jugador tiene un tag "Player" y un InventoryManager
        if (other.CompareTag("Player"))
        {
            InventoryManager inventory = other.GetComponent<InventoryManager>();
            if (inventory != null)
            {
                if (inventory.AddItem(itemDefinition, quantity))
                {
                    Debug.Log($"Player picked up {quantity} x {itemDefinition.itemName}");
                    itemDefinition.OnPickup(); // Llama a la lógica de pickup del item
                    Destroy(gameObject); // Destruir el item del mundo después de recogerlo
                }
                else
                {
                    Debug.LogWarning("Inventory is full! Could not pick up " + itemDefinition.itemName);
                }
            }
        }
    }

    // Dibuja el icono del item en el editor para facilitar la visualización
    private void OnDrawGizmos()
    {
        if (itemDefinition != null && itemDefinition.itemIcon != null)
        {
            Gizmos.DrawIcon(transform.position, itemDefinition.itemIcon.name, true);
        }
    }
}
💡 Consejo: Asegúrate de que el `GameObject` de tu jugador tenga un `Collider` (con `Is Trigger` activado si usas `OnTriggerEnter`) y un `Rigidbody` para detectar colisiones. Además, tu jugador debe tener el tag "Player".

5.2. Creando un Ítem Recogible en la Escena

  1. Crea un GameObject 3D (e.g., Cube o Sphere) en tu escena y nómbralo Pocion_Pickup.
  2. Ajusta su Scale si es necesario.
  3. Añade un Collider (e.g., Box Collider) y activa Is Trigger.
  4. Adjunta el script ItemPickup.cs.
  5. Arrastra tu asset de PocionSalud (el ScriptableObject creado anteriormente) al campo Item Definition en el Inspector.
  6. Ajusta la Quantity a 1 o más.
  7. Opcionalmente, puedes añadir un Mesh Renderer con un material para que se vea bien o un Sprite Renderer si tu juego es 2D.

Importante: Verifica que tu jugador tenga el tag "Player" y un collider compatible para la detección de pickups.


✅ 6. Probando el Sistema

¡Es hora de ver tu trabajo en acción!

  1. Asegúrate de tener:
    • Un GameObject _InventoryManager con el script InventoryManager adjunto.
    • Un GameObject _InventoryUIController con el script InventoryUIController adjunto y todas sus referencias UI configuradas.
    • Al menos un ScriptableObject de ítem (e.g., PocionSalud).
    • Al menos un GameObject de ItemPickup en la escena referenciando tu PocionSalud.
    • Un GameObject de jugador con el tag "Player", un Collider (Is Trigger = true) y un Rigidbody (Kinematic = true si no quieres física).
  2. Ejecuta el juego.
  3. Mueve a tu jugador para pasar por encima del ItemPickup. Deberías ver un mensaje en la consola de que el ítem ha sido recogido y el GameObject del ítem debería desaparecer.
  4. Presiona la tecla I (o la que hayas configurado en InventoryUIController). El panel del inventario debería aparecer. Deberías ver el icono y la cantidad de tu PocionSalud en una de las ranuras.
  5. Haz clic izquierdo en la ranura de la poción. Deberías ver un mensaje en la consola de que la poción ha sido "usada" y su cantidad debería disminuir si era apilable o desaparecer si solo había una.
  6. Arrastra y suelta el ítem de una ranura a otra. La UI debería actualizarse para reflejar el cambio.

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!