很多蓝图程序员做到一定程度,都会遇到一个瓶颈:有些事情蓝图做不到,或者做起来太慢了。

这时候就需要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类

  1. 在UE5编辑器里,工具栏 → ToolsNew C++ Class
  2. 选择父类(比如AActor
  3. 输入类名(比如AMyActor),点击Create Class
  4. UE会自动生成两个文件:MyActor.h(头文件)和MyActor.cpp(实现文件)
  5. Visual Studio / Rider 会自动打开,你可以在里面写代码
  6. 写完代码后,点Compile(工具栏上的按钮),UE会自动重新编译

C++与蓝图混合编程

实际项目中最常用的模式是:C++写底层逻辑,蓝图做上层定制

具体做法:

  1. 在C++里,把需要在蓝图里访问的变量标记为UPROPERTY(BlueprintReadOnly)
  2. 在C++里,把需要在蓝图里调用的函数标记为UFUNCTION(BlueprintCallable)
  3. 在C++里,把需要在蓝图里”覆盖”的函数标记为UFUNCTION(BlueprintImplementableEvent)(C++里不写实现,完全在蓝图里写)
  4. 编译后,创建一个基于这个C++类的蓝图类(右键C++类 → Create Blueprint class based on...
  5. 在蓝图里,就能访问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框架,结合实际游戏项目案例。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。