DataTable是UE4为了数据驱动而开发的便捷工具,一般我们做它可以在游戏里做数据的填写、归类等作用,便于策划进行游戏的设计。
官方的解释:源自数据驱动游戏性元素
数据表就是以有意义且有用的方式将各种相关的数据归类的表格, 其中,数据字段可以是任何有效的 UObject 属性,包括资产引用。在设计师将 CSV 文件导入数据表前,程序员必须创建行容器以指示引擎如何解释数据。 这些数据表包含了列名,这些列名和基于代码的UStruct结构以及它的(子)变量一一对应, 这个UStruct的结构必须继承自FTableRowBase才可以被导入器辨识。
就是注意如果在C++中编写一个表格,需要继承FTableRowBase
下面我做了一个技能管理者的类,继承于Actor,作为演示
头文件
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Engine/DataTable.h"
#include "SkillManager.generated.h"
UENUM(BlueprintType)
enum class EDamageType : uint8
{
//物理
E_Physical,
//魔法
E_Mage
};
UENUM(BlueprintType)
enum class EAttackType : uint8
{
//近战
E_Close,
//远程
E_Remote
};
USTRUCT()
struct FSkillTable : public FTableRowBase
{
GENERATED_USTRUCT_BODY();
//技能ID
UPROPERTY(BlueprintReadOnly, EditAnywhere)
int32 SkillID;
//技能图标
UPROPERTY(BlueprintReadOnly, EditAnywhere)
class UTexture2D* SkillIcon;
//伤害类型
UPROPERTY(BlueprintReadOnly, EditAnywhere)
EDamageType DamageType;
//攻击类型
UPROPERTY(BlueprintReadOnly, EditAnywhere)
EAttackType AttackType;
//攻击伤害值
UPROPERTY(BlueprintReadOnly, EditAnywhere)
float InjuryValue;
};
/**
*
*/
UCLASS()
class PRACTICE_API ASkillManager : public AActor
{
GENERATED_BODY()
public:
virtual void BeginPlay()override;
//加载当前技能表里的数据到管理者里
UFUNCTION(BlueprintPure, Category = "Practice|DataTable")
void LoadSkillDataTable();
//通过ID在技能表里找内容
UFUNCTION(BlueprintPure, Category = "Practice|DataTable")
FSkillTable GetTableFromID(int32 ID);
//通过ID判断角色身上是否应该有该技能
UFUNCTION(BlueprintPure, Category = "Practice|DataTable")
FSkillTable GetTargetSkillID(class ACharacter* Player,int32 SendID);
protected:
//技能表
TArray<FSkillTable*> SkillTable;
};
Cpp文件
#include "SkillManager.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "Roles/Role.h"
#include "Kismet/KismetSystemLibrary.h"
void ASkillManager::BeginPlay()
{
Super::BeginPlay();
}
void ASkillManager::LoadSkillDataTable()
{
if (SkillTable.Num() == 0)
{
UDataTable* TempSkillData = LoadObject<UDataTable>(this, TEXT("DataTable'/Game/Demo/Role/SkillDataTable.SkillDataTable'"));
if (TempSkillData)
{
TempSkillData->GetAllRows(TEXT("Load SkillData Miss!"), SkillTable);
UE_LOG(LogTemp, Log, TEXT("===========SUCCESS LOAD========="));
}
}
}
FSkillTable ASkillManager::GetTableFromID(int32 ID)
{
for (auto SkillItem : SkillTable)
{
if (SkillItem->SkillID == ID)
{
return *SkillItem;
}
}
FSkillTable TempSkillTable;
return TempSkillTable;
}
FSkillTable ASkillManager::GetTargetSkillID(class ACharacter* Player, int32 SendID)
{
//角色类
ARole* _role = Cast<ARole>(UGameplayStatics::GetPlayerController(this, 0)->GetPawn());
if (Player==_role)
{
for (auto Tempskill : _role->GetRoleSkillMap())
{
if (SendID== Tempskill.Value)
{
FSkillTable temp_=GetTableFromID(SendID);
return temp_;
}
}
}
UKismetSystemLibrary::PrintString(this, TEXT("CurrentRole don't Have SkillID"));
FSkillTable TempSkillTable;
return TempSkillTable;
}
管理者中创建了一个表格,两个枚举,编译
创建完成后,直接在蓝图中右击
选中在C++中创建的DataTable的Name,即SkillTable
再填入表格内容,如下,这个可以由策划去填写,可以添加其他属性,比如远程技能可以添加一个需要释放的Mesh等。
LoadSkillDataTable()
这个函数主要是为了将蓝图中创建并且填写的DataTable数据表格,在C++中加载,并在C++中使用,当然也可在蓝图中调用;
GetTableFromID()
这个函数主要是为了通过ID号,找到填写好的数据表格里的那一层的内容,比如获取ID号是0的那一层的数据,返回其结构体内容;
GetTargetSkillID
这个函数主要是为了判断传入的Player指针及需要发送的技能ID,首先先判断该角色身上是否能有该技能(可能是为学习,可能是职业不同),判断可以,再将此技能ID传入上面函数,返回结构体内容。
所以在角色身上少了一个,储存当前角色的技能背包;
我在C++中创建了一个Role角色;
头文件
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Role.generated.h"
UCLASS()
class PRACTICE_API ARole : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ARole();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION(BlueprintPure)
TMap<FString, int32> GetRoleSkillMap() { return RoleSkill; };
protected:
UPROPERTY(EditAnywhere,Category="Role|Skill")
TMap<FString, int32> RoleSkill;
};
Cpp文件
#include "Role.h"
// Sets default values
ARole::ARole()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ARole::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ARole::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ARole::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
为了测试方便,我在蓝图中创建了
一个BP_GameMode,继承于GameModeBase;
一个BP_Controller,继承于PlayerController;
一个BP_Role,继承于在C++中编写的ARole;
都绑定在BP_GameMode里
函数SetRoleSkillFromID的操作
在BP_Role里面给,角色填充了应该有得技能ID;
最后运行,分别按下1,2,3,4按键,打印结果如下。
在Controller里按下了技能按键,经过SkillManager,然后进入该角色里判断是否含有此技能,再从技能表格里面将传入的ID所对应的技能内容调出。
在蓝图中建立DataTable,首先需要建立一个结构体
再结构体中填入相关属性
需要建立相关的枚举
再去建立数据表格DataTable,选择的是刚刚建的SkillStruct
在DataTable里填入相关内容
在BP_Role里面创一个TMap数组,填入该角色可使用的技能,及ID
在BP_Controller里面,编写BPSetRoleSkill函数;
调用函数,将SkillID传入;
最后按下1,2,3,4按钮打印效果如下;
使用DataTable,可以更合理,更有条理性,更适合和策划配合使用。
一般策划写的Excel表格,我们也可以按照一定格式导入到UE4,可转换成DataTable使用。
想了解相关操作的可以点击参考文档