下面按“面试可能问到的底层基础”来梳理,不展开到源码级,但要能说清楚 UE5 为什么这样设计、各模块怎么协作。

1. UObject / 反射系统

核心知识:

UE 的很多对象都继承自 UObject,例如 Actor、ActorComponent、DataAsset、Widget 等。UObject 最大的价值不是普通 C++ 继承,而是接入了 UE 的反射、GC、序列化、蓝图、编辑器属性面板等系统。

常见问法:

UE 的反射系统是怎么来的?

UCLASS、UPROPERTY、UFUNCTION 有什么用?

为什么 UE 不直接用 C++ RTTI?

标准回答:

UE 通过 UHT,也就是 Unreal Header Tool,在编译前扫描带有 UCLASS、UPROPERTY、UFUNCTION 等宏的代码,生成额外的反射代码。反射信息会记录类名、父类、属性、函数、元数据等,使对象可以被编辑器识别、被蓝图调用、被序列化、被 GC 追踪。

UE 不完全依赖 C++ RTTI,是因为引擎需要更强的跨平台、编辑器、蓝图、序列化和对象管理能力。C++ RTTI 只能解决运行时类型识别,不能满足属性面板、蓝图暴露、网络复制、存档等需求。

2. UObject 生命周期与 GC

核心知识:

UE 的 UObject 由引擎对象系统管理,不能像普通 C++ 对象一样随便 new/delete。GC 会从 Root Set 出发,沿着 UPROPERTY 引用链标记可达对象,不可达对象会被回收。

常见问法:

UE 的 GC 怎么知道一个对象要不要回收?

为什么 UObject 指针要写 UPROPERTY?

MarkAsGarbage 是不是直接销毁对象?

标准回答:

UE GC 采用标记清除思路。它从 Root Set、World、Level、Actor、被 UPROPERTY 标记的引用等出发,遍历对象引用关系。能被访问到的对象保留,访问不到的对象会在 GC 阶段被回收。

UPROPERTY 的意义是把对象引用暴露给反射系统和 GC。如果一个 UObject 指针只是普通 C++ 裸指针,GC 可能不知道这个引用存在,导致对象被误回收。MarkAsGarbage 只是标记对象可回收,不是立刻 delete。

3. Actor / Component 架构

核心知识:

Actor 是可以放进 World 的游戏对象,Component 是挂在 Actor 上的功能模块。UE 倾向于用组件组合功能,而不是所有功能都写进继承层级。

常见问法:

UObject 和 Actor 是什么关系?

Actor 和 ActorComponent 的关系是什么?

为什么很多功能适合做成 Component?

标准回答:

Actor 继承自 UObject,是一种可以存在于关卡中的对象,拥有 Transform、生命周期、Tick、网络复制等能力。ActorComponent 也是 UObject,但它不能独立放在场景中,通常挂在 Actor 上提供功能。

使用 Component 的好处是组合优于继承。例如攻击系统、装备系统、交互系统、血量系统都可以做成 Component,不同角色按需挂载,复用性更好,也避免角色类越来越臃肿。

4. World / Level / GameInstance

核心知识:

UE 的运行世界由 UWorld 管理,Level 是场景内容,GameInstance 是整个游戏进程生命周期内较持久的对象。

常见问法:

GameInstance、GameMode、GameState、PlayerController、Pawn 分别干什么?

哪些只存在服务器?哪些客户端也有?

标准回答:

GameInstance 生命周期最长,切换关卡时也可以保留,适合保存全局状态。

GameMode 只在服务器存在,负责游戏规则,比如玩家出生、胜负条件。

GameState 服务器和客户端都有,用来同步公共游戏状态。

PlayerController 代表玩家控制逻辑,处理输入和控制 Pawn。

Pawn 是可以被控制的角色或单位,Character 是 Pawn 的一种,内置移动组件和胶囊体。

5. Tick 与引擎主循环

核心知识:

UE 每帧会执行输入、游戏逻辑、动画、物理、渲染提交等流程。Tick 是最常见的每帧更新入口,但不能滥用。

常见问法:

Tick 是什么时候执行的?

为什么不建议大量对象 Tick?

如果不用 Tick,怎么实现定时逻辑?

标准回答:

Tick 是对象每帧更新逻辑的入口,Actor、Component 都可以 Tick。但大量 Tick 会增加 Game Thread 压力,尤其是很多对象每帧做查询、寻路、Trace 或复杂判断时容易卡顿。

可以用 Timer、事件驱动、AnimNotify、Behavior Tree Service、状态变化回调等方式替代 Tick。比如 AI 距离检测不需要每帧做,可以 0.3 到 0.5 秒更新一次。

6. 蓝图与 C++ 通信

核心知识:

UE 的常见开发方式是 C++ 写底层和框架,蓝图做配置、表现和快速迭代。

常见问法:

C++ 和蓝图怎么通信?

