很多蓝图程序员做到一定程度,都会遇到一个瓶颈:有些事情蓝图做不到,或者做起来太慢了。
这时候就需要C++了。
UE5的C++跟纯C++有点不一样——UE有一套自己的反射系统(Reflection System),需要用特定的宏来标记类、函数、变量,这样UE的编辑器才能识别它们。
这篇文章把UE C++的核心知识讲清楚,看完你就能看懂大部分UE C++代码了。
UE C++的特殊之处:宏系统
UE C++里,几乎每个类、函数、变量前面都有特定的宏。
常用宏
| 宏 | 作用 | 示例 |
|---|---|---|
UCLASS() |
标记一个类,让UE识别它 | UCLASS() class MYGAME_API AMyActor : public AActor |
USTRUCT() |
标记一个结构体 | USTRUCT() struct FMyData |
UPROPERTY() |
标记一个成员变量,让它出现在蓝图细节面板里 | UPROPERTY(EditAnywhere) int Health; |
UFUNCTION() |
标记一个成员函数,让它可以被蓝图调用 | UFUNCTION(BlueprintCallable) void Attack(); |
UINTERFACE() |
标记一个接口类 | UINTERFACE() class UMyInterface : public UInterface |
UPROPERTY的说明符(Specifier)
UPROPERTY()括号里可以加说明符,控制这个变量在编辑器里的行为:
EditAnywhere:在任何地方都可以编辑(包括蓝图实例和关卡里的实例)EditDefaultsOnly:只能在蓝图默认值里编辑(不能在关卡里改每个实例的值)VisibleAnywhere:在任何地方都可见,但不可编辑BlueprintReadOnly:蓝图里只读BlueprintReadWrite:蓝图里可读可写Category = "XXX":在细节面板里,把这个变量放在”XXX”分类下
UFUNCTION的说明符
UFUNCTION()括号里可以加说明符,控制这个函数在蓝图里的行为:
BlueprintCallable:可以在蓝图里调用这个函数BlueprintImplementableEvent:这个函数可以在蓝图里被”覆盖”(类似虚函数)BlueprintNativeEvent:这个函数有C++默认实现,但也可以在蓝图里被”覆盖”Server/Client/NetMulticast:网络同步相关(后面会讲)
UE C++的框架类
UE有一套自己的类继承体系,核心类有这些:
UObject:所有UE类的基类
如果你的类不需要放在关卡里(比如数据结构、管理器),继承UObject。
UObject提供了:
- 反射(Reflection):可以在运行时获取类的信息(有哪些属性、哪些函数)
- 垃圾回收(Garbage Collection):用
UPROPERTY()引用的UObject,会被自动回收(不用手动delete) - 序列化(Serialization):可以保存到磁盘/从磁盘加载
AActor:可以放在关卡里的东西
如果你的类需要出现在关卡里(比如角色、道具、触发器),继承AActor。
AActor本身一般不直接放网格体,而是用Component来组合功能。比如:
UStaticMeshComponent:显示静态模型USkeletalMeshComponent:显示骨骼模型UCameraComponent:摄像机UBoxComponent:碰撞体(盒子形状)USphereComponent:碰撞体(球形状)
ACharacter:带移动功能的角色
ACharacter继承自AActor,内置了:
UCharacterMovementComponent:处理移动逻辑(走、跑、跳、游泳、飞行)UCapsuleComponent:胶囊体碰撞(适合人形角色)USkeletalMeshComponent:骨骼模型
AGameMode:定义游戏规则
AGameMode定义了游戏的规则,比如:
- 玩家用什么角色类(
Default Pawn Class) - 玩家用什么Player Controller类(
Player Controller Class) - 游戏怎么开始、怎么结束
- HUD用什么类
注意: AGameMode只存在于服务器端(如果是网络游戏),客户端没有。
APlayerController:连接玩家和角色
APlayerController代表一个”玩家”。它处理:
- 输入(按键、鼠标、触屏)
- 视角控制
- 网络同步(如果是网络游戏,每个玩家有一个Player Controller)
在C++里写游戏逻辑
创建一个C++ Actor类
- 在UE5编辑器里,工具栏 →
Tools→New C++ Class - 选择父类(比如
AActor) - 输入类名(比如
AMyActor),点击Create Class - UE会自动生成两个文件:
MyActor.h(头文件)和MyActor.cpp(实现文件) - Visual Studio / Rider 会自动打开,你可以在里面写代码
- 写完代码后,点
Compile(工具栏上的按钮),UE会自动重新编译
C++与蓝图混合编程
实际项目中最常用的模式是:C++写底层逻辑,蓝图做上层定制。
具体做法:
- 在C++里,把需要在蓝图里访问的变量标记为
UPROPERTY(BlueprintReadOnly) - 在C++里,把需要在蓝图里调用的函数标记为
UFUNCTION(BlueprintCallable) - 在C++里,把需要在蓝图里”覆盖”的函数标记为
UFUNCTION(BlueprintImplementableEvent)(C++里不写实现,完全在蓝图里写) - 编译后,创建一个基于这个C++类的蓝图类(右键C++类 →
Create Blueprint class based on...) - 在蓝图里,就能访问C++暴露出来的变量和函数了
容器类型:TArray、TMap、TSet
UE C++有自己的容器类型,不要用标准C++的std::vector等。
TArray:动态数组
// 创建一个整数数组
TArray<int32> Scores;
// 添加元素
Scores.Add(100);
Scores.Add(200);
Scores.Push(300); // Push跟Add一样
// 访问元素
int32 FirstScore = Scores[0];
// 遍历
for (int32 Score : Scores) {
UE_LOG(LogTemp, Warning, TEXT("Score: %d"), Score);
}
// 查找
int32 Index = Scores.IndexOfByKey(200); // 返回1
// 删除
Scores.Remove(200);
TMap:键值对(字典)
// 创建一个"字符串→整数"的Map
TMap<FString, int32> PlayerScores;
// 添加
PlayerScores.Add("Player1", 100);
PlayerScores.Add("Player2", 200);
// 查找
int32* ScorePtr = PlayerScores.Find("Player1"); // 返回指针,如果没找到返回nullptr
// 遍历
for (auto& Pair : PlayerScores) {
UE_LOG(LogTemp, Warning, TEXT("%s: %d"), *Pair.Key, Pair.Value);
}
TSet:集合(不重复的元素)
TSet<int32> UniqueIDs;
UniqueIDs.Add(1001);
UniqueIDs.Add(1002);
UniqueIDs.Add(1001); // 重复添加,不会生效
智能指针:不用手动管理内存
UE C++有自己的智能指针系统(类似标准C++的std::shared_ptr),但更适合UE。
TSharedPtr:共享指针(最常用)
// 创建一个共享指针
TSharedPtr<FMyData> DataPtr = MakeShared<FMyData>();
// 使用
DataPtr->DoSomething();
// 不需要手动delete,引用计数为0时自动释放
TUniquePtr:独占指针
// 创建一个独占指针(只有一个地方能持有这个指针)
TUniquePtr<FMyData> DataPtr = MakeUnique<FMyData>();
// 不能复制,只能移动
TUniquePtr<FMyData> MovedPtr = MoveTemp(DataPtr);
注意: UObject不要用智能指针来管理,用UPROPERTY()引用,UE的垃圾回收会自动处理。
日志输出:调试C++代码的利器
在C++里输出日志,用UE_LOG宏:
// 输出普通日志
UE_LOG(LogTemp, Warning, TEXT("Hello, UE C++!"));
// 输出带变量的日志
int32 Health = 100;
UE_LOG(LogTemp, Warning, TEXT("Health: %d"), Health);
// 输出字符串
FString PlayerName = "Alice";
UE_LOG(LogTemp, Warning, TEXT("Player: %s"), *PlayerName);
// 输出向量
FVector Location = FVector(100, 200, 300);
UE_LOG(LogTemp, Warning, TEXT("Location: %s"), *Location.ToString());
日志会输出到:
- 输出日志(Output Log)窗口(UE编辑器里)
- Visual Studio的输出窗口(如果在调试模式下运行)
招聘需求参考(Boss直聘,2026年6月)
看了40多个”UE5 C++程序员”职位,总结:
- 熟悉UE C++框架:知道UObject、AActor、ACharacter、AGameMode等类的用途
- 会用UE宏系统:知道UPROPERTY、UFUNCTION等宏的用法
- 了解容器和智能指针:会用TArray、TMap、TSharedPtr
- 有实际项目经验:能展示用C++写的游戏逻辑(比如AI系统、网络同步、插件)
- 加分项:会用
UnrealHeaderTool(UHT)、了解Gameplay Ability System(GAS)、会写网络同步代码
相关课程: 火星人教育UE5 C++编程培训课程,从C++语法到UE框架,结合实际游戏项目案例。

评论(0)