目录
一,常用UEC++变量类型
// 基础类型
bool bool_val = 1;
uint8 byte_val = 255;
int32 int32_val = -32;
int64 int64_val = -64;
double double_val = 3.14;
// UE_LOG 的第 3 个参数(Format)必须是格式化字符串字面量
UE_LOG(LogTemp, Error, TEXT("%d"), bool_val);
UE_LOG(LogTemp, Warning, TEXT("%d"), byte_val);
UE_LOG(LogTemp, Warning, TEXT("%d"), int32_val);
UE_LOG(LogTemp, Display, TEXT("%d"), int64_val);
UE_LOG(LogTemp, Display, TEXT("%f"), double_val);
// 字符串类型
FString str = TEXT("FString!");
FName name = TEXT("FName!");
FText text = FText::FromString(TEXT("FText!"));
UE_LOG(LogTemp, Display, TEXT("%s"), *str);
UE_LOG(LogTemp, Display, TEXT("%s"), *name.ToString());
UE_LOG(LogTemp, Display, TEXT("%s"), *text.ToString());
// 容器类型
TArray<int32> arr = { 1,2,3,4,5 };
TSet<int32> set = { 10,20,30,40,50 };
TMap<int32, FString> map = { {1, TEXT("one")}, {2, TEXT("two")} };
FString arr_ret;
for (auto num : arr)
arr_ret += FString::FromInt(num) + TEXT(" ");
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, arr_ret);
FString set_ret;
for (auto num : set) {
set_ret += FString::FromInt(num) + TEXT(" ");
}
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, set_ret);
FString map_ret;
for (auto num : map)
map_ret += num.Value + TEXT(" ");
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, map_ret);
// CreateDefaultSubobject是UEC++中一个非常核心的函数,专门用于在构造函数中为Actor或Object创建默认子对象(通常是组件);
// 在构造阶段为对象创建子对象,并让引擎正确地管理它(包括反射、序列化、以及在蓝图编辑器中可见等);
// 注,只能在类的构造函数中调用;
UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyMeshComponent"));
二,理解UBT/UHT
UBT(Unreal Build Tool )虚幻编译工具,负责管理整个编译流程,包括收集所需编译的模块、处理依赖关系、调用 UHT,最后再调用标准的 C++ 编译器(如 MSVC)完成最终编译;
UHT(Unreal Header Tool)预处理,负责解析头文件中的特殊宏(如
UCLASS(),UFUNCTION()等),读取为 UObject 系统添加的“元数据”,并自动生成*.generated.h和*.gen.cpp等中间代码,从而支持反射、蓝图调用等功能;
点击编译 (Live Coding / 生成解决方案)
│
▼
┌─────────────────────────────────────┐
│ 1. UBT (Unreal Build Tool) 启动 │
│ - 读取 .uproject 文件 │
│ - 读取 Target.cs 文件 │
│ - 解析模块依赖关系树 │
│ - 判断哪些文件需要重新编译 │
└─────────────────────────────────────┘
│
▼ 反射系统 = UHT(步骤 2~3)在编译期生成数据表 + UE 运行时库读取这些表
┌─────────────────────────────────────┐
│ 2. UBT 调用 UHT (Unreal Header Tool)│
│ - 只扫描头文件 (.h) 或 .generated.h│
│ - 识别 UCLASS, UFUNCTION 等宏 │
│ - 验证反射规范的合法性 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. UHT 生成中间代码 │
│ - 为每个类生成 .generated.h │
│ - 生成 .gen.cpp(包含反射数据) │
│ - 生成函数参数封包代码 │
│ (这些文件放在 Intermediate 文件夹)│
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. UBT 准备编译环境 │
│ - 构建编译命令行参数 │
│ - 设置包含目录 (Include Paths) │
│ - 配置预处理器宏 │
│ - 确定编译配置 (Debug/Development) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 5. UBT 调用底层编译器 (MSVC/Clang) │
│ - 编译所有 .cpp + .gen.cpp │
│ - 输出 .obj 文件 │
│ - 链接成 .dll (模块) 或 .exe │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 6. UBT 处理资源/其他 │
│ - 编译着色器(如果是首次/有变更) │
│ - 复制生成的 .dll 到正确位置 │
│ - 更新模块热重载信息(如有) │
└─────────────────────────────────────┘
│
▼
引擎可以运行新代码
三,反射系统
反射 是程序在运行时检查、访问和操作自身结构(类、属性、函数等)的能力,其在UE中的主要用途:
- 编辑器交互(最核心),能直接在编辑器的Details面板里修改它的值,无需任何额外代码,如在
UPROPERTY(EditAnywhere);- 蓝图与C++交互,可直接在蓝图节点中调用C++函数,如UFUNCTION(BlueprintCallable);反之,C++也能调用蓝图中实现的事件如BlueprintImplementableEvent;
- 序列化(保存与加载),保存游戏时,反射系统能自动遍历对象上所有
UPROPERTY()标记的变量,把值写入磁盘,加载时再自动恢复;- 垃圾回收,
UPROPERTY()最重要的职责之一是阻止垃圾回收,被标记的指针,GC就知道“这是正在使用的”,不会错误地清理掉,防止内存泄漏和野指针的关键;- 网络复制,
UPROPERTY(Replicated)可让某个属性在服务器和所有客户端之间自动同步,省去了手写大量网络通信代码的麻烦;注:必须是UObject派生类,完整的反射功能(如垃圾回收)只在继承自UObject的类上生效,普通的C++类不行;
关键宏
// 创建新类型时“对外声明”,告诉构建工具“该类需要被纳入反射系统”;否则UBT在扫描头文件时会直接忽略该类,不会为它生成 .generated.h 和 .gen.cpp 文件;
// 可在其后附加说明符,用于该类与引擎编辑器及蓝图系统的沟通交互(如Blueprintable,BlueprintType,meta=(...));
// 标记类型错误(如USTRUCT用在了UObject上),UHT会编译错误;
UCLASS():对继承自UObject的类反射,提供完整反射支持(如UFUNCTION、垃圾回收、网络复制等);
USTRUCT():对普通C++结构体轻量级反射(支持UPROPERTY、序列化、蓝图作为数据类型,但不支持函数暴露和垃圾回收);
UENUM():对C++枚举反射(可在蓝图、编辑器下拉菜单和序列化中直接使用);
// “对内填充”,在类体内补齐必要的代码;
// 提供必要的函数实现(如StaticClass(),返回本类专属的UClass指针),必要的类型定义(如Super);
GENERATED_BODY()
// 对类型成员的反射,标记需要进行反射的宏
// 必须用于被UCLASS或USTRUCT标记的类型内部成员
// 不可用于全局变量或全局函数,也不可用于普通 C++ 类/结构体中;
UPROPERTY():反射成员变量(支持序列化、蓝图访问、网络复制等);
UFUNCTION():反射函数(支持蓝图调用、网络远程调用、控制台命令等);
UPROPERTY() FString GlobalName; // ❌ 错误:全局变量不能用
class MyNormalClass {
UPROPERTY() int Value; // ❌ 错误:普通C++类不能用
};
UCLASS() // ✅ 正确:在UCLASS内部使用
class AMyActor : public AActor {
GENERATED_BODY()
UPROPERTY() int Score;
UFUNCTION() void DoAction();
};
USTRUCT() // ✅ 正确:在USTRUCT内部使用
struct FMyData {
GENERATED_BODY()
UPROPERTY() FString Name;
};
用于生成
UPROPERTY和UFUNCTION通过反射系统将对应属性或函数暴露给蓝图;// 编辑器可编辑性(Edit / Visible) UPROPERTY(EditAnywhere) // 实例和类默认值(蓝图/CDO)均可编辑 UPROPERTY(EditDefaultsOnly) // 仅类默认值可编辑,实例不可 UPROPERTY(EditInstanceOnly) // 仅实例可编辑,类默认值不可 UPROPERTY(VisibleAnywhere) // 始终可见但不可编辑(只读显示),实例和默认值均可见 UPROPERTY(VisibleDefaultsOnly) // 仅类默认值中可见(只读) UPROPERTY(VisibleInstanceOnly) // 仅实例中可见(只读)// 蓝图访问控制(Blueprint) UPROPERTY(BlueprintReadWrite) // 蓝图可读写,即可get/set UPROPERTY(BlueprintReadOnly) // 蓝图只读,即只可get UPROPERTY(BlueprintGetter) // 指定一个自定义函数作为 Getter(替代默认的读操作) UPROPERTY(BlueprintSetter) // 指定一个自定义函数作为 Setter(替代默认的写操作)// 网络复制(Replication) UPROPERTY(Replicated) // 属性会进行网络复制(需在 GetLifetimeReplicatedProps 中注册) UPROPERTY(ReplicatedUsing) // 属性复制时,会调用指定的回调函数(通常在客户端执行)// 序列化与持久化 UPROPERTY(SaveGame) // 属性会被包含在 SaveGame 存档系统中 UPROPERTY(Transient) // 属性不会被序列化(保存/加载时忽略),加载后为默认值 UPROPERTY(DuplicateTransient) // 复制(Duplicate)对象时,此属性不会被复制到新对象 UPROPERTY(TextExportTransient) // 导出为文本(如复制到剪贴板)时忽略 UPROPERTY(NonTransactional) // 在编辑器中操作(如移动、修改)时不参与 Undo/Redo 系统// 资产与元数据 UPROPERTY(Category = "名称") // 指定属性在编辑器 Details 面板中所属的分类 UPROPERTY(SimpleDisplay) // 优先显示在简单列表中(而不是高级折叠页) UPROPERTY(AdvancedDisplay) // 默认折叠到“高级”区域 UPROPERTY(AssetRegistrySearchable) // 属性会加入资产注册表,允许在内容浏览器中搜索// 实例化与引用 UPROPERTY(Instanced) // 对于 UObject* 或 TSubclassOf,每个实例都会拥有自己独立的对象,而不是共享默认对象 UPROPERTY(Ref) // 标记一个引用参数(通常用于函数参数,很少用在 UPROPERTY) UPROPERTY(Export) // 将引用的对象作为子对象序列化(内嵌)而不是通过引用路径// 配置相关 UPROPERTY(Config) // 此属性可从配置文件(*.ini)读取/写入 UPROPERTY(GlobalConfig) // 类似 Config,但保存在全局基类配置文件中(不保存在子类) UPROPERTY(Localized) // 属性是本地化的(UI 文本等)// 其他实用说明符 UPROPERTY(meta = (DisplayName = "xxx")) // 在编辑器中显示的名称,而不是变量名 UPROPERTY(meta = (ClampMin = "0", ClampMax = "100")) // 限制数值编辑范围(仅对浮点和整数) UPROPERTY(meta = (AllowPrivateAccess = "true")) // 允许蓝图访问私有成员(不推荐,但有时有用) UPROPERTY(Native) // 仅用于结构体,标记为本地类型 UPROPERTY(NoClear) // 对象引用不能设置为 None(必须总是有效)
// 蓝图交互 UFUNCTION(BlueprintCallable) // 蓝图可调用,允许蓝图节点调用此C++函数,是暴露函数最常见的方式; UFUNCTION(BlueprintPure) // 蓝图纯函数(无副作用),在蓝图中不显示执行引脚,直接连出数据,const函数默认隐含此标记; UFUNCTION(BlueprintNativeEvent) // C++默认实现,蓝图可重写,C++需在函数名后加_Implementation实现; UFUNCTION(BlueprintImplementableEvent) // 纯蓝图实现,C++声明无实现,完全由蓝图实现;// 网络与权限 UFUNCTION(NetMulticast) // 网络多播 UFUNCTION(Server) // 服务器执行 UFUNCTION(Client) // 客户端执行 UFUNCTION(Reliable / Unreliable) // 配合RPC使用,保证/不保证网络调用必达; UFUNCTION(BlueprintAuthorityOnly) // 限制蓝图代码仅在拥有网络权限的机器上执行; UFUNCTION(BlueprintCosmetic) // 标记为装饰性函数,在专用服务器上会被跳过;// 其他实用功能 UFUNCTION(Exec) // 将函数暴露为游戏内控制台命令 UFUNCTION(CallInEditor) // 在编辑器中选中对象,便可在细节面板看到调用按钮; UFUNCTION(Category = "Name") // 在蓝图节点面板中,为函数指定分类名称; UFUNCTION(meta = (DisplayName="...")) // 自定义函数在蓝图中的显示名称 UFUNCTION(BlueprintSetter) // 当蓝图修改特定UPROPERTY时,关联并自动调用此函数;
用于调用(运行时)
- 在程序运行期间,通过字符串名字或类型信息动态地查找、访问、调用对象的属性和方法;
主要用途:
运行时类型识别(RTTI)
判断对象是否为某个类型或其子类:
MyActor->IsA(AActor::StaticClass());判断类之间的继承关系:
MyClass->IsChildOf(UObject::StaticClass());- 反射访问属性(
UPROPERTY)
通过
FindPropertyByName获取FProperty描述符;结合对象实例,读写成员变量的值(通过
ContainerPtrToValuePtr或CopyCompleteValue);- 反射调用函数(
UFUNCTION)
通过
FindFunctionByName获取UFunction;调用
UObject::ProcessEvent动态执行函数(支持参数和返回值);- 动态创建对象
NewObject<UObject>(Outer, UClass*):创建任意UObject派生对象;
World->SpawnActor<AActor>(UClass*, ...):在关卡中生成Actor;- 获取类默认对象(CDO)
UClass::GetDefaultObject()返回该类的默认实例;用途:
读取/修改类的默认属性值(影响所有新实例);
比较对象属性是否与默认值不同(用于网络同步、序列化差异);
快速获取类的一些静态配置;
- 支撑引擎底层系统
序列化:遍历
UClass的所有UPROPERTY,自动保存/加载;网络复制:标记
Replicated的属性会通过UClass查找并同步;垃圾回收:通过
UClass遍历对象引用的属性;编辑器 Details 面板:根据
UClass中的属性元数据动态生成 UI;蓝图虚拟机:通过
UClass查找函数并执行ProcessEvent;
反射入口 → UClass (StaticClass / GetClass)
↓
属性:FindPropertyByName → FProperty → ContainerPtrToValuePtr → 读写
函数:FindFunctionByName → UFunction → ProcessEvent → 调用
类型:IsA / IsChildOf
创建:NewObject / SpawnActor
// 获取 UClass(元数据入口) T::StaticClass() // 获取已知 C++ 类 T 的 UClass(编译期) UObject::GetClass() // 获取实例对象所属的 UClass(运行时) FindObject<UClass>(ANY_PACKAGE, TEXT("MyClass")) // 通过名字(或路径)在包中查找类 LoadClass<T>(nullptr, TEXT("/Game/MyClass.MyClass_C")) // 加载蓝图类(常与动态生成配合)// 访问属性(UPROPERTY) UClass::FindPropertyByName(FName("PropName")) // 按名称查找 FProperty TFieldIterator<FProperty> // 遍历类的所有属性(含继承) FProperty::ContainerPtrToValuePtr<void>(Object) // 获取对象中该属性的内存指针 FProperty::CopyCompleteValue(Dest, Src) // 复制属性值(不关心类型) FProperty::GetValue_InContainer(Object, &OutVal) // 读取属性值(模板版) FProperty::SetValue_InContainer(Object, &NewVal) // 设置属性值// 调用函数(UFUNCTION) UClass::FindFunctionByName(FName("FuncName")) // 按名称查找 UFunction UObject::ProcessEvent(UFunction*, void* Parms) // 执行函数(支持参数/返回值) UFunction::Invoke(Object, Parms) // 另一个调用方式(较少用) TFieldIterator<UFunction> // 遍历类的所有函数// 动态创建对象 NewObject<UClass>(Outer, UClass*) // 创建 UObject 派生对象 World->SpawnActor<AActor>(UClass*, FTransform, ...) // 在世界中生成 Actor ConstructObject<UClass>() // 低级别创建(不常用)// 类型判断与转换 UObject::IsA(UClass*) // 判断对象是否属于某类(或子类) UClass::IsChildOf(UClass*) // 判断类是否继承自另一个类 Cast<T>(UObject*) // 安全转换(编译期已知类型) DynamicCast<T>(UObject*) // 运行时反射转换(类似 Cast) StaticClass()->IsChildOf(AActor::StaticClass()) // 类继承检查// 其他辅助 FindField<FProperty>(UClass*, FName) // 等价于 FindPropertyByName FindField<UFunction>(UClass*, FName) // 等价于 FindFunctionByName UClass::GetDefaultObject() // 获取类默认对象(CDO) UClass::GetSuperClass() // 获取父类 UObject::GetFName() // 获取对象名称(可用于反射查找)// 常用宏(编译期帮助反射生成) GENERATED_BODY() // 必须在类声明中,展开反射所需的代码 DECLARE_DYNAMIC_MULTICAST_DELEGATE(...) // 声明动态委托(支持蓝图) DECLARE_FUNCTION // 自定义 UFUNCTION 底层(极少用)
四,UClass
- 是描述一个 UObject 派生类元数据(属性、函数、父类、大小等)的核心类型;
- 是UE反射系统为每一个
UCLASS(即带有UCLASS()宏的 UObject 派生类)自动生成的元数据类型(继承链UObject -> UField -> UStruct -> UClass );- 可理解为C++ type_info的超级增强版——不仅包含类型名称、父类信息,还存储了该类的所有属性(UPROPERTY)、函数(UFUNCTION)、以及用于序列化、网络复制、实例化等的额外数据;
- 该类型是引擎核心代码中已经写好的(位于
UObject.h/Class.h);- 是UE中“类的类”,提供了运行时对 C++ 类结构(属性、函数、继承、默认值)的完整描述和操作能力,是反射、动态创建、编辑器集成等所有高级功能的基础;
- 每个 UObject 派生类都有一个唯一的 UClass 对象(单例);
- UClass 对象是模块加载时创建的,其元数据内容由UHT生成提供;
AMyActor
|
| 编译,UHT 扫描头文件
|
生成:.generated.h
.gen.cpp(包含静态注册对象 TClassCompiledInDefer<AMyActor> 和元数据描述)
|
| 模块启动/热加载,静态注册对象的构造函数执行
| → 调用 UClass::CreateClass
|
| ① 创建 UClass 对象,填充元数据(属性/函数/父类等)
| ② 将 UClass 注册到全局类表
|
生成:UClass 对象(已注册)
|
| 调用 UClass::CreateDefaultObject → 调用 AMyActor 构造函数
|
生成:CDO(存储默认属性值)
(编辑器中修改 "Class Defaults" 即修改此 CDO 的值)
|
运行时:AMyActor::StaticClass() 返回 UClass*
// 简化版 UClass 伪代码
class UClass : public UStruct
{
// 反射元数据
FName ClassName; // 类名,如 "MyActor"
UClass* SuperClass; // 父类指针
UObject* ClassDefaultObject; // CDO(类默认对象)
TArray<FProperty*> Properties; // 该类所有的 UPROPERTY 属性
TArray<UFunction*> Functions; // 该类所有的 UFUNCTION 函数
uint32 ClassFlags; // 类标志(如可蓝图创建、抽象类等)
UObject* (*ClassConstructor)(const FObjectInitializer&); // 构造器函数指针
// 常用接口
UClass* GetSuperClass() const { return SuperClass; }
FName GetFName() const { return ClassName; }
UObject* GetDefaultObject() const { return ClassDefaultObject; }
// 创建实例的静态辅助函数(通常由 NewObject<> 调用)
UObject* CreateInstance(const FObjectInitializer& OI) const
{
return (*ClassConstructor)(OI);
}
// 查找属性
FProperty* FindPropertyByName(FName PropName) const
{
for (FProperty* Prop : Properties)
if (Prop->GetFName() == PropName)
return Prop;
return nullptr;
}
// 反射调用函数
void CallFunction(UObject* Obj, UFunction* Func, void* Params)
{
Obj->ProcessEvent(Func, Params);
}
};
// 注:UStruct 是 UClass 的父类,包含了字段(属性)的通用管理逻辑
class UStruct : public UField
{
UStruct* SuperStruct; // 继承结构体的父结构体
TArray<FProperty*> ChildProperties; // 当前结构体直属的属性
int32 MinAlignment; // 内存对齐要求
int64 PropertySize; // 结构体实例的总字节大小
};


1525

被折叠的 条评论
为什么被折叠?



