tutoriales.com

Unreal Engine: Creando un Sistema de Inventario Dinámico con UMG y C++

Este tutorial te guiará paso a paso en la creación de un robusto sistema de inventario para tus juegos en Unreal Engine 5. Aprenderás a combinar la potencia de C++ para la lógica de datos y la flexibilidad de UMG para diseñar una interfaz de usuario interactiva y atractiva. Cubriremos la gestión de objetos, la visualización y la interacción del jugador.

Intermedio25 min de lectura6 views24 de marzo de 2026Reportar error

🚀 Introducción al Sistema de Inventario en Unreal Engine

El sistema de inventario es un componente fundamental en la mayoría de los videojuegos modernos, especialmente en géneros como RPG, supervivencia o aventura. Permite a los jugadores recolectar, almacenar y gestionar objetos, lo que añade profundidad y estrategia a la jugabilidad. En este tutorial, exploraremos cómo construir un sistema de inventario dinámico y eficiente utilizando las herramientas de Unreal Engine 5: la potencia de C++ para el backend y la versatilidad de Unreal Motion Graphics (UMG) para el frontend.

¿Por qué C++ y UMG?

Combinar C++ con UMG nos ofrece lo mejor de ambos mundos:

  • C++: Proporciona un rendimiento óptimo, mayor control sobre la memoria y acceso a todas las características del motor. Es ideal para la lógica de datos subyacente del inventario, la gestión de objetos y la comunicación con otros sistemas del juego.
  • UMG: Es el sistema de interfaz de usuario de Unreal Engine, que permite crear interfaces visualmente atractivas e interactivas de forma rápida y eficiente. Perfecto para diseñar la representación visual del inventario, los slots de objetos y las herramientas de interacción del usuario.
💡 Consejo: Aunque este tutorial se centra en C++, muchos de los conceptos de UMG pueden adaptarse fácilmente a Blueprints si prefieres un enfoque más visual para la interfaz.

🛠️ Configuración Inicial del Proyecto

Antes de sumergirnos en la lógica, necesitamos configurar nuestro proyecto.

1. Creación del Proyecto

Comienza creando un nuevo proyecto de Unreal Engine 5. Puedes elegir una plantilla de juego en blanco (Blank) o la plantilla de tercera persona (Third Person) si quieres un personaje preconfigurado para probar el inventario.

📌 Nota: Asegúrate de que el proyecto sea de C++ al crearlo. Si no, no tendrás acceso a la generación de clases C++.

2. Estructura de Carpetas Recomendada

Una buena organización es clave para proyectos grandes. Sugerimos la siguiente estructura en la carpeta Content:

  • Content/Inventory
    • Data (para estructuras de datos, data assets)
    • Items (para blueprints de objetos específicos)
    • Widgets (para todos los widgets UMG)
    • C++ (donde irán tus clases C++ del inventario)
¿Por qué es importante la organización de carpetas?Una estructura de carpetas clara facilita la navegación, el mantenimiento del proyecto y el trabajo en equipo. Previene la "espiral de la desorganización" que puede surgir en proyectos grandes.

📖 Paso 1: Definiendo los Datos del Objeto (C++)

El primer paso es definir qué es un objeto en nuestro inventario. Usaremos una estructura de datos para almacenar la información básica de cada ítem.

1.1. Creando la Clase Base de Objeto (UObject)

Crearemos una clase base UInventoryItem que herede de UObject. Esto nos permitirá tener instancias de objetos de inventario gestionadas por el recolector de basura de Unreal y replicarlas fácilmente si el juego es multijugador.

En el Editor de Unreal, ve a Tools > New C++ Class.... Selecciona UObject como clase padre y nómbrala InventoryItem (o InventoryObject para evitar conflictos con AActor).

Archivo InventoryItem.h:

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "InventoryItem.generated.h"

