The Need for Data-Driven Design
When developing games with Unreal Engine (UE), you may face challenges like:
- Difficulty for designers and planners to adjust data: Enemy stats, item performance, level design parameters—is your game's "data" embedded in C++ code or Blueprints? Every data change requires programmer work, slowing iteration speed.
- Low data reusability: Are you creating new Blueprint classes for similar items or enemies just because parameters differ slightly? This leads to asset bloat and management complexity.
- Poor memory efficiency: When multiple actors hold the same data (e.g., weapon base stats), that data gets duplicated in memory.
The solution that resolves these challenges and realizes division of labor between programmers and non-programmers, enabling efficient and flexible development is "Data-Driven Design." Data-driven design clearly separates game logic (behavior) from data (parameters).
And in Unreal Engine, the core enabler of this data-driven design is the "Data Asset."
What is Data Asset
Data Asset is an asset designed to hold only data based on a specific data structure (UDataAsset class).
While Blueprint and C++ classes are templates that hold both "behavior (logic)" and "data (properties)," Data Asset purely defines "data" and allows managing it as an independent asset in the Content Browser.
| Characteristic | Data Asset | Blueprint Class (Actor, etc.) |
|---|---|---|
| Purpose | Hold and share data (parameters) | Define behavior (logic) and data |
| Instantiation | Not needed (data itself is the asset) | Needed (place in world or spawn) |
| Memory Efficiency | Good (easy to design sharing data by reference without duplication) | Depends on situation (may hold data per instance) |
| Use Cases | Enemy stats, item definitions, configuration values | Player character, doors, UI widgets |
Data Asset's greatest advantage is that multiple classes and systems can reference the same data and designers can edit data without touching code.
Creating and Using Data Asset
The procedure for introducing Data Asset is very simple.
Step 1: Define the Data Asset Base Class (C++)
First, create a C++ class defining the data structure you want to hold. This class must inherit from UDataAsset.
GameItemDataAsset.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameItemDataAsset.generated.h"
UCLASS(BlueprintType)
class MYPROJECT_API UGameItemDataAsset : public UDataAsset
{
GENERATED_BODY()
public:
// Item basic information
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
FText ItemName;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
FText ItemDescription;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item")
UTexture2D* ItemIcon;
// Item stats
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats")
int32 AttackPower;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats")
int32 DefenseValue;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats")
float Weight;
};
UCLASS(BlueprintType): Makes this class referenceable from Blueprint.UPROPERTY(EditAnywhere, BlueprintReadOnly): Makes it editable in the Data Asset instance in the Content Browser and read-only accessible from Blueprint.
Step 2: Create Data Asset Instance
- Right-click in the Unreal Editor Content Browser.
- Select Miscellaneous > Data Asset.
- Select the
GameItemDataAssetyou created from the displayed list. - Name the created asset (e.g.,
DA_Sword_Basic,DA_Potion_Heal). - Double-click the asset to open it, and designers can freely set each property (
ItemName,AttackPower, etc.) in the Details panel.
Step 3: Reference Data Asset from Blueprint
To use Data Asset data in-game, have Blueprint classes (e.g., player, enemy, inventory system) hold a reference to the Data Asset.
- Create a variable of type
UGameItemDataAssetin the Blueprint class. - Assign the Data Asset instance created in the Content Browser (e.g.,
DA_Sword_Basic) to this variable. - In the Blueprint graph, get Data Asset properties (e.g.,
AttackPower) from this variable and use them in game logic.
Blueprint Example (Item Usage Logic)
Node image for getting data from Data Asset reference and using it in logic.
graph TD
A[Event Use Item] --> B{Get Item Data Asset Reference};
B --> C[Get Attack Power];
C --> D[Apply Damage to Target];
D --> E[Print String: ItemName];
Choosing Between Data Asset and Data Table
Unreal Engine has another data management feature called Data Table besides Data Asset. These have different use cases.
| Feature | Data Asset | Data Table |
|---|---|---|
| Structure | Custom UDataAsset class | Custom FTableRowBase struct |
| Management Unit | 1 asset = 1 data set | 1 asset = multiple rows of data (CSV/Excel format) |
| Flexibility | High (complex data structures, asset references possible) | Low (limited to simple table format) |
| Editors | Mainly designers/planners | Mainly designers/planners (external file editing too) |
| Suited For | Complex item definitions, config files, unique data | Large amounts of homogeneous data (e.g., enemy level-based stats, translation text) |
Best Practices:
- Use Data Asset for unique, complex data (e.g., player skill tree settings, specific boss enemy definitions).
- Use Data Table for large amounts of homogeneous data (e.g., 100 types of potion base stats) and manage with external files (CSV/Excel) for easy batch editing.
Data Asset Applications
Data Asset's true value shines when making the entire game system data-driven.
Application: Status Effect System
Defining status effects (poison, paralysis, etc.) as Data Assets makes adding new effects or adjusting parameters easy.
C++ Data Asset Definition
// StatusEffectDataAsset.h
UCLASS(BlueprintType)
class UStatusEffectDataAsset : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FText EffectName;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float Duration; // Effect duration
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float TickDamage; // Damage per second
// References to other assets like status effect icons, particle systems
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UParticleSystem* ParticleEffect;
};
Logic Side (Blueprint/C++)
Design functions that apply status effects to receive Data Asset references instead of concrete damage values or effect durations.
// Function to apply status effect
void UCombatComponent::ApplyStatusEffect(UStatusEffectDataAsset* EffectData, AActor* Target)
{
// Get Duration and TickDamage from Data Asset and execute logic
float ActualDuration = EffectData->Duration;
float DamagePerTick = EffectData->TickDamage;
// ... actual status effect logic ...
}
This way, programmers only implement ApplyStatusEffect logic once, and designers can add new status effects to the game just by creating new Data Assets (e.g., DA_Poison_Strong, DA_Paralysis_Weak).
Common Mistakes and Best Practices
Common Mistakes
- Writing logic in Data Asset: Data Asset is purely for holding "data." Write logic (behavior) in classes that reference it like Actors, Components, or Subsystems.
- Overusing Data Asset instead of Data Table: When you want to manage large amounts of homogeneous data row by row, Data Table is more appropriate. Data Assets become cumbersome to manage when there are too many.
- Trying to instantiate Data Asset directly: Data Assets exist as assets in the Content Browser and are used by reference. They're not meant to be generated at runtime with
NewObject.
Best Practices
- Unify naming conventions: Add prefixes like
DA_to Data Assets (e.g.,DA_Enemy_Goblin) to identify them at a glance. - Use Primary Data Asset: Deriving Data Assets from
UPrimaryDataAssetenables async loading via Asset Manager and patch target management via Asset Bundles. Essential technique for large projects. - Use Data Asset as singleton: Create Data Assets holding game-wide settings (e.g., graphics setting presets, gameplay constants) and reference them from Subsystems to centrally manage global settings.
Key Points for Data Asset Usage
Data Asset in Unreal Engine is a powerful tool for achieving data-driven design.
| Key Point | Description |
|---|---|
| Role | Asset that separates data (parameters) from logic (behavior) and holds only data. |
| Benefits | Easier data adjustment by designers, improved data reusability, better memory efficiency. |
| Selection | Data Asset for complex, unique data; Data Table for large amounts of homogeneous data. |
| Design Philosophy | Logic side depends on Data Asset type, concrete values depend on Data Asset instances. |
Properly utilizing Data Asset makes Unreal Engine development more flexible and efficient. Try incorporating data-driven design into your project.