BlueprintCallable、BlueprintImplementableEvent、BlueprintNativeEvent 有什么区别?

什么时候用 C++,什么时候用蓝图?

标准回答:

C++ 可以通过 UFUNCTION 暴露函数给蓝图,通过 UPROPERTY 暴露变量给编辑器和蓝图。BlueprintCallable 表示蓝图可以调用这个 C++ 函数;BlueprintImplementableEvent 表示 C++ 声明事件,蓝图实现;BlueprintNativeEvent 表示 C++ 可以提供默认实现,蓝图也可以重写。

底层逻辑、性能敏感、多人同步、复杂系统框架适合 C++;UI、动画衔接、关卡脚本、数值配置、简单交互适合蓝图。

7. 委托 / 事件系统

核心知识:

委托是 UE 里常用的解耦机制,相当于事件回调。一个系统发生变化后,不需要直接依赖另一个系统,只需要广播事件。

常见问法:

UE 委托有什么用?

单播、多播、动态委托区别?

标准回答:

委托用于解耦模块。例如血量组件血量归零后广播 OnDeath,AI、UI、任务系统都可以监听,不需要血量组件直接调用它们。

单播委托绑定一个回调,多播委托可以绑定多个回调。动态委托支持反射和蓝图绑定,但开销更高;普通 C++ 委托性能更好。

8. 序列化与资源系统

核心知识:

UE 的序列化用于保存和加载对象数据,资源文件 .uasset 本质上也依赖 UE 的对象和序列化系统。

常见问法:

UE 序列化是干什么的?

修改类成员后,已经保存的资源怎么兼容?

DataAsset 和 DataTable 有什么区别?

标准回答:

UE 序列化负责把 UObject 的属性保存到磁盘,或者从磁盘加载回来。UPROPERTY 标记的属性可以被引擎识别并参与序列化、编辑器显示、复制等流程。

如果修改了类成员,需要考虑旧资源兼容,比如给新字段默认值、保留旧字段迁移数据、使用版本号处理加载逻辑。

DataAsset 更适合一个对象一份配置,比如武器、敌人、技能;DataTable 更适合表格化批量数据,比如大量物品或数值配置。

9. 动画系统与 AnimNotify

核心知识:

游戏战斗里很多逻辑不是按键瞬间触发,而是跟动画时间点绑定。AnimNotify 用来在动画指定帧触发逻辑。

常见问法:

为什么攻击判定要放在 AnimNotify 里?

Montage 有什么用?

状态机和 Montage 区别?

标准回答:

攻击输入只代表玩家想攻击,但真正的伤害判定应该发生在武器挥到敌人那一段动画时间里,所以用 AnimNotify 打开 Trace 或碰撞窗口更合理。

Montage 适合播放攻击、翻滚、受击、处决这类临时动作,可以插入 Notify、分段播放、打断和混合。动画状态机更适合待机、走路、跑步、跳跃等持续状态切换。

10. 碰撞与 Trace

核心知识:

UE 碰撞主要涉及 Collision Channel、Object Type、Response、Overlap、Hit、Trace。

常见问法:

Overlap 和 Hit 区别?

LineTrace、SphereTrace、碰撞体检测怎么选?

高速子弹穿透怎么办?

标准回答:

Overlap 表示两个碰撞体发生重叠,不一定有物理阻挡;Hit 通常表示发生阻挡碰撞,有命中点、法线等信息。

LineTrace 适合射线检测,比如枪械、视线检测;SphereTrace 有体积,更适合近战武器扫击或容错检测;Overlap 适合范围触发器。

高速子弹如果只靠离散碰撞,可能一帧前在敌人前,一帧后在敌人后,直接穿过去。解决方法是使用连续检测,比如上一帧位置到当前帧位置做 LineTrace / SphereTrace,或者启用 CCD。

11. AIController / Blackboard / Behavior Tree

核心知识:

UE AI 常见组合是 AIController 控制 Pawn,Blackboard 存状态,Behavior Tree 做决策。

常见问法:

Behavior Tree、Blackboard、Task、Service、Decorator 分别是什么?

为什么不用 Tick 写 AI?

标准回答:

AIController 是 AI 的控制者,Blackboard 是行为树共享的数据表,比如 TargetActor、Distance、PatrolLocation。Behavior Tree 根据黑板状态选择行为。

Task 执行具体动作,比如移动、攻击;Service 定时更新数据,比如目标距离;Decorator 判断条件,比如是否有目标、是否在攻击范围内。

行为树比 Tick 里写大量 if else 更清晰,状态切换更可视化,也更适合策划和程序协作。

12. NavMesh 与寻路

核心知识:

NavMesh 是把场景中可走区域生成导航网格,AI 寻路会在导航网格上计算路径。

常见问法:

NavMesh 是什么?

AI 为什么 MoveTo 失败?