UCLASS(Blueprintable, BlueprintType)
class YOURPROJECT_API UInventoryItem : public UObject
{
    GENERATED_BODY()

public:
    UInventoryItem();

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    FText ItemName;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    FText ItemDescription;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    UTexture2D* Thumbnail;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    int32 Weight;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    int32 MaxStackSize; // Cuántos de este item se pueden apilar

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item Info")
    bool bIsStackable; // ¿Se puede apilar este item?

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Runtime Info")
    int32 CurrentStackSize; // Cantidad actual de este item en un slot

    void SetCurrentStackSize(int32 NewSize) { CurrentStackSize = NewSize; }
};

Archivo InventoryItem.cpp:

#include "InventoryItem.h"

UInventoryItem::UInventoryItem()
    : ItemName(FText::FromString("New Item")),
      ItemDescription(FText::FromString("Generic item description")),
      Thumbnail(nullptr),
      Weight(1),
      MaxStackSize(1),
      bIsStackable(false),
      CurrentStackSize(1)
{
}

🔥 Importante: Compila tu proyecto después de añadir nuevas clases C++.

📋 Paso 2: Creando el Componente de Inventario (C++)

Ahora necesitamos un lugar donde almacenar estos objetos. Crearemos un UActorComponent que se pueda añadir a cualquier actor (como el jugador) para darle capacidades de inventario.

2.1. Creando el Componente

Crea una nueva clase C++ que herede de UActorComponent y nómbrala InventoryComponent.

Archivo InventoryComponent.h:

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InventoryItem.h"
#include "InventoryComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInventoryUpdated, const TArray<UInventoryItem*>&, CurrentInventory);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class YOURPROJECT_API UInventoryComponent : public UActorComponent
{
    GENERATED_BODY()

public:	
    UInventoryComponent();

protected:
    virtual void BeginPlay() override;

public:	
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory")
    int32 Capacity; // Número máximo de slots

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Inventory")
    TArray<UInventoryItem*> Items; // Los items actuales en el inventario

    UFUNCTION(BlueprintCallable, Category = "Inventory")
    bool AddItem(UInventoryItem* ItemToAdd);

    UFUNCTION(BlueprintCallable, Category = "Inventory")
    bool RemoveItem(UInventoryItem* ItemToRemove);

    UFUNCTION(BlueprintCallable, Category = "Inventory")
    void ClearInventory();

    // Delegate para notificar a la UI cuando el inventario cambia
    UPROPERTY(BlueprintAssignable, Category = "Inventory")
    FOnInventoryUpdated OnInventoryUpdated;

    void NotifyInventoryUpdated();

protected:
    bool TryStackItem(UInventoryItem* ItemToAdd);
    void AddNewItem(UInventoryItem* ItemToAdd);

};

Archivo InventoryComponent.cpp:

#include "InventoryComponent.h"
#include "Net/UnrealNetwork.h"

UInventoryComponent::UInventoryComponent()
{
    PrimaryComponentTick.bCanEverTick = false;
    Capacity = 10; // Capacidad inicial
    SetIsReplicatedByDefault(true); // Es importante para multijugador
}

void UInventoryComponent::BeginPlay()
{
    Super::BeginPlay();

    // Inicializar el array de ítems con punteros nulos para representar slots vacíos
    Items.Init(nullptr, Capacity);
}

void UInventoryComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    DOREPLIFETIME(UInventoryComponent, Items);
    DOREPLIFETIME(UInventoryComponent, Capacity);
}

void UInventoryComponent::NotifyInventoryUpdated()
{
    OnInventoryUpdated.Broadcast(Items);
}

