UE4 | 多人游戏#1的库存| DataAsset上的数据仓库




数据资产 在本文中,我将尝试揭示创建DataAsset作为各种数据存储库的含义和方法,在我们的案例中,它是Actor及其参数的库。




略略介绍

在大约2年前决定做出一款游戏时,我偶然发现了虚幻引擎4的相关信息,并阅读了它的酷炫和简单性,这对我有很大帮助。 实际上,对于一个不知道如何编写代码(在这种情况下,编程语言无关紧要)的人来说 ,创建一个比对引擎上的一组标准工件进行少量修改要复杂的事情非常困难。 因此,随着对这个项目的现实知识的了解,制作超大型游戏的最初愿望逐渐变成了一种爱好。 对于一个人来说,从3D建模和动画到编写代码的所有层次的游戏开发似乎都是可行的。 但是,这是对大脑的良好锻炼。


你为什么决定写点东西?..可能是因为这个原因。 所提供的手册要么提供了非常肤浅的知识(并且其中大多数都是如此),要么是非常专业的,仅包含一般说明。


从头开始几乎总是更好。 我不能说我总是这样做,但是我会尽量保持一致。


当然,最好从结构开始,但是,不幸的是,由于有一个密闭的工具箱,很难理解在他们的帮助下可以建造什么。 因此,让我们打开此框,看看里面有什么。




第一个要回答的问题。 为什么选择DataAsset


  1. 在文章和教程中,您经常可以看到DataTable的使用。 为什么这样不好? 如果您存储特定Blueprint的地址,则在将其重命名或移动到另一个文件夹时,将被迫手动更改此地址。 同意-不舒服? 使用DataAsset不会发生这种情况。 所有通讯将自动更新。 如果您对未来几年的项目结构绝对有信心,那么当然可以使用表格。
  2. 不可否认的第二个优点是能够存储复杂的数据类型,例如结构( Struct )。

现在介绍一下相对的缺点。 实际上,我只看到一个。 这是编写C ++代码的需要。


如果您已经了解到不使用代码就不会做任何史诗般的工作 ,那么这不是缺点,而是功能。


应该注意的是,有一种解决方法-将Actor用作这样的存储库。 但是,这样的应用程序看起来像是不想学习C ++的最后借口,并且有可能在将来陷入困境。
如果您确信可以在Blueprint上完成项目所需的一切,请使用表格。




既然您已经相信DataAsset是好的,那么请考虑如何为您的项目创建它。


对于那些仍然完全“不在坦克中”的人
UE4专用的俄语论坛上,对这些步骤和图片进行了非常详细的描述。 只需在Google上搜索 “ UE4 DataAsset”即可 。 大约一年前,他精通了本手册的基础知识。

首先,创建一个C ++类 ,例如UDataAsset中的 Child
(下面的所有代码均来自我未出生的项目。只需根据需要重命名即可。)


/// 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() } 

现在,基于该类,您可以安全地创建Blueprint ,但是现在做起来还为时过早...到目前为止,它只是一个虚拟对象。 不过,请注意,已经包含了纹理和名称。




从这一刻开始,您将开始创建存储库的结构。 它将重做很多次,因此我强烈建议您不要立即填满您的存储空间。 对于我们的清单项目,三到五个元素足以进行测试。 有时,在编译之后,您的蓝图可能是空白的,如果您已经担任过十二个职位,那将是非常不愉快的。


您可以直接在头文件中创建结构,因为 在这种情况下,不太可能在其他地方应用。 通常,我更喜欢将其作为单独的头文件“ SrtuctName.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 }; 

TMap的 帐户 不能复制! 在这种情况下,没关系。


请注意,我不使用FName 。 根据现代趋势, FGameplayTag的使用被认为是更正确的,因为 大大降低了出错的风险,并具有稍后将派上用场的几个优点。


编辑器中的GameplayTag
游戏标签

从Excel导出GameplayTag的数据表
数据表

定义用于调用结构中变量的函数也是一种好习惯 ,例如GetSomething() 。 显然,由于该数据库位于该数据库中,因此我仍然需要进行培养,所以我还没有打过电话。


这是使用另一个数据库作为示例的方法。
 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; } }; 

最重要的一点是数据库声明:


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

现在您已经可以创建我们的蓝图并填写它。


DataAsset填充示例
DataAsset填充示例

但在此之前,我们将编写更多的调用函数,以便能够从数据库接收数据。


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; } 

在多人游戏中,仍然没有任何东西。 但这是朝正确方向迈出的第一步。


在下一篇文章中,我将讨论连接DataAsset (是的,以及任何Blueprint )以读取C ++中的数据的方法,并说明哪种方法最正确。


如果您有疑问或建议要更详细地披露任何方面,请在评论中写。

Source: https://habr.com/ru/post/zh-CN418913/


All Articles