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.
¡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.
📖 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.
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
}
}
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();
}
}
3.3. Configurando el InventoryManager en Unity
- Crea un
GameObjectvacío en tu escena y nómbralo_InventoryManager. - Adjunta el script
InventoryManager.csa esteGameObject. - Ajusta el
Inventory Sizeen el Inspector (e.g., a 20 ranuras).
🖼️ 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
- En Unity, crea un
Canvas(Haz clic derecho en la jerarquía >UI > Canvas). - Asegúrate de que el
Render Modedel Canvas seaScreen Space - Cameray arrastra tu cámara principal aRender Camera. - Cambia
UI Scale ModeaScale With Screen Sizepara que la UI se adapte a diferentes resoluciones (e.g., 1920x1080). - Dentro del
Canvas, crea unEmpty Object(click derecho >UI > Panel) y nómbraloInventoryPanel. 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}");
}
}
}
}
}
4.3. Creando el Prefab de la Ranura UI
- Dentro de
InventoryPanelen elCanvas, crea unUI > Imagey nómbraloInventorySlotPrefab. - Ajusta su tamaño (e.g.,
Width: 64,Height: 64). - Dentro de
InventorySlotPrefab, crea unUI > Image(icono) y nómbraloItemIcon. Ajusta suRect Transformpara que ocupe todo el padre. - Dentro de
InventorySlotPrefab, crea unUI > Text - TextMeshProy nómbraloItemQuantityText. Anclalo a la esquina inferior derecha y ajusta su tamaño y fuente para que muestre el número de forma legible. - Adjunta el script
InventorySlotUI.csaInventorySlotPrefab. - Arrastra
ItemIconal campoItem IconyItemQuantityTextal campoItem Quantity Texten el Inspector deInventorySlotUI. - Arrastra
InventorySlotPrefabdesde la jerarquía a tu carpetaAssets/Prefabspara 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
- Crea un
GameObjectvacío en elCanvasy nómbralo_InventoryUIController. - Adjunta el script
InventoryUIController.csa esteGameObject. - En el Inspector, arrastra:
InventoryPanelal campoInventory Panel.- El
GameObjectque contendrá las ranuras (puedes crear unEmptydentro delInventoryPanely nombrarloSlotContainer) al campoSlot Parent. - Tu prefab
InventorySlotPrefabal campoInventory Slot UI Prefab.
🔍 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);
}
}
}
5.2. Creando un Ítem Recogible en la Escena
- Crea un
GameObject3D (e.g.,CubeoSphere) en tu escena y nómbraloPocion_Pickup. - Ajusta su
Scalesi es necesario. - Añade un
Collider(e.g.,Box Collider) y activaIs Trigger. - Adjunta el script
ItemPickup.cs. - Arrastra tu asset de
PocionSalud(elScriptableObjectcreado anteriormente) al campoItem Definitionen el Inspector. - Ajusta la
Quantitya 1 o más. - Opcionalmente, puedes añadir un
Mesh Renderercon un material para que se vea bien o unSprite Renderersi 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!
- Asegúrate de tener:
- Un
GameObject_InventoryManagercon el scriptInventoryManageradjunto. - Un
GameObject_InventoryUIControllercon el scriptInventoryUIControlleradjunto y todas sus referencias UI configuradas. - Al menos un
ScriptableObjectde ítem (e.g.,PocionSalud). - Al menos un
GameObjectdeItemPickupen la escena referenciando tuPocionSalud. - Un
GameObjectde jugador con el tag "Player", unCollider(Is Trigger = true) y unRigidbody(Kinematic = true si no quieres física).
- Un
- Ejecuta el juego.
- 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 elGameObjectdel ítem debería desaparecer. - Presiona la tecla
I(o la que hayas configurado enInventoryUIController). El panel del inventario debería aparecer. Deberías ver el icono y la cantidad de tuPocionSaluden una de las ranuras. - 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.
- 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!