UE4 | Inventario para multijugador # 1 | Data Warehouse en DataAsset




Conjunto de datos En este artículo trataré de revelar el significado y la metodología de crear DataAsset , como un repositorio para varios tipos de datos, y en nuestro caso es una biblioteca para Actores y sus parámetros.




Una pequeña introducción para saltar

Para tomar la decisión de crear un juego hace aproximadamente 2 años, me ayudó a encontrar accidentalmente información sobre Unreal Engine 4 y leer lo genial y simple que es. De hecho, es muy difícil para una persona que no sabe cómo escribir código (un lenguaje de programación no importa en este contexto) crear algo que sea más complicado que una pequeña modificación de un conjunto estándar de piezas de trabajo del motor. Por lo tanto, el deseo inicial de hacer un súper mega juego, con el crecimiento del conocimiento sobre la realidad de este proyecto, gradualmente se convirtió en un hobby. Elevar todas las capas del desarrollo del juego, desde el modelado y la animación en 3D, hasta la escritura de código, para una persona parece una empresa poco factible. Sin embargo, este es un buen ejercicio para el cerebro.


¿Por qué decidiste escribir algo? ... Probablemente por eso. que los manuales presentados dan un conocimiento muy superficial (y hay la mayoría de ellos), o incluso para un profesional muy y contienen solo instrucciones generales.


Casi siempre es mejor comenzar desde el principio. No puedo decir que siempre hago esto, pero intentaré decir lo más coherente posible.


Por supuesto, es mejor comenzar con la estructura, pero, desafortunadamente, al tener una caja cerrada con herramientas, es muy difícil entender qué se puede construir exactamente con su ayuda. Así que abramos este cuadro y veamos qué hay dentro.




La primera pregunta a responder. ¿Por qué DataAsset ?


  1. Muy a menudo en artículos y tutoriales puede ver el uso de DataTable . ¿Por qué es esto malo? Si almacena una dirección para un Blueprint específico, al cambiarle el nombre o moverlo a otra carpeta, se verá obligado a cambiar esta dirección manualmente. De acuerdo, ¿incómodo? Con DataAsset , esto no sucederá. Todas las comunicaciones se actualizarán automáticamente. Si tiene absoluta confianza en la estructura de su proyecto en los años venideros, entonces, por supuesto, puede usar tablas.
  2. La segunda ventaja innegable es la capacidad de almacenar tipos de datos complejos, como estructuras ( Struct ).

Ahora un poco sobre las desventajas relativas. De hecho, solo veo uno. Esta es la necesidad de escribir código C ++ .


Si ya comprende que sin trabajar con el código no hará nada épico , entonces esto no es un inconveniente, sino una característica.


Cabe señalar que hay una solución alternativa: utilizar Actor como tal repositorio. Pero esa aplicación parece la última excusa para no querer aprender C ++, y tiene el potencial de terminar en un callejón sin salida en el futuro.
Si está convencido de que todo lo que necesita para su proyecto se puede hacer en Blueprint , use las tablas.




Ahora que ya creyó que DataAsset es bueno, considere cómo puede crearlo para su proyecto.


Para aquellos que todavía están completamente 'no en el tanque'
Hay una descripción muy detallada de los pasos y con imágenes en el foro en ruso dedicado a UE4 . Simplemente busque en Google "UE4 DataAsset" para . Él dominó los conceptos básicos de este manual hace aproximadamente un año.

En primer lugar, cree una clase C ++ , como Child de UDataAsset .
(Todo el código a continuación está tomado de mi proyecto no nacido. Simplemente cambie el nombre de los nombres como desee).


/// Copyright 2018 Dreampax Games, Inc. All Rights Reserved. #pragma once /* Includes from Engine */ #include "Engine/DataAsset.h" #include "Engine/Texture2D.h" #include "GameplayTagContainer.h" /* Includes from Dreampax */ //no includes #include "DreampaxItemsDataAsset.generated.h" UCLASS(BlueprintType) class DREAMPAX_API UDreampaxItemsDataAsset : public UDataAsset { GENERATED_BODY() } 

Ahora, sobre la base de esta clase, puede crear Blueprint de forma segura, pero es demasiado pronto para hacerlo ... hasta ahora es solo un muñeco. Sin embargo, tenga en cuenta que ya se han hecho inclusiones para texturas y nombres.