bool UInventoryComponent::AddItem(UInventoryItem* ItemToAdd)
{    
    if (!ItemToAdd) return false;

    // Si es apilable, intenta apilarlo
    if (ItemToAdd->bIsStackable && TryStackItem(ItemToAdd))
    {
        NotifyInventoryUpdated();
        return true;
    }

    // Si no es apilable o no se pudo apilar, busca un slot vacío
    int32 EmptySlotIndex = Items.Find(nullptr);
    if (EmptySlotIndex != INDEX_NONE && EmptySlotIndex < Capacity)
    {
        // Creamos una nueva instancia del ítem para que cada slot tenga su propia instancia
        // Esto es crucial para manejar CurrentStackSize de forma individual
        UInventoryItem* NewInstance = DuplicateObject<UInventoryItem>(ItemToAdd, this);
        NewInstance->SetCurrentStackSize(ItemToAdd->bIsStackable ? ItemToAdd->CurrentStackSize : 1);
        Items[EmptySlotIndex] = NewInstance;
        NotifyInventoryUpdated();
        return true;
    }

    // No hay slots disponibles
    return false;
}

bool UInventoryComponent::RemoveItem(UInventoryItem* ItemToRemove)
{
    if (!ItemToRemove) return false;

    int32 ItemIndex = Items.Find(ItemToRemove);
    if (ItemIndex != INDEX_NONE)
    {
        // Si el ítem es apilable y tiene más de uno, solo decrementamos la cantidad
        if (ItemToRemove->bIsStackable && ItemToRemove->CurrentStackSize > 1)
        {
            ItemToRemove->SetCurrentStackSize(ItemToRemove->CurrentStackSize - 1);
        }
        else // Si es uno solo o no apilable, lo eliminamos del slot
        {
            Items[ItemIndex] = nullptr;
            ItemToRemove->MarkAsGarbage(); // Marcar para eliminación por el GC
        }
        NotifyInventoryUpdated();
        return true;
    }
    return false;
}

void UInventoryComponent::ClearInventory()
{
    for (UInventoryItem* Item : Items)
    {
        if (Item) Item->MarkAsGarbage();
    }
    Items.Init(nullptr, Capacity);
    NotifyInventoryUpdated();
}

bool UInventoryComponent::TryStackItem(UInventoryItem* ItemToAdd)
{
    for (UInventoryItem* ExistingItem : Items)
    {
        if (ExistingItem && ExistingItem->GetClass() == ItemToAdd->GetClass() && ExistingItem->bIsStackable)
        {
            int32 SpaceLeft = ExistingItem->MaxStackSize - ExistingItem->CurrentStackSize;
            if (SpaceLeft > 0)
            {
                int32 AmountToStack = FMath::Min(SpaceLeft, ItemToAdd->CurrentStackSize);
                ExistingItem->SetCurrentStackSize(ExistingItem->CurrentStackSize + AmountToStack);
                ItemToAdd->SetCurrentStackSize(ItemToAdd->CurrentStackSize - AmountToStack);

                if (ItemToAdd->CurrentStackSize <= 0)
                {
                    ItemToAdd->MarkAsGarbage(); // El ítem original fue completamente apilado
                    return true;
                }
                // Si aún quedan ítems en ItemToAdd, intentará apilarlos en otro slot o añadirlos como nuevo
            }
        }
    }
    return false; // No se pudo apilar completamente o no se encontró un stack compatible
}

⚠️ Advertencia: La lógica de `AddItem` y `RemoveItem` debe ser robusta para manejar la replicación en multijugador. En este ejemplo, `DOREPLIFETIME` está presente para `Items` y `Capacity`, pero la implementación de las funciones en sí debería ser llamada en el servidor.

🎨 Paso 3: Diseño de la Interfaz de Usuario (UMG)

Ahora crearemos los widgets UMG para visualizar y permitir la interacción con nuestro inventario.

3.1. Widget de Slot de Inventario (WBP_InventorySlot)

Este widget representará un único slot en el inventario, mostrando el icono del ítem y su cantidad.

  1. En la carpeta Content/Inventory/Widgets, crea un nuevo User Widget y nómbralo WBP_InventorySlot.

  2. Abre WBP_InventorySlot.

  3. Jerarquía de Widgets:

    • CanvasPanel (Root)
    • SizeBox (para tamaño fijo del slot, e.g., 64x64)
      • Border (fondo visual del slot)
        • Overlay
          • Image (para el icono del ítem, nombre: ItemThumbnail)
          • TextBlock (para la cantidad del ítem, nombre: ItemQuantity, alineado abajo a la derecha)
  4. En el Graph de WBP_InventorySlot:

    • Crea una variable UInventoryItem* ItemReference (Editable, Expose on Spawn).
    • En Event Pre Construct, actualiza la visibilidad del icono y la cantidad basándose en ItemReference.