A* 和 NavMesh 有什么关系?

标准回答:

NavMesh 表示角色可行走区域。AI MoveTo 时会根据目标点在 NavMesh 上搜索路径,然后沿路径移动。

MoveTo 失败常见原因包括目标点不在 NavMesh 上、NavMesh Bounds Volume 没覆盖、角色碰撞体太大、Agent 半径/高度配置不匹配、目标不可达。

A* 是常见寻路算法,NavMesh 提供图结构,A* 在图上搜索从起点到终点的较优路径。

13. 网络复制基础

核心知识:

UE 网络模型通常是服务器权威。Actor 和属性可以复制,RPC 用于远程调用。

常见问法:

UE Replication 是什么?

Server RPC、Client RPC、Multicast RPC 区别?

为什么不能相信客户端?

标准回答:

Replication 是服务器把 Actor 或属性状态同步到客户端。服务器通常拥有权威状态,客户端负责表现和输入。

Server RPC 是客户端请求服务器执行逻辑,例如释放技能;Client RPC 是服务器通知某个客户端;Multicast RPC 是服务器通知所有相关客户端。

不能相信客户端是因为客户端容易被篡改。伤害、掉落、购买、技能命中等关键逻辑应该由服务器校验。

14. 引擎线程模型

核心知识:

UE 不是所有工作都在一个线程里。常见有 Game Thread、Render Thread、RHI Thread,以及异步加载线程等。

常见问法:

Game Thread 和 Render Thread 分别干什么?

为什么不能在主线程等网络请求?

异步任务完成后怎么回到游戏线程?

标准回答:

Game Thread 负责游戏逻辑、Actor Tick、输入、AI 等。Render Thread 负责把渲染命令组织并提交给底层图形接口。RHI Thread 更接近底层图形 API 调用。

网络请求、文件加载、AI 请求、耗时计算不能阻塞 Game Thread,否则会卡帧。异步完成后,如果要操作 UObject 或 UI,通常需要切回 Game Thread。

15. 模块与插件系统

核心知识:

UE 工程和插件都可以拆成模块。插件可以有 Runtime Module 和 Editor Module。

常见问法:

UE 插件怎么设计?

Runtime Module 和 Editor Module 区别?

为什么工具代码不应该放进运行时模块?

标准回答:

Runtime Module 是游戏运行时需要的代码,可以打包进游戏;Editor Module 只在编辑器中使用,比如自定义面板、导入工具、资产检查工具。

插件设计时,运行时能力应该放 Runtime,编辑器工具放 Editor,避免把编辑器依赖带进最终包体。对外接口可以用 Subsystem、ActorComponent 和 BlueprintCallable API 暴露。

16. 渲染管线与 RHI

核心知识:

UE 渲染大体经过场景收集、可见性剔除、阴影、BasePass、光照、后处理、UI 等阶段。RHI 用来屏蔽不同图形 API 差异。

常见问法:

RHI 是干什么的?

UE 为什么要有 Render Thread?

Lumen / Nanite 大概是什么?

标准回答:

RHI 是 Render Hardware Interface,负责抽象 DirectX、Vulkan、Metal 等底层图形 API,让上层渲染代码可以跨平台。

Render Thread 把渲染提交和游戏逻辑分开,减少 Game Thread 被 GPU 提交细节拖慢。

Nanite 是 UE5 的虚拟化几何系统,用于高面数模型的高效渲染;Lumen 是动态全局光照和反射系统,用于更实时的间接光效果。

17. 性能分析与调试

核心知识:

游戏客户端面试很容易问“卡了怎么查”。UE 里要知道 stat 命令、Unreal Insights、Profiler、Behavior Tree Debugger、碰撞调试。

常见问法:

游戏卡顿你怎么定位?

怎么判断是 CPU 还是 GPU 瓶颈?

AI 不动怎么查?

标准回答:

我会先复现问题,然后用 stat unit 看 Game、Draw、GPU 时间。如果 Game 高,优先看 Tick、AI、蓝图、碰撞、网络;如果 Draw 高,看渲染提交和物体数量;如果 GPU 高,看材质、后处理、阴影、透明物体、粒子。

AI 问题可以看 Behavior Tree Debugger、Blackboard 值、NavMesh 可视化、MoveTo 返回结果和碰撞设置。

你面试前最该背的优先级

第一优先级:UObject / 反射 / GC / UPROPERTY。

第二优先级:Actor / Component / GameMode / Controller / Pawn。

第三优先级:蓝图 C++ 通信、委托、AnimNotify、碰撞 Trace。

第四优先级:Behavior Tree / Blackboard / NavMesh。

第五优先级:Tick 优化、对象池、异步、线程、Profiler。

如果时间紧,你不需要把源码细节背到很深,但每个点都要能回答“它解决什么问题、核心机制是什么、在我的 Demo 里哪里用到了”。

原文:可能的UE底层知识