A partir de este momento, comienza a crear la estructura de su repositorio. Se volverá a hacer muchas veces, por lo que le recomiendo no llenar inmediatamente su almacenamiento. De tres a cinco elementos, en nuestro caso artículos de inventario, son suficientes para las pruebas. A veces, después de la compilación, su Blueprint puede quedar vacío, lo que es extremadamente desagradable si ya ha ocupado una docena o dos posiciones.


Puede crear una estructura directamente en el archivo de encabezado, porque en este caso, es poco probable que se aplique en otro lugar. Por lo general, prefiero hacerlo como un archivo de encabezado separado "SrtuctName.h" y conectarlo cuando sea necesario según sea necesario.


En mi caso, se ve así
 USTRUCT(BlueprintType) struct FItemsDatabase { GENERATED_USTRUCT_BODY() /* Storage for any float constant data */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TMap<FGameplayTag, float> ItemData; /* Gameplay tag container to store the properties */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") FGameplayTagContainer ItemPropertyTags; /* Texture for showing in the inventory */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") UTexture2D* IconTexture; /* The class put on the Mesh on the character */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TSubclassOf<class ADreampaxOutfitActor> ItemOutfitClass; /* The class to spawn the Mesh in the level then it is dropped */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TSubclassOf<class ADreampaxPickupActor> ItemPickupClass; //TODO internal call functions }; 

Ser cuentas con TMap . ¡No replicado! En este caso, no importa.


Tenga en cuenta que no uso FName . Según las tendencias modernas, el uso de FGameplayTag se considera más correcto, porque Reduce significativamente el riesgo de error y tiene varias ventajas que serán útiles más adelante.


GameplayTag en el editor
Gameplaytag

DataTable para GameplayTag exportado desde Excel
DataTable

También es una buena práctica definir funciones para llamar a variables en la estructura, como GetSomething () . Aparentemente, todavía necesito trabajar en mi educación, ya que está en esta base de datos, todavía no he hecho esa llamada.


Así es como se puede hacer usando otra base de datos como ejemplo.
 USTRUCT(BlueprintType) struct FBlocksDatabase { GENERATED_USTRUCT_BODY() /* The class put on the Mesh for the building block */ UPROPERTY(EditDefaultsOnly, Category = "BlocksDatabase") TSubclassOf<class ADreampaxBuildingBlock> BuildingBlockClass; UPROPERTY(EditDefaultsOnly, Category = "BlocksDatabase") FVector DefaultSize; UPROPERTY(EditDefaultsOnly, Category = "BlocksDatabase") FVector SizeLimits; UPROPERTY(EditDefaultsOnly, Category = "BlocksDatabase") TArray<class UMaterialInterface *> BlockMaterials; FORCEINLINE TSubclassOf<class ADreampaxBuildingBlock> * GetBuildingBlockClass() { return &BuildingBlockClass; } FORCEINLINE FVector GetDefaultSize() { return DefaultSize; } FORCEINLINE FVector GetSizeLimits() { return SizeLimits; } FORCEINLINE TArray<class UMaterialInterface *> GetBlockMaterials() { return BlockMaterials; } }; 

Y el punto más importante es la declaración de la base de datos:


 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ItemsDatabase") TMap<FGameplayTag, FItemsDatabase> ItemsDataBase; 

Ahora ya puede crear nuestro Blueprint y llenarlo.


Ejemplo de relleno de DataAsset
Ejemplo de relleno de DataAsset

Pero antes de eso, escribiremos algunas funciones de llamada más para poder recibir datos de la base de datos.