Inicio ¿ItemReference es válido? SÍ (True) Configurar Visibilidad: Visible (Thumbnail y Quantity) Establecer Texto de Cantidad Cargar Textura Thumbnail NO (False) Configurar Visibilidad: Colapsado / Oculto Fin

3.2. Widget de Inventario Principal (WBP_InventoryScreen)

Este será el widget principal que contendrá todos los slots del inventario.

  1. En la carpeta Content/Inventory/Widgets, crea un nuevo User Widget y nómbralo WBP_InventoryScreen.

  2. Abre WBP_InventoryScreen.

  3. Jerarquía de Widgets:

    • CanvasPanel (Root)
    • Border (fondo del inventario)
      • VerticalBox
        • TextBlock (Título: "Inventario")
        • UniformGridPanel (nombre: InventoryGrid, donde se añadirán los WBP_InventorySlot dinámicamente)
  4. En el Graph de WBP_InventoryScreen:

    • Crea una variable UInventoryComponent* OwningInventory (Editable).
    • Crea una función RefreshInventoryUI.
    • Dentro de RefreshInventoryUI:
      • Limpia el InventoryGrid.
      • Itera sobre OwningInventory->Items.
      • Por cada ítem:
        • Crea un WBP_InventorySlot.
        • Pasa el ítem actual al WBP_InventorySlot (Set ItemReference).
        • Añade el WBP_InventorySlot al InventoryGrid.
Inicio Limpiar InventoryGrid BUCLE Para cada Item en OwningInventory Crear WBP_InventorySlot Asignar Item al Slot Añadir Slot a InventoryGrid Fin No hay más items
  1. En el Event Construct de WBP_InventoryScreen:
    • Asegúrate de que OwningInventory esté asignado (por ejemplo, desde el personaje).
    • Llama a RefreshInventoryUI.
    • Suscríbete al delegado OnInventoryUpdated de OwningInventory y conéctalo a RefreshInventoryUI.
💡 Consejo: Usa `WrapBox` en lugar de `UniformGridPanel` si quieres que los slots se ajusten automáticamente a diferentes tamaños de pantalla o a un número variable de ítems por fila.

🔗 Paso 4: Conectando C++ con UMG

Ahora enlazaremos la lógica de C++ con la interfaz UMG.

4.1. Creando un Item de Blueprint Derivado

  1. Ve a tu carpeta Content/Inventory/Items.
  2. Haz clic derecho -> Blueprint Class.
  3. En All Classes, busca y selecciona InventoryItem (tu clase C++).
  4. Nómbralo BP_HealthPotion.
  5. Abre BP_HealthPotion y configura sus propiedades por defecto:
    • Item Name: "Poción de Salud"
    • Item Description: "Restaura 50 puntos de vida."
    • Thumbnail: Asigna una textura (puedes usar una de los starter content o crear una simple).
    • Weight: 1
    • Max Stack Size: 5 (si quieres que sea apilable)
    • Is Stackable: true

4.2. Añadiendo el Inventario al Personaje (Blueprint)

  1. Abre tu Blueprint de personaje (e.g., BP_ThirdPersonCharacter).
  2. En la pestaña Components, haz clic en Add y busca InventoryComponent.
  3. Asigna la capacidad deseada a tu InventoryComponent.

4.3. Mostrando el Inventario en Pantalla

En tu Blueprint de personaje:

  1. En el Event Graph, busca un evento de entrada (e.g., Input Action (E) o Input Action (I) para Inventario).
  2. Cuando se presione la tecla:
    • Comprueba si el widget de inventario ya está creado. Si no, créalo.
    • Si no es visible, añádelo al viewport y muestra el cursor del ratón.
    • Si ya es visible, quítalo del viewport y oculta el cursor.
    • Importante: Cuando crees WBP_InventoryScreen, asegúrate de pasarle la referencia a tu InventoryComponent (la variable OwningInventory).
