ue Q&A
前言
收集ue相关问题。AI辅助。
QA1
actor与uobject的关系 gc 委托有哪些种类 蓝图通信方式 UE有哪些线程 自定义事件与函数的区别 GAS c++的类型转换 静态多态和动态多态 虚继承 右值引用和移动语义 用过哪些脚本语言 大世界流式关卡加载有卡顿怎么解决 同一范围内有大量行为树运行如何优化 游戏内存溢出如何解决
QA2
一、基础概念与引擎架构
Actor与Component的区别是什么?各自的应用场景?
- Actor 可以独立存在于世界中有根组件的变换,可以设置位置、旋转、缩放 AActor* Actor = GetWorld()->SpawnActor
(); - 必须依附于Actor 相对于父组件的相对变换,或相对于Actor的根组件的相对变换
- SceneComponent的核心作用 变换层级系统(Transform Hierarchy)
- 变换层级系统(Transform Hierarchy)
- 插槽系统(Socket System)
- 变换空间转换
- 变换更新与同步
- 总结: 比起Actor 的Transform 有Mesh,Collider,physics
- Actor 可以独立存在于世界中有根组件的变换,可以设置位置、旋转、缩放 AActor* Actor = GetWorld()->SpawnActor
Pawn、Character、Controller分别是什么?它们之间的关系如何?
- **Pawn **可操控的实体
- Character 角色移动、动画、胶囊体碰撞
- Controller 处理输入、AI决策、管理状态
UObject、AActor、UActorComponent的继承关系是怎样的?
UObject:UE中所有对象的基类,提供基础特性如反射、序列化、垃圾回收等。
AActor:继承自UObject,是可以在场景中放置和生成的对象基类。。
UActorComponent:继承自UObject,是附加在Actor上的组件基类。
AActor和UActorComponent是并列关系,都直接继承自UObject,但UActorComponent不是继承自AActor。
UObject的设计基础
反射:支持运行时类型信息,蓝图、编辑器集成GC:自动内存管理,避免内存泄漏
序列化:支持保存/加载,热重载
网络:内置网络复制支持
CDO:类默认对象,支持编辑器配置默认值
```
UObjectBase (引擎内部基类)↓UObject (所有UE对象的基类)
├── AActor (可放入世界的对象) │ ├── APawn (可被控制的Actor) │ │ └── ACharacter (角色Actor) │ ├── AController (控制Pawn的Actor) │ │ ├── APlayerController │ │ └── AAIController │ └── ... 其他所有Actor派生类 │ └── UActorComponent (附加到Actor的组件) ├── USceneComponent (有变换能力的组件) │ ├── UPrimitiveComponent (可渲染/有碰撞的组件) │ │ ├── UStaticMeshComponent │ │ ├── USkeletalMeshComponent │ │ ├── UCapsuleComponent │ │ └── ... │ └── UCameraComponent, USpringArmComponent等 │ └── 其他Component ├── UMovementComponent ├── UInputComponent ├── UAbilitySystemComponent └── ...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
4. **简述UE的反射系统(Reflection System)的作用及常见用途。**
1. **运行时类型信息**:提供完整的类、属性、函数信息
**序列化支持**:自动保存/加载对象状态
**网络复制**:支持属性同步和RPC调用
**蓝图集成**:实现C++与蓝图的无缝交互
**编辑器集成**:支持属性面板、细节定制
**垃圾回收**:提供引用跟踪信息
5. **Gameplay框架中GameInstance、World、GameMode、Level、Actor、Pawn的关系是什么?**// 继承链
UObject
├── UWorld* (World不是UObject派生,但由引擎管理)
├── UGameInstance (继承UObject)
├── AGameModeBase (继承AActor)
├── APlayerController (继承AActor)
├── AActor
│ ├── APawn
│ │ └── ACharacter
│ ├── AController
│ │ ├── APlayerController
│ │ └── AAIController
│ └── AGameStateBase1
2
3
4
5
### 继承链UObjectBase (引擎内部基类)
↓
UObject (所有UE对象的基类)
├── UGameInstance (在整个游戏生命周期内始终存在的全局管理器。独立存在于服务器和所有客户端,不随关卡切换而销毁。管理游戏保存系统、在线服务(好友、游戏会话、排行榜等)以及需要在多个关卡间持久化的数据。)
│
├── AActor (可放入世界的对象。包含了诸如Replication,Spawn,Tick等基础功能。所有可放置在关卡中的对象的基类,如摄像机、静态网格体、玩家出生点等。)
│ ├── AGameModeBase (定义游戏规则的核心类,相当于游戏的“导演”。仅在服务器上运行,每个关卡可以设置不同的GameMode。制定胜利条件、玩家数量限制、生成规则等,并在创建时实例化GameState和PlayerState。)
│ │
│ ├── AGameStateBase (存储游戏的全局状态信息,相当于“公告板”。在服务器和所有客户端间同步。内容:队伍得分、游戏时间、所有玩家列表等所有玩家可见的全局数据。)
│ │
│ ├── APawn (所有可被玩家或AI控制的Actor的基类,是玩家在游戏世界中的物理实体。)
│ │ └── ACharacter (Pawn的特殊子类,专为角色设计,内置角色移动组件、骨架网格体组件和胶囊体碰撞组件,支持行走、奔跑、跳跃等标准动作。)
│ │
│ ├── AController (控制Pawn的Actor,非实体Actor,在游戏世界中没有物理表示。)
│ │ ├── APlayerController (处理人类玩家的输入,控制摄像机,管理HUD。)
│ │ └── AAIController (控制非玩家角色,使用行为树、状态树、寻路等AI系统。)
│ │
│ ├── APlayerState (存储单个玩家的状态信息。内容:生命值、子弹数量、物品栏、得分等玩家个人数据。与Player和PlayerController保持1:1:1的关系。)
│ │
│ ├── AHUD (平视显示器,可以理解为对部分Player State的场景可视化。比如怪物或者人物头顶的血条,名字等等。一般来说是不能交互的,显示简略信息。)
│ │
│ └── … 其他所有Actor派生类
│
├── UActorComponent (附加到Actor的组件。Actor的功能构成元素,控制Actor的移动、渲染、位置等不同方面。Actor可以添加UActorComponent来实现功能的扩展。)
│ ├── USceneComponent (有变换能力的组件)
│ │ ├── UPrimitiveComponent (可渲染/有碰撞的组件)
│ │ │ ├── UStaticMeshComponent
│ │ │ ├── USkeletalMeshComponent
│ │ │ ├── UCapsuleComponent
│ │ │ └── …
│ │ └── UCameraComponent, USpringArmComponent等
│ │
│ └── 其他Component
│ ├── UMovementComponent
│ ├── UInputComponent
│ ├── UAbilitySystemComponent
│ └── …
│
├── UUserWidget (用户界面,覆盖在场景渲染之上,提供更多玩家交互和查看的信息。指的是菜单和其他互动元素。可交互的用户界面。)
│
├── UWorld (负责管理所有的ULevel。)
│
└── ULevel (所有的Actor都存在于ULevel中。)
注意:UUserWidget 继承自 UWidget,UWidget 继承自 UVisual,UVisual 继承自 UObject。这里为了简化,直接连接到了 UObject。同样,UWorld 和 ULevel 的继承链也做了简化。
1 |
|
委托(Delegate)机制怎么用?单播和多播委托的区别及应用场景?
需要返回值 → 单播委托
多个监听者 → 多播委托
与蓝图交互 → 动态多播委托
性能敏感 → 单播委托
蓝图通信的常用方式有哪些?各自适用场景?
三、内存管理与智能指针
UE中常用的智能指针有哪些?TSharedPtr、TUniquePtr、TWeakPtr的区别和使用场景?(备注)
TArray与std::vector有何异同?TMap和TSet的底层原理是什么?
- TArray深度集成UE(序列化、网络、蓝图)
UStruct和UClass在内存布局上有何不同?
UE的异步加载使用哪种智能指针存储资源?
四、网络与同步
- UE的网络同步原理是什么?常用的同步属性/函数声明方式?(备注)
- 如何优化大量Actor的网络同步性能?PushModel是什么?
- GAS(Gameplay Ability System)的两种网络策略是什么?区别及性能开销?
- FastArray常用接口有哪些?如何提升同步效率?
- 动画同步与多播机制如何实现?多播动画是否会在主控端和模拟端各播放一次?
五、渲染与性能优化
- 前向渲染与延迟渲染的区别?UE默认使用哪种?
- 如何优化UE项目的帧率?常用的性能分析工具有哪些?
- LOD(Level of Detail)的原理是什么?在UE中如何应用?
- 材质系统的基本原理?PBR(物理基础渲染)是什么?
- Nanite和Lumen的核心原理是什么?与UE4相比有哪些革新?
六、物理与碰撞
- 如何在UE中实现物体的碰撞检测?常用的碰撞体类型有哪些?
- 子弹速度过快导致穿墙的原因是什么?如何解决?
- 伤害检测与碰撞判定的流程?墙体遮挡的判定如何优化?
七、动画与行为树
- 动画蓝图(Anim Blueprint)与动画蒙太奇(Montage)的区别?
- 行为树(Behavior Tree)和黑板(Blackboard)是什么?多个NPC能否复用行为树?如何实现?
- 增强型输入系统(Enhanced Input)如何工作?
八、系统设计与场景题
- 设计一个回旋镖系统(包括运动轨迹、伤害判定、回收机制)。
- 游戏中非常卡顿,只有二三十帧,你如何定位卡顿原因?
- 游戏中有很多个Actor导致卡顿,如何进行性能优化?
- 对象池(Object Pool)如何实现?在什么场景下使用?
- 如果要进行关卡切换,但不想用GameInstance保存数据,可以怎么做?
九、C++底层与算法
- C++中的多态性和虚函数机制?在UE中的应用举例。
- 智能指针的原理?循环引用如何解决?
- 右值引用、完美转发、引用折叠的原理是什么?
- SFINAE是什么?模板匹配的优先级?
- 长度为n-1的数组,元素为1~n的数字,其中缺了一个数字,如何快速找出来?
十、项目经验与架构设计
- 你在项目中用GAS做了什么?请详细说明。
- 你实现过什么系统吗?请描述设计思路和难点。
- 如果要设计一个生命周期与GameMode一致的子系统,如何实现?
- 如何设计一个支持不定数量和类型参数的委托机制?
- 大世界场景下GC如何优化?除了簇和新老生代还有哪些方法?
QA3
CPP
GP
第一组:UE核心架构(必问)
1️⃣ Actor 生命周期(高频必杀题)
你讲清楚一个 Actor 从创建到销毁的完整流程:
- 构造函数什么时候调用?(和Spawn的关系)
A:
PostInitProperties/PostInitializeComponents/BeginPlay区别?
A:
避免在构造函数中进行复杂逻辑,因为此时许多系统可能未初始化
避免在PostInitProperties中访问组件,因为它们还不存在
PostInitializeComponents适合组件间的设置,但不适合开始游戏逻辑
BeginPlay是最安全、最常用的初始化点,特别是对于蓝图项目
Tick是怎么被调度的?
A:执行顺序 →
- TG_PrePhysics // 物理计算前
- TG_StartPhysics // 开始物理模拟
- TG_DuringPhysics // 物理模拟期间(并行)
- TG_EndPhysics // 物理模拟结束
- TG_PostPhysics // 物理计算后
- TG_PostUpdateWork // 后更新工作
- TG_LastDemotable // 最后可降级的
Destroy之后会立刻销毁吗?
A:
EndPlay()
调用 Destroy() 的时刻
Actor 被标记为 “待销毁” (PendingKill)
当前帧继续执行(Actor 仍然存在)
下一帧开始前执行实际清理
资源释放和内存回收
- 收集所有标记为 PendingKill 的对象
- 调用 BeginDestroy() 开始销毁
- 检查引用 IsReadyForFinishDestroy()
- 调用 FinishDestroy() 完成销毁
- 释放内存
👉 面试官想听的是:调用顺序 + 引擎机制,不是函数名罗列
2️⃣ UObject vs Actor(本质区别)
- UObject 为什么不能直接放到世界里?
A:
UObject
核心功能:反射、序列化、垃圾回收、属性系统
但缺少:位置、旋转、缩放、场景表示
- Actor 比 UObject 多了什么能力?
A:
Actor特有:
Transfrom,Component,生命周期,world交互,physics,Replicated/RPC,Visible,Tag,Parent,Level,InputUObject基础能力:
Save,Blueprint,editorComponent 为什么必须挂在 Actor 上?
A:
组合模式(Composition over Inheritance)
创建Component时,将其注册到Actor,Actor会负责调用Component的初始化、Tick和销毁函数。
当Actor被销毁时,它所拥有的所有Component也会被销毁。
Actor 是”什么”(游戏世界中的实体)
Component 是”如何”(实体的功能和行为)
Component 必须属于某个 Actor,就像功能必须属于某个实体
👉 如果你答成“一个是基础类一个是实体类”,基本不过
3️⃣ 反射系统(UE最核心之一)
讲一下 UE 反射系统:
UCLASS / UPROPERTY / UFUNCTION本质做了什么?
A:UCLASS、UPROPERTY、UFUNCTION是虚幻引擎(UE)反射系统的核心宏。它们的本质是通过预处理和代码生成,将 C++ 类、属性和函数标记为“可反射的”,从而在运行时能够被引擎识别、访问和操作。
编译前:元数据标记与代码生成,预处理展开#define,UHT扫描头文件,生成generated元数据
运行时:
.generated.h是怎么来的?
.generated.h文件是虚幻引擎反射系统的编译时生成产物,由 UHT 工具自动创建。它:
是反射系统的”源代码”:将宏标记转换为实际的C++代码
在编译时生成:由 UBT 驱动,UHT 执行
实现了类型自省:让C++类在运行时能查询自身结构
支持所有UE高级特性:蓝图、序列化、网络、编辑器集成
- 反射数据在运行时存在哪里?
- 补:RTTI是什么
👉 这一题直接区分“会用UE”和“懂UE”
第二组:组件与模块化(中级)
4️⃣ ActorComponent 机制
- Component 是怎么被注册的?
RegisterComponent()做了什么?- TickComponent 是怎么进入调度的?
5️⃣ Subsystem(UE5常问)
- GameInstanceSubsystem / WorldSubsystem 区别?
- 生命周期分别是什么?
- 为什么不用单例而用 Subsystem?
第三组:内存与GC(高频深水区)
6️⃣ UE 的 GC 机制
- UE 是怎么做垃圾回收的?(引用计数吗?)
A:标记阶段:从根集(Root Set)(如全局变量、当前栈上的对象引用、显式标记为根的对象等)出发,扫描所有 UObject 对象。凡是能被直接或间接引用到的对象,都会被标记为“可达”(存活)。
清除阶段:所有未被标记的对象被判定为“垃圾”,随后在合适的时机被销毁并释放内存
UPROPERTY为什么重要?- 什么情况下对象会被回收?
👉 这一题很多人会死在“说成引用计数”
A: 详见GC文章
7️⃣ 智能指针 vs UObject
TSharedPtr和 UObject 能一起用吗?- 为什么 UObject 不用 shared_ptr?
A:TSharedPtr这类指针是不能直接用于UObject的(非得强行使用也不是不行,但是要自己实现Deleter)
第四组:Tick与性能(实战向)
8️⃣ Tick 系统
- Tick 是怎么调度的?
- Tick Group 是干嘛的?
- 怎么减少 Tick 开销?
9️⃣ 多线程(加分题)
- UE 主线程做什么?
- 渲染线程是什么?
- Gameplay 能不能多线程?
第五组:进阶(拉开差距)
🔟 模块系统(Module)
- UE 模块是怎么加载的?
IMPLEMENT_MODULE做了什么?- 游戏启动流程大致是什么?
回答建议
你可以这样来:
👉 直接说:“我答第1题”
我会根据你回答继续往深里追(比如直接问源码级细节)
提醒你一个现实情况
如果你目标是“一线游戏公司”:
- 能答到 第3组(GC) → 中级稳
- 能答到 第4组(Tick + 性能) → 中高级
- 能答第5组 → 面试官会认真考虑你
Unlua
好,这块我会按“UE客户端 + 脚本层架构”面试强度来问,重点不是Lua语法,而是:
👉 UnLua 如何嵌入 UE、如何做工程化、以及你是否真的在项目中用过
你可以一题一题答,我会继续深挖。
第一组:UnLua 基础原理(必问)
1️⃣ UnLua 是怎么工作的?
你讲清楚:
- UnLua 是怎么把 Lua 绑定到 UE 的?
- C++ 类是怎么暴露给 Lua 的?
- Lua 是怎么调用 UObject / Actor 方法的?
👉 至少要提到:反射 / 绑定 / 虚拟机交互
2️⃣ Lua 文件是怎么驱动 Actor 的?
比如你有一个 Actor:
1 | UCLASS() |
你用 UnLua:
- Lua 是怎么“接管”这个 Actor 的?
- 生命周期函数(BeginPlay / Tick)是怎么映射的?
👉 不要只说“写同名函数”,要说机制
第二组:架构设计(中级分水岭)
3️⃣ 为什么用 UnLua,而不是全 C++?
你需要讲清楚:
- 优点(至少3点)
- 缺点(至少2点)
- 适合放 Lua 的模块有哪些?
👉 这一题考的是“工程判断力”
4️⃣ C++ 和 Lua 怎么分层?
假设一个项目:
- 战斗系统
- UI系统
- 技能逻辑
你会怎么拆?
👉 如果你回答“UI用Lua,底层用C++”,这是初级答案
👉 我要听的是:边界 + 原则
第三组:性能与坑(高频)
5️⃣ UnLua 性能问题
- Lua 调用 C++ 开销大吗?
- 哪些地方会成为瓶颈?
- 如何优化?
👉 能说到“减少跨语言调用”才算入门
6️⃣ GC 与内存管理
- Lua 有 GC,UE 也有 GC → 会冲突吗?
- UObject 在 Lua 里怎么保证不被回收?
- 有没有遇到野指针 / dangling 的问题?
👉 这题非常关键(很多人不会)
第四组:进阶(拉开差距)
7️⃣ 热更新(Hotfix)
- UnLua 能不能热更新?
- 怎么做?
- 有什么限制?
8️⃣ 生命周期问题(真实项目坑)
比如:
- Actor 被销毁了,但 Lua 还持有引用怎么办?
- World 切换时 Lua 状态怎么处理?
👉 能答这题,基本就是“用过项目”的人
第五组:深水区(高阶)
9️⃣ 你了解 UnLua 的绑定方式吗?
- 是静态绑定还是动态绑定?
- 有没有用到模板 / 宏生成?
- 和 tolua++ / slua 的区别?
回答建议
👉 从第1题开始答(UnLua原理)
我会像面试官一样:
- 追问你源码层细节
- 帮你补成“中高级答案”
- 告诉你这题能不能过一线
提醒你一个关键点
很多人写了:
“熟悉UnLua”
但实际上只能回答:
- 写Lua脚本
- 调UE接口
👉 这种在一线面试里是直接挂的
开始吧:
👉 先答第1题:UnLua 是怎么工作的?
DS
第一组:UE网络基础(必杀)
1️⃣ UE 网络模型(必须讲清)
你说一下 UE 是什么网络模型:
- 是 Client-Server 还是 P2P?
A:CS(DS) P2P(LS)
- Server 是权威的吗?
A:Server 是权威的:服务器(Server)拥有游戏状态的最终决定权,是唯一权威(Authority)的来源。
- Client 能不能修改状态?
A:Client 不能直接修改权威状态:客户端(Client)不能直接修改服务器上的权威状态。它需要通过向服务器发送远程过程调用(RPC)来请求状态更改,由服务器验证并执行。
👉 如果你没提到 Authority / AutonomousProxy / SimulatedProxy,这一题算没答好
2️⃣ Actor 同步机制 (待 源码)
一个 Actor 在网络中是怎么同步的:
- 什么是 Replication?
bReplicates开了之后发生了什么?- 属性同步(UPROPERTY Replicated)是怎么走的?
👉 面试官要听:引擎在背后做了什么
3️⃣ RPC 机制
- Server / Client / NetMulticast 区别?
A: 服务器,单播,广播
- RPC 是立即执行的吗?
A:RPC 是非阻塞的异步网络操作,不会立即在目标端执行。执行时机受网络延迟、带宽、优先级和可靠性的影响。
- Reliable vs Unreliable 怎么选?
A:
低频且重要、不能丢的事件:交易、授权、评分结算 等系统逻辑事件
高频或可被覆盖的事件:移动与位置,动画口型特效,UI的更新事件(扣血数据等必须要可靠),语音聊天
不可靠:Tick连续变化可以使用,只是表现出问题数据没问题可以使用
👉 很多人会答成“Server就是服务器调用”,这是不够的
第二组:移动同步(中级分水岭)
4️⃣ 角色移动同步(CharacterMovement)
移动(Movement Replication / CharacterMovement)
这是超高频题:
- 为什么 Character 移动看起来很流畅?
- Client Prediction 是怎么做的?
- Server Correction 怎么处理?
👉 至少要讲:
- 输入上报
- 服务端重算
- 回滚 / 修正
5️⃣ 延迟与抖动处理
- 网络延迟会带来什么问题?
- 怎么减少“卡顿感”?
- 插值(Interpolation)和预测的区别?
第三组:技能同步(GAS/战斗系统核心)
6️⃣ 技能同步怎么做?
假设你用 GAS 或自己实现:
- 技能是在 Client 触发还是 Server?
- 如何防作弊?
- 如何保证表现流畅?
👉 这是你简历里的重点(GAS + 网络)
7️⃣ 命中判定(Hit Detection)
- 是客户端判定还是服务端判定?
- 延迟情况下怎么保证公平?
👉 能说到:
- Server Rewind / Lag Compensation → 加分
第四组:带宽与优化(中高级)
8️⃣ 网络性能优化
如果有 100 个玩家:
- 会有哪些瓶颈?
- 怎么减少带宽?
👉 至少要提到:
- NetCullDistance
- relevancy
- dormancy
9️⃣ 属性同步优化
- 所有变量都 Replicate 吗?
- 如何减少同步频率?
第五组:DS(Dedicated Server)
🔟 DS 架构理解
- DS 和 Listen Server 区别?
- 为什么生产环境用 DS?
- DS 不需要哪些东西?(很关键)
11️⃣ 无头服务器优化
- DS 上怎么做性能优化?
- 是否需要动画 / 渲染?
第六组:进阶(拉开差距)
12️⃣ 网络架构设计题
给你一个需求:
👉 设计一个“多人技能战斗系统”
你要考虑:
- 技能释放流程
- 同步策略
- 延迟处理
- 防作弊
回答方式建议
👉 从第1题开始(UE网络模型)
我会:
- 按一线面试强度追问
- 指出你答案的问题
- 帮你修成“能过面试”的版本
提醒你一个现实情况
如果你目标是一线厂:
- 只会 RPC + Replication → ❌ 不够
- 能讲移动预测 → ✔ 中级
- 能讲技能同步 + 延迟处理 → ✔✔ 中高级
- 能讲 Lag Compensation → ⭐ 强候选
QA4
- UE4网络同步,UE的角色几种权限,说一下属性同步,RPC,以及他们的优劣
A:权威服务器,myself 自主代理, otherPlayer 模拟代理。
属性同步自动将Actor的属性更新到客户端,RPC 显式调用
- 在服务器生成了一个actor,actor有一个属性x,都开启了网络同步,现在由于客户端性能原因,延迟生成了actor,请问在客户端生成actor前服务器修改了x的值,这个属性可以同步吗?
A:可以同步。客户端最终生成的Actor,其属性x的值将是服务器在“初始复制”时刻的当前值。如果服务器在客户端建立网络通道、执行首次复制之前修改了x,那么客户端收到的就是修改后的值。
QA5
我为你准备了一份针对初级UE系统开发(Lua/DS网络)的面试题清单,涵盖基础概念和常见应用场景,希望能帮助你系统性地准备。
一、 Lua 基础与在UE中的应用
基础语法:Lua中
pairs和ipairs遍历一个表有什么区别?请举例说明。UE集成:在UE项目中,通常如何使用Lua?你了解
UnLua或SLUA这类绑定方案的基本原理吗?面向对象:Lua本身没有内置的类系统,你如何用Lua的元表(
metatable)模拟实现面向对象的继承?
二、 DS(Dedicated Server,专用服务器)与网络同步
- 权威性概念:解释一下客户端权威和服务器权威的区别。在UE的DS架构中,为什么通常要坚持服务器权威?
- RPC(远程过程调用):UE中的
RPC_Server、RPC_Client和RPC_NetMulticast分别用在什么场景?调用它们时有哪些注意事项? - 属性同步:UE中
Replicated属性和RepNotify(复制通知)是如何工作的?请描述一个使用RepNotify的简单例子。
三、 UE Gameplay 框架与系统设计
- 框架理解:简述
Actor、Pawn、Character和PlayerController之间的关系与区别。 - 蓝图与代码:你如何平衡使用蓝图和C++/Lua进行开发?在什么情况下你会倾向于将逻辑写在脚本里而不是蓝图里?
- 性能与优化:如果一个游戏场景中突然出现大量Actor,可能导致性能问题,你会从哪些方面入手排查和优化?(提示:可考虑渲染、Tick、网络复制等方面)
四、 综合与实践
- 问题解决:假设你在开发一个多人射击游戏,发现某个玩家的客户端显示其他玩家的位置有轻微延迟和抖动。你会如何一步步分析和定位这个问题?
给你的准备建议:回答时尽量结合你过去项目中的实际经历。对于概念性问题,清晰准确地定义是关键;对于场景题,展示你的排查思路和分析逻辑比直接给出一个“正确”答案更重要。祝你面试顺利!
QA6
unlua: unlua绑定主要是依赖反射系统,无需解析c++,动静态反射,动态 processEvent 去分支执行蓝图交互的u函数,此时原数据由反射得来uclass,同时对于luagc和uegc双端管理生命周期,对于性能敏感则使用静态导出,平时主要也是动态绑定。
luagc:对于lua的gc来说一个增量式的三色标记清除法,分为黑白灰三色。对于gc白 无gc访问,灰 已gc访问 但没检查引用 黑 全检查完毕。
从根集合出发,逐步把灰色对象引用的对象变灰,自身变黑,最终白色对象被回收。
相比 UE GC,它能自动处理循环引用,但因为 Lua 和 UE 各有一套 GC,UnLua 里要特别注意用弱表避免跨语言循环引用。
lua闭包:Lua 的闭包是函数加上它可以访问的外部局部变量(Upvalue)。即使外部函数返回,这些变量仍然存活,闭包可以继续访问和修改它们。
我在 UnLua 中主要用闭包做 UI 回调、事件监听和协程逻辑,但要注意闭包会延长 Upvalue 的生命周期,可能导致内存泄漏。
userdata:userdata 是 Lua 用来持有 C/C++ 对象的核心机制,它是一块由 Lua GC 管理但内容不透明的内存。
在 UnLua 中,我们用 full userdata 包装 UObject 指针,通过元表暴露反射接口,让 Lua 能安全调用 UE 对象。
为了避免内存泄漏,我们通常配合弱引用或 TWeakObjectPtr 使用,而不是让 Lua 强持有 UObject。
table:Lua 的 table 是数组 + 哈希的混合结构,所有值都用 TValue 表示。
TValue 是一个带类型标签的联合体,可以存数字、布尔、GC 对象等。
整数键优先放在数组部分,非整数或越界整数放在哈希部分。
插入新 key 可能触发 rehash,所以在大表场景中我会提前预分配,避免性能抖动。
反射:对于ue反射,是一个模仿类似与C#的特性的语法糖的处理。对于u对象的子类,会去组织u属性,u函数等,类似特性的语法作为tag标记,并写上具体的meta属性,经过编译器uht的生成 会生成新的h和cpp文件,里面包含属性type,name,等元数据,这些元数据ue会把他们根据模块组织起来,在启动模块时会进行注册到全局反射系统,并利用引用关系链连接起来,也是方便后续gc。
uegc:对于ue的gc 是最基础的一个标记清除算法,第一步,先收集对象,根对象是gc的起点,包括全局对象,当前活跃的actor,还有addToRoot标记的对象。第二步 在合适阶段进行遍历标记所有根对象为活跃,第三部 递归gc堆 消除所有不可达与未被标记对象对象。第四部清除 从BeginDestory 中标记PendingKill 经过收集后,后再次检查引用后最后到达FinishDestory 最后下一帧会进行回收
1.在gc中若要保持对u对象的引用 必须要在有u属性情况下,否则会被回收。
2.gc触发时机要多种,切换场景,达到gc时间间隔,内存压力触发,也可以主动根据接口触发。
sharedptr:引用计数实现,简单来说就是计数为0就会销毁对象。
构造函数=1,拷贝构造++,赋值= –= =++ 0->销毁。
sharedptr本身安全无锁 但是指向对象的读写不是,所以不是线程安全
std::move 左值是具有持久地址、可以取地址的表达式,比如变量名;
右值是临时的、即将销毁的表达式,比如字面量和临时对象。
C++11 引入了右值引用(&&)和移动语义,允许我们“偷走”临时对象的资源,避免不必要的深拷贝。
在 UE 中,TUniquePtr、FString、TArray 都大量使用移动构造来提升性能。
虚函数:虚函数是 C++ 实现运行时多态的机制,通过 virtual 关键字声明,允许派生类重写基类行为。
底层通过虚函数表(vtable)和 vptr 实现,在运行时根据对象真实类型调用对应函数。
RPC和属性同步的区别,属性回调理论上一定会执行,而RPC函数有可能由于错过执行时机而不再会执行。
例如:我在服务器上面有一个宝箱,第一个玩家过去后,宝箱会自动开启。如果使用RPC函数,当第一个玩家过去后,箱子执行多播RPC函数触发开箱子操作。但是由于其他的玩家离这个箱子很远,所有这个箱子没有同步给其他玩家,其他玩家收不到这个RPC消息。
当这些玩家之后再过去之后,会发现箱子还是关闭的。如果采用属性回调,但第一个玩家过去后,设置箱子的属性bOpen为true,然后同步到所有客户端,通过属性回调执行开箱子操作。
这时候其他玩家靠近箱子时,箱子会同步到靠近的玩家,然后玩家在客户端上会收到属性bOpen,同时执行属性回调,这时候可以实现所有靠近的玩家都会发现箱子已经被别人开过了。

