c12.数据表格|Datatable
大约 4 分钟
Datatable
与DataAsset区别?
特征 | DataTable | DataAsset |
---|---|---|
用途 | 存储和管理结构化数据,如游戏配置、物品属性等 | 存储和管理游戏资产数据,如模型、纹理等 |
主要内容 | 表格形式数据,每行为一条记录 | 可以包含各种类型的资源数据,如静态资产或动态资产 |
文件类型 | .csv 、.xlsx 等表格文件 | .uasset 文件格式 |
基本使用
1. 创建数据结构
/** 道具基础信息 */
USTRUCT(BlueprintType)
struct FInventoryBase : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
FGameplayTag EquipmentTag;
// 库存项名称
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
FText ItemName;
// 库存项描述
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
FText Description;
// 物品类型(武器、消耗品、装备等)
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
EItemType ItemType;
// 库存项图标
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
TSoftObjectPtr<UTexture2D> Icon;
// 库存项缩略图
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "BaseInfo")
TSoftObjectPtr<UTexture2D> Thumbnail;
FInventoryBase()
: EquipmentTag(FGameplayTag())
, ItemName(FText())
, Description(FText())
, ItemType(EItemType::Weapon)
, Icon(nullptr)
, Thumbnail(nullptr)
{
}
};
2. 创建 DataTable 资产
在 UE5 编辑器中,打开 内容浏览器。
右键 →
Miscellaneous(杂项)
→DataTable
。在弹出的
结构体选择
窗口中,选择 刚刚创建的 FInventoryBase 结构体。

3. 编辑 DataTable 数据
- 双击打开
DataTable
资源。 - 点击
+ 添加
按钮,添加新的数据行。

4. 运行时读取 DataTable
Blueprint 读取



C++ 读取
获取行结构体
const T* RowData = DataTable->FindRow<T>(RowName, TEXT("GetRows"));
//例如我们刚刚的结构体
FInventoryBase* ItemRow = ItemDataTable->FindRow<FInventoryBase>(FName("行名"), “标识字符串”);
5. 动态修改 DataTable(运行时)数据
虽然 DataTable
主要用于存储静态数据,但在运行时也可以修改:
if (ItemRow)
{
ItemRow->ItemValue += 100; // 修改数值
}

表格蓝图函数库
Source/Runtime/Engine/Classes/Kismet/DataTableFunctionLibrary.h
获取多行
#if WITH_EDITOR
TArray<FName> EditorGetDatatableRowNames() const;
#endif
/** 存储 DataTable 的引用 */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "DataTable")
TObjectPtr<const UDataTable> DataTable;
/** 存储多个 RowNames */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "DataTable", meta = (GetOptions = "EditorGetDatatableRowNames"))
TSet<FName> RowNames;
/** 通过 RowNames 批量获取表格行数据 */
template <typename T>
TArray<T> GetRows() const
{
TArray<T> Result;
if (!DataTable)
{
UE_LOG(LogTemp, Warning, TEXT("DataTableMultiRowHandle: DataTable is not set!"));
return Result;
}
// 遍历所有 RowName,查找对应的行
for (const FName& RowName : RowNames)
{
const T* RowData = DataTable->FindRow<T>(RowName, TEXT("GetRows"));
if (RowData)
{
Result.Add(*RowData);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("DataTableMultiRowHandle: Row %s not found in DataTable"), *RowName.ToString());
}
}
return Result;
}
进阶
UScriptStruct
UScriptStruct
和 FTableRowBase
的关系
UScriptStruct 是 Unreal Engine 5(UE5) 用于 反射和序列化 C++ 结构体(struct) 的核心系统。它使得 struct 具备 蓝图可用性、网络复制、GC(垃圾回收)支持 等功能。 在 UE5 中,普通的 struct 是 标准 C++ 结构体,但如果需要让引擎识别它(如在蓝图或 DataTable 中使用),就必须使用 USTRUCT(BlueprintType) 进行标记,而 USTRUCT 背后的实现正是 UScriptStruct。

源码解析

uint8*
UDataTable 的 RowMap 存储行数据时,以 uint8* 表示每行数据的起始地址。 这是因为它需要以与类型无关的原始内存形式 存储结构体数据,便于动态管理不同结构体类型的行数据。
为什么能用 reinterpret_cast<T*> 转换?
Unreal 的 USTRUCT 结构体默认是 Plain Old Data (POD) 类型,没有虚函数表(vtable)或复杂继承关系。 其内存布局是连续的,字段顺序和偏移量在编译时确定。