Input (I) Pressed ¿InventoryWidget es válido? Si No Crear WBP_Inventory Asignar InventoryComp Añadir a Viewport Mostrar Cursor Set Input Mode UI ¿Es visible en pantalla? Si No Quitar de Viewport Ocultar Cursor Añadir a Viewport Mostrar Cursor Set Input Mode UI FIN

✨ Paso 5: Implementando la Recolección de Ítems

Para que el inventario sea útil, necesitamos poder añadir ítems a él.

5.1. Clase Base de Recolectable (Actor)

Crea una nueva clase C++ que herede de AActor y nómbrala CollectibleActor.

Archivo CollectibleActor.h:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InventoryItem.h"
#include "CollectibleActor.generated.h"

UCLASS()
class YOURPROJECT_API ACollectibleActor : public AActor
{
    GENERATED_BODY()
    
public:	
    ACollectibleActor();

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UStaticMeshComponent* MeshComponent;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    class USphereComponent* SphereComponent;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    TSubclassOf<UInventoryItem> ItemClass;

protected:
    virtual void BeginPlay() override;

    UFUNCTION()
    void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

public:	
    // Función para obtener el ítem instanciado por este recolectable
    UFUNCTION(BlueprintCallable, Category = "Item")
    UInventoryItem* GetItemInstance();

protected:
    // Instancia del ítem que será añadida al inventario
    UPROPERTY()
    UInventoryItem* ItemInstance;
};

Archivo CollectibleActor.cpp:

#include "CollectibleActor.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SphereComponent.h"
#include "InventoryComponent.h"
#include "Kismet/GameplayStatics.h"

ACollectibleActor::ACollectibleActor()
{
    PrimaryActorTick.bCanEverTick = false;

    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
    RootComponent = MeshComponent;

    SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
    SphereComponent->SetupAttachment(RootComponent);
    SphereComponent->SetSphereRadius(50.f);
    SphereComponent->OnComponentBeginOverlap.AddDynamic(this, &ACollectibleActor::OnOverlapBegin);

    ItemClass = UInventoryItem::StaticClass(); // Clase por defecto
}

void ACollectibleActor::BeginPlay()
{
    Super::BeginPlay();
    
    if (ItemClass)
    {
        ItemInstance = NewObject<UInventoryItem>(this, ItemClass);
    }
}

void ACollectibleActor::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor && OtherActor != this && ItemInstance)
    {
        UInventoryComponent* Inventory = OtherActor->FindComponentByClass<UInventoryComponent>();
        if (Inventory)
        {
            if (Inventory->AddItem(ItemInstance))
            {
                // Si el ítem se añadió con éxito, destruir este actor recolectable
                Destroy();
            }
        }
    }
}

UInventoryItem* ACollectibleActor::GetItemInstance()
{
    return ItemInstance;
}

5.2. Creando un Blueprint de Recolectable

  1. Crea un nuevo Blueprint Class basado en CollectibleActor en Content/Inventory/Items.
  2. Nómbralo BP_Collectible_HealthPotion.
  3. Abre BP_Collectible_HealthPotion.
    • Asigna un Static Mesh a MeshComponent (e.g., una esfera o un cubo del starter content).
    • Asegúrate de que Item Class esté configurado a BP_HealthPotion (la clase de ítem de blueprint que creaste antes).
  4. Arrastra algunas instancias de BP_Collectible_HealthPotion al nivel.

🎮 Paso 6: Interacción y Funcionalidad Adicional

Un inventario no solo muestra ítems, también permite interactuar con ellos.

6.1. Funcionalidad de 'Usar Ítem' (UInventoryItem)

Podemos añadir una función virtual UseItem a nuestra clase base UInventoryItem para que los ítems puedan tener efectos.

Archivo InventoryItem.h (actualizado):

