Unreal Engine 使用一套自省的反射系统,它允许程序在运行时查询、访问和操作类、变量和函数的信息。然而,标准的 C++ 本身并不支持这种级别的反射。
这些宏标记(如 UCLASS()
, UPROPERTY()
, UFUNCTION()
)的作用就是为 Unreal Header Tool (UHT) 提供指令。UHT 在编译前扫描你的代码,根据这些标记生成额外的反射代码(*.generated.h
文件),从而将你的 C++ 代码"暴露"给 UE 的各个系统,如蓝图编辑器、序列化、网络复制和垃圾回收。
一、UCLASS() - 类标记
作用:将一个 C++ 类声明为 UE 可识别的、可参与引擎对象管理的 UObject。
必须包含 :在标记了 UCLASS()
的类体内,必须包含 GENERATED_BODY()
宏。
常用选项 (Specifiers)
选项 | 说明 | 使用场景 |
---|---|---|
Blueprintable |
最重要选项之一。允许此类的蓝图被创建。 | 希望设计师能基于你的 C++ 类创建蓝图。 |
NotBlueprintable |
(默认)禁止创建此类的蓝图。 | 不希望被蓝图继承的基类或工具类。 |
BlueprintType |
允许此类作为变量类型在蓝图中使用。 | 希望蓝图能定义此类型的变量。 |
Placeable |
允许在关卡编辑器中将此类的 Actor 拖入场景。 | 大多数继承自 AActor 的类。 |
NotPlaceable |
(默认)禁止在关卡中放置。 | 抽象基类或不应直接放置的类(如 AGameMode )。 |
Abstract |
标记该类为抽象类,无法创建实例。 | 用于定义接口或基础功能的基类。 |
示例代码:
cpp
// 这个类可以被蓝图继承,可以在蓝图中用作变量类型,并且可以放置在关卡中
UCLASS(Blueprintable, BlueprintType, Placeable)
class AMyGameCharacter : public ACharacter
{
GENERATED_BODY() // 必须包含在类体内
// ... 类的成员
};
二、UPROPERTY() - 变量标记
作用:暴露变量给属性系统,使其可被编辑器详情面板显示、被蓝图访问、参与网络复制、序列化等。
常用选项 (Specifiers) - 按功能分类
1. 访问与可见性 (Access & Visibility)
选项 | 说明 | 建议 |
---|---|---|
BlueprintReadOnly |
蓝图可读,不可修改。 | 最常用、最安全。在 C++ 中设置,供蓝图使用。 |
BlueprintReadWrite |
蓝图可读也可写。 | 谨慎使用!蓝图可能在任何时候修改它。 |
VisibleAnywhere |
在编辑器的详情面板 中可见但不可编辑。 | 用于显示状态信息(如计算后的结果)。 |
EditAnywhere |
在详情面板 中可见且可编辑。 | 可在类默认值和实例上修改。灵活性高,但控制力弱。 |
EditDefaultsOnly |
仅在类的蓝图默认值中可编辑,实例上不可编辑。 | 最常用。用于定义类的固有属性(如最大血量、速度)。 |
VisibleDefaultsOnly |
仅在类的蓝图默认值中可见,不可编辑。 | - |
EditInstanceOnly |
仅在关卡中的实例上可编辑,默认值中不可编辑。 | 用于每个实例都不同的属性(如 NPC 的名字)。 |
2. 游戏性功能 (Gameplay)
选项 | 说明 | 注意 |
---|---|---|
Replicated |
启用网络复制。服务器端变量的变化会自动同步到客户端。 | 多人游戏核心。需在 GetLifetimeReplicatedProps 中声明。 |
SaveGame |
此变量应被包含在游戏存档/读档过程中。 | 需与 USaveGame 系统配合使用。 |
Transient |
临时变量,不被保存或加载。 | 用于运行时计算的缓存或临时指针。 |
3. 其他 (Others)
选项 | 说明 |
---|---|
AdvancedDisplay |
在详情面板中,该属性将被折叠到"高级"部分。 |
Category = "CategoryName" |
重要:将属性归类到详情面板的特定分类下,使UI更整洁。 |
示例代码:
cpp
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Health", Replicated)
// ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^
// 仅在默认值可编辑 蓝图只读(安全) 分类目录 网络复制
int32 MaxHealth;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")
// ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
// 在任何地方可见(只读) 蓝图只读
int32 CurrentHealth;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
// ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
// 任何地方可编辑 蓝图可读写(谨慎!)
float MovementSpeed;
三、UFUNCTION() - 函数标记
作用:暴露函数给蓝图系统或引擎回调机制(如定时器、委托)。
常用选项 (Specifiers)
1. 蓝图调用 (Blueprint Callability)
选项 | 说明 | 蓝图中的表现 |
---|---|---|
BlueprintCallable |
蓝图可以调用此函数来执行某些逻辑。 | 有执行 引脚(> )。 |
BlueprintPure |
蓝图可以调用此函数,但它不修改对象状态(无副作用)。 | 没有执行引脚,只有输出引脚。用于计算和获取值。 |
2. 蓝图重写 (Blueprint Overriding)
选项 | 说明 | C++ 实现要求 |
---|---|---|
BlueprintImplementableEvent |
这是一个事件,其实现完全由蓝图提供。C++ 中只有声明,无函数体。 | 无需在 C++ 中编写函数体。 |
BlueprintNativeEvent |
这是一个事件,C++ 提供默认实现,但蓝图可以重写它。 | 必须编写一个 函数名_Implementation 作为默认实现。 |
3. 网络 (Networking) - RPC (Remote Procedure Call)
选项 | 说明 | 调用规则 |
---|---|---|
Server |
标记函数在服务器上执行。 | 从客户端调用,在服务器上执行。 |
Client |
标记函数在客户端上执行。 | 从服务器调用,在所有客户端上执行。 |
NetMulticast |
标记函数在所有客户端和服务器上执行。 | 从服务器调用,在服务器和所有客户端上执行。 |
示例代码:
cpp
// 蓝图可以调用这个函数
UFUNCTION(BlueprintCallable, Category = "Combat")
void ApplyDamage(float DamageAmount);
// 这是一个纯函数,用于计算,不改变状态
UFUNCTION(BlueprintPure, Category = "Combat")
float CalculateFinalDamage(float BaseDamage) const;
// 蓝图可实现事件。C++中无实现,由蓝图定义逻辑
UFUNCTION(BlueprintImplementableEvent, Category = "Events")
void OnPlayerDied();
// 蓝图可原生事件。C++中有默认实现(_Implementation),蓝图可重写
UFUNCTION(BlueprintNativeEvent, Category = "Events")
void OnHealthChanged(float NewHealth);
// 必须提供默认实现:
virtual void OnHealthChanged_Implementation(float NewHealth);