DreampaxItemsDataAsset.h
 /// Copyright 2018 Dreampax Games, Inc. All Rights Reserved. #pragma once /* Includes from Engine */ #include "Engine/DataAsset.h" #include "Engine/Texture2D.h" #include "GameplayTagContainer.h" /* Includes from Dreampax */ //no includes #include "DreampaxItemsDataAsset.generated.h" USTRUCT(BlueprintType) struct FItemsDatabase { GENERATED_USTRUCT_BODY() /* Storage for any float constant data */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TMap<FGameplayTag, float> ItemData; /* Gameplay tag container to store the properties */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") FGameplayTagContainer ItemPropertyTags; /* Texture for showing in the inventory */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") UTexture2D* IconTexture; /* The class put on the Mesh on the character */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TSubclassOf<class ADreampaxOutfitActor> ItemOutfitClass; /* The class to spawn the Mesh in the level then it is dropped */ UPROPERTY(EditDefaultsOnly, Category = "ItemsDatabase") TSubclassOf<class ADreampaxPickupActor> ItemPickupClass; //TODO internal call functions }; UCLASS(BlueprintType) class DREAMPAX_API UDreampaxItemsDataAsset : public UDataAsset { GENERATED_BODY() protected: /* This GameplayTag is used to find a Max size of the stack for the Item. This tag can be missed in the ItemData */ UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ItemsDatabase") FGameplayTag DefaultGameplayTagForMaxSizeOfStack; /* This is the main Database for all Items. It contains constant common variables */ UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ItemsDatabase") TMap<FGameplayTag, FItemsDatabase> ItemsDataBase; public: FORCEINLINE TMap<FGameplayTag, float> * GetItemData(const FGameplayTag &ItemNameTag); FORCEINLINE FGameplayTagContainer * GetItemPropertyTags(const FGameplayTag &ItemNameTag); /* Used in the widget */ UFUNCTION(BlueprintCallable, Category = "ItemDatabase") FORCEINLINE UTexture2D * GetItemIconTexture(const FGameplayTag & ItemNameTag) const; FORCEINLINE TSubclassOf<class ADreampaxOutfitActor> * GetItemOutfitClass(const FGameplayTag & ItemNameTag); FORCEINLINE TSubclassOf<class ADreampaxPickupActor> * GetItemPickupClass(const FGameplayTag & ItemNameTag); int GetItemMaxStackSize(const FGameplayTag & ItemNameTag); FORCEINLINE bool ItemIsFound(const FGameplayTag & ItemNameTag) const; }; 

DreampaxItemsDataAsset.pp
 /// Copyright 2018 Dreampax Games, Inc. All Rights Reserved. #include "DreampaxItemsDataAsset.h" /* Includes from Engine */ // no includes /* Includes from Dreampax */ // no includes TMap<FGameplayTag, float>* UDreampaxItemsDataAsset::GetItemData(const FGameplayTag & ItemNameTag) { return & ItemsDataBase.Find(ItemNameTag)->ItemData; } FGameplayTagContainer * UDreampaxItemsDataAsset::GetItemPropertyTags(const FGameplayTag & ItemNameTag) { return & ItemsDataBase.Find(ItemNameTag)->ItemPropertyTags; } UTexture2D* UDreampaxItemsDataAsset::GetItemIconTexture(const FGameplayTag &ItemNameTag) const { if (ItemNameTag.IsValid()) { return ItemsDataBase.Find(ItemNameTag)->IconTexture; } return nullptr; } TSubclassOf<class ADreampaxOutfitActor>* UDreampaxItemsDataAsset::GetItemOutfitClass(const FGameplayTag &ItemNameTag) { return & ItemsDataBase.Find(ItemNameTag)->ItemOutfitClass; } TSubclassOf<class ADreampaxPickupActor>* UDreampaxItemsDataAsset::GetItemPickupClass(const FGameplayTag &ItemNameTag) { return & ItemsDataBase.Find(ItemNameTag)->ItemPickupClass; } int UDreampaxItemsDataAsset::GetItemMaxStackSize(const FGameplayTag & ItemNameTag) { // if DefaultGameplayTagForMaxSizeOfStack is missed return 1 for all items if (!DefaultGameplayTagForMaxSizeOfStack.IsValid()) { return 1; } int MaxStackSize = floor(GetItemData(ItemNameTag)->FindRef(DefaultGameplayTagForMaxSizeOfStack)); if (MaxStackSize > 0) { return MaxStackSize; } // if Tag for MaxStackSize is "0" return 1 return 1; } bool UDreampaxItemsDataAsset::ItemIsFound(const FGameplayTag & ItemNameTag) const { if (ItemsDataBase.Find(ItemNameTag)) { return true; } return false; } 

De multijugador todavía no hay nada. Pero este es el primer paso que se ha dado en la dirección correcta.


En el próximo artículo hablaré sobre los métodos para conectar DataAsset (sí, y cualquier Blueprint ) para leer datos en C ++, y mostraré cuál es el más correcto.


Si tiene preguntas o sugerencias para revelar algún aspecto con más detalle, escriba los comentarios.

Source: https://habr.com/ru/post/es418913/


All Articles