// ... (código anterior)

UCLASS(Blueprintable, BlueprintType)
class YOURPROJECT_API UInventoryItem : public UObject
{
    GENERATED_BODY()

public:
    UInventoryItem();

    // ... (propiedades anteriores)

    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Item Actions")
    void UseItem(AActor* Character);
    virtual void UseItem_Implementation(AActor* Character);
};

Archivo InventoryItem.cpp (actualizado):

// ... (código anterior)

void UInventoryItem::UseItem_Implementation(AActor* Character)
{
    // Lógica por defecto para usar un ítem
    UE_LOG(LogTemp, Warning, TEXT("Using item: %s"), *ItemName.ToString());
}

Ahora, en tu BP_HealthPotion (el Blueprint de ítem), puedes sobrescribir el evento UseItem_Implementation para añadir la lógica específica, como curar al personaje. Luego, en InventoryComponent, puedes crear una función UseItemInSlot que llame a este método y luego a RemoveItem.

6.2. Funcionalidad de Arrastrar y Soltar (Drag & Drop)

Implementar Drag & Drop es más complejo y requiere:

  1. UMG Drag & Drop Operation: Una clase UMG que define qué sucede cuando se arrastra un ítem.
  2. Widgets que pueden arrastrar: Tu WBP_InventorySlot necesita un evento OnMouseButtonDown para iniciar la operación de arrastre.
  3. Widgets que pueden soltar: Tu WBP_InventorySlot y WBP_InventoryScreen necesitarán OnDrop para manejar dónde se suelta el ítem (moverse entre slots, soltar fuera para descartar).

Este es un tema avanzado por sí mismo, pero es fundamental para un inventario moderno.

Ejemplo básico de Drag & Drop para un slot

En WBP_InventorySlot Graph:

EVENT OnMouseButtonDown (Left Mouse Button)
    IF ItemReference IS VALID
        Create Drag and Drop Operation (MyDragDropOperation)
        SET Payload (MyDragDropOperation) TO ItemReference
        SET DefaultDragVisual (MyDragDropOperation) TO CreateWidget(WBP_ItemDragVisual)
        DO Drag (MyDragDropOperation)
    END IF
END EVENT

En WBP_InventorySlot Graph (para soltar un ítem en otro slot):

EVENT OnDrop
    CAST DragAndDropOperation TO MyDragDropOperation
    IF CAST IS SUCCESSFUL
        GET ItemReference FROM MyDragDropOperation (This is the dragged item)
        // Lógica para intentar mover el itemDragged al slot de este widget
        // Esto probablemente requerirá llamar a funciones en el OwningInventoryComponent
    END IF
END EVENT

6.3. Mejoras Avanzadas

  • Replicación de Inventario: Asegúrate de que todas las modificaciones del inventario (añadir/quitar ítems, cambiar cantidades) se realicen en el servidor para juegos multijugador y se repliquen a los clientes.
  • Persistencia: Guarda y carga el estado del inventario utilizando el sistema de guardado de Unreal Engine (USaveGame).
  • Información Detallada (Tooltips): Crea un widget adicional que muestre información detallada del ítem cuando el jugador pase el ratón por encima de un slot.
  • Equipamiento: Un sistema para equipar ítems en ranuras específicas (armas, armaduras, accesorios).

✅ Conclusión

Has llegado al final de este extenso tutorial sobre cómo crear un sistema de inventario dinámico en Unreal Engine 5, combinando la potencia de C++ para la lógica de datos y la flexibilidad de UMG para la interfaz de usuario. Hemos cubierto la definición de ítems, la creación del componente de inventario, el diseño de los widgets y la implementación básica de la recolección.

Este es solo el comienzo. Un sistema de inventario es un componente complejo que puede expandirse con muchas más características, como sistemas de equipamiento, crafteo, almacenamiento, comercio y más. ¡Experimenta, itera y adapta estas bases a las necesidades específicas de tu juego!

Tutorial Completado

Tutoriales relacionados

Comentarios (0)

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