前言

收集ue相关问题。AI辅助。

QA1

actor与uobject的关系 gc 委托有哪些种类 蓝图通信方式 UE有哪些线程 自定义事件与函数的区别 GAS c++的类型转换 静态多态和动态多态 虚继承 右值引用和移动语义 用过哪些脚本语言 大世界流式关卡加载有卡顿怎么解决 同一范围内有大量行为树运行如何优化 游戏内存溢出如何解决

QA2

一、基础概念与引擎架构

  1. Actor与Component的区别是什么?各自的应用场景?

    1. Actor 可以独立存在于世界中有根组件的变换,可以设置位置、旋转、缩放 AActor* Actor = GetWorld()->SpawnActor();
    2. 必须依附于Actor 相对于父组件的相对变换,或相对于Actor的根组件的相对变换
    3. SceneComponent的核心作用 变换层级系统(Transform Hierarchy)
      1. 变换层级系统(Transform Hierarchy)
      2. 插槽系统(Socket System)
      3. 变换空间转换
      4. 变换更新与同步
      5. 总结: 比起Actor 的Transform 有Mesh,Collider,physics
  2. Pawn、Character、Controller分别是什么?它们之间的关系如何?

    1. **Pawn **可操控的实体
    2. Character 角色移动、动画、胶囊体碰撞
    3. Controller 处理输入、AI决策、管理状态
  3. UObject、AActor、UActorComponent的继承关系是怎样的?

    1. UObject:UE中所有对象的基类,提供基础特性如反射、序列化、垃圾回收等。

    2. AActor:继承自UObject,是可以在场景中放置和生成的对象基类。。

    3. UActorComponent:继承自UObject,是附加在Actor上的组件基类。

    4. AActor和UActorComponent是并列关系,都直接继承自UObject,但UActorComponent不是继承自AActor。

    5. UObject的设计基础
      反射:支持运行时类型信息,蓝图、编辑器集成

      GC:自动内存管理,避免内存泄漏

      序列化:支持保存/加载,热重载

      网络:内置网络复制支持

      CDO:类默认对象,支持编辑器配置默认值

    6. ```
      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
      │ └── AGameStateBase

      1
      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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48







## 二、C++与蓝图交互

1. **蓝图与C++各自的优缺点是什么?实际开发中如何合理分工?**

1. "在UE开发中,我们采用'C++为骨,蓝图为肉'的策略。C++负责性能敏感的核心系统,如网络同步、物理计算、AI决策和复杂算法。蓝图则用于快速迭代的内容创作,如UI设计、动画状态机、关卡脚本和数据配置。

实际分工上,程序员用C++开发可复用的组件和系统,暴露参数和事件给蓝图。策划和美术用蓝图配置游戏内容,调整参数,制作过场动画。当发现性能瓶颈时,将关键逻辑从蓝图迁移到C++。

这种分工既发挥了蓝图快速原型的优势,又通过C++保证了性能和可维护性,是大型商业项目的标准做法。"

2. **UFUNCTION()中BlueprintCallable、BlueprintPure、BlueprintImplementableEvent、BlueprintNativeEvent的区别?** (备注)

1. | 修饰符 | 中文名 | 执行流引脚 | 副作用 | 蓝图实现 | C++实现 | 常见用途 |
| --------------------------- | ------------------ | ---------- | ------ | -------- | -------- | -------------------- |
| BlueprintCallable | 蓝图可调用函数 | 有 | 允许 | 不可实现 | 必须实现 | 执行操作、修改状态 |
| BlueprintPure | 蓝图纯函数 | 无 | 禁止 | 不可实现 | 必须实现 | 计算、查询、获取值 |
| BlueprintImplementableEvent | 蓝图可实现事件 | 有 | 允许 | 必须实现 | 禁止实现 | 事件回调、可扩展行为 |
| BlueprintNativeEvent | 蓝图可重写原生事件 | 无 | 允许 | 可重写 | 默认实现 | 可扩展的模板方法 |



3. **UE的垃圾回收(GC)机制如何工作?常见内存泄漏原因有哪些?如何防止UObject被自动GC?**

1. ```
// 标记阶段(Mark Phase)
void PerformGarbageCollection() {
// 1. 暂停游戏线程(可增量式GC时部分暂停)
SuspendGameThread();

// 2. 标记根对象
MarkRoots();

// 3. 递归标记可达对象
MarkReachableObjects();

// 4. 清除不可达对象
SweepUnreachableObjects();

// 5. 恢复游戏线程
ResumeGameThread();
}
  1. 委托(Delegate)机制怎么用?单播和多播委托的区别及应用场景?

    1. 需要返回值 → 单播委托

      多个监听者 → 多播委托

      与蓝图交互 → 动态多播委托

      性能敏感 → 单播委托

  2. 蓝图通信的常用方式有哪些?各自适用场景?

三、内存管理与智能指针

  1. UE中常用的智能指针有哪些?TSharedPtr、TUniquePtr、TWeakPtr的区别和使用场景?(备注)

  2. TArray与std::vector有何异同?TMap和TSet的底层原理是什么?

    1. TArray深度集成UE(序列化、网络、蓝图)
  3. UStruct和UClass在内存布局上有何不同?

  4. UE的异步加载使用哪种智能指针存储资源?

四、网络与同步

  1. UE的网络同步原理是什么?常用的同步属性/函数声明方式?(备注)
  2. 如何优化大量Actor的网络同步性能?PushModel是什么?
  3. GAS(Gameplay Ability System)的两种网络策略是什么?区别及性能开销?
  4. FastArray常用接口有哪些?如何提升同步效率?
  5. 动画同步与多播机制如何实现?多播动画是否会在主控端和模拟端各播放一次?

五、渲染与性能优化

  1. 前向渲染与延迟渲染的区别?UE默认使用哪种?
  2. 如何优化UE项目的帧率?常用的性能分析工具有哪些?
  3. LOD(Level of Detail)的原理是什么?在UE中如何应用?
  4. 材质系统的基本原理?PBR(物理基础渲染)是什么?
  5. Nanite和Lumen的核心原理是什么?与UE4相比有哪些革新?

六、物理与碰撞

  1. 如何在UE中实现物体的碰撞检测?常用的碰撞体类型有哪些?
  2. 子弹速度过快导致穿墙的原因是什么?如何解决?
  3. 伤害检测与碰撞判定的流程?墙体遮挡的判定如何优化?

七、动画与行为树

  1. 动画蓝图(Anim Blueprint)与动画蒙太奇(Montage)的区别?
  2. 行为树(Behavior Tree)和黑板(Blackboard)是什么?多个NPC能否复用行为树?如何实现?
  3. 增强型输入系统(Enhanced Input)如何工作?

八、系统设计与场景题

  1. 设计一个回旋镖系统(包括运动轨迹、伤害判定、回收机制)。
  2. 游戏中非常卡顿,只有二三十帧,你如何定位卡顿原因?
  3. 游戏中有很多个Actor导致卡顿,如何进行性能优化?
  4. 对象池(Object Pool)如何实现?在什么场景下使用?
  5. 如果要进行关卡切换,但不想用GameInstance保存数据,可以怎么做?

九、C++底层与算法

  1. C++中的多态性和虚函数机制?在UE中的应用举例。
  2. 智能指针的原理?循环引用如何解决?
  3. 右值引用、完美转发、引用折叠的原理是什么?
  4. SFINAE是什么?模板匹配的优先级?
  5. 长度为n-1的数组,元素为1~n的数字,其中缺了一个数字,如何快速找出来?

十、项目经验与架构设计

  1. 你在项目中用GAS做了什么?请详细说明。
  2. 你实现过什么系统吗?请描述设计思路和难点。
  3. 如果要设计一个生命周期与GameMode一致的子系统,如何实现?
  4. 如何设计一个支持不定数量和类型参数的委托机制?
  5. 大世界场景下GC如何优化?除了簇和新老生代还有哪些方法?

QA3

CPP

GP

第一组:UE核心架构(必问)

1️⃣ Actor 生命周期(高频必杀题)

你讲清楚一个 Actor 从创建到销毁的完整流程:

  • 构造函数什么时候调用?(和Spawn的关系)

A:

  • PostInitProperties / PostInitializeComponents / BeginPlay 区别?

A:

避免在构造函数中进行复杂逻辑,因为此时许多系统可能未初始化

避免在PostInitProperties中访问组件,因为它们还不存在

PostInitializeComponents适合组件间的设置,但不适合开始游戏逻辑

BeginPlay是最安全、最常用的初始化点,特别是对于蓝图项目

  • Tick 是怎么被调度的?

A:执行顺序 →

  1. TG_PrePhysics // 物理计算前
  2. TG_StartPhysics // 开始物理模拟
  3. TG_DuringPhysics // 物理模拟期间(并行)
  4. TG_EndPhysics // 物理模拟结束
  5. TG_PostPhysics // 物理计算后
  6. TG_PostUpdateWork // 后更新工作
  7. TG_LastDemotable // 最后可降级的
  • Destroy 之后会立刻销毁吗?

A:

EndPlay()

调用 Destroy() 的时刻
Actor 被标记为 “待销毁” (PendingKill)
当前帧继续执行(Actor 仍然存在)
下一帧开始前执行实际清理
资源释放和内存回收

  1. 收集所有标记为 PendingKill 的对象
  2. 调用 BeginDestroy() 开始销毁
  3. 检查引用 IsReadyForFinishDestroy()
  4. 调用 FinishDestroy() 完成销毁
  5. 释放内存

👉 面试官想听的是:调用顺序 + 引擎机制,不是函数名罗列


2️⃣ UObject vs Actor(本质区别)

  • UObject 为什么不能直接放到世界里?

A:

UObject

核心功能:反射、序列化、垃圾回收、属性系统
但缺少:位置、旋转、缩放、场景表示

  • Actor 比 UObject 多了什么能力?

A:

  • Actor特有:
    Transfrom,Component,生命周期,world交互,physics,Replicated/RPC,Visible,Tag,Parent,Level,Input

  • UObject基础能力:
    Save,Blueprint,editor

  • Component 为什么必须挂在 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
2
UCLASS()
class AMyActor : public AActor

你用 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

  1. UE4网络同步,UE的角色几种权限,说一下属性同步,RPC,以及他们的优劣

A:权威服务器,myself 自主代理, otherPlayer 模拟代理。

属性同步自动将Actor的属性更新到客户端,RPC 显式调用

  1. 在服务器生成了一个actor,actor有一个属性x,都开启了网络同步,现在由于客户端性能原因,延迟生成了actor,请问在客户端生成actor前服务器修改了x的值,这个属性可以同步吗?

A:可以同步。客户端最终生成的Actor,其属性x的值将是服务器在“初始复制”时刻的当前值。如果服务器在客户端建立网络通道、执行首次复制之前修改了x,那么客户端收到的就是修改后的值。

QA5

我为你准备了一份针对初级UE系统开发(Lua/DS网络)的面试题清单,涵盖基础概念和常见应用场景,希望能帮助你系统性地准备。

一、 Lua 基础与在UE中的应用

  1. 基础语法:Lua中pairsipairs遍历一个表有什么区别?请举例说明。

  2. UE集成:在UE项目中,通常如何使用Lua?你了解UnLuaSLUA这类绑定方案的基本原理吗?

  3. 面向对象:Lua本身没有内置的类系统,你如何用Lua的元表(metatable)模拟实现面向对象的继承?

二、 DS(Dedicated Server,专用服务器)与网络同步

  1. 权威性概念:解释一下客户端权威和服务器权威的区别。在UE的DS架构中,为什么通常要坚持服务器权威?
  2. RPC(远程过程调用):UE中的RPC_ServerRPC_ClientRPC_NetMulticast分别用在什么场景?调用它们时有哪些注意事项?
  3. 属性同步:UE中Replicated属性和RepNotify(复制通知)是如何工作的?请描述一个使用RepNotify的简单例子。

三、 UE Gameplay 框架与系统设计

  1. 框架理解:简述ActorPawnCharacterPlayerController之间的关系与区别。
  2. 蓝图与代码:你如何平衡使用蓝图和C++/Lua进行开发?在什么情况下你会倾向于将逻辑写在脚本里而不是蓝图里?
  3. 性能与优化:如果一个游戏场景中突然出现大量Actor,可能导致性能问题,你会从哪些方面入手排查和优化?(提示:可考虑渲染、Tick、网络复制等方面)

四、 综合与实践

  1. 问题解决:假设你在开发一个多人射击游戏,发现某个玩家的客户端显示其他玩家的位置有轻微延迟和抖动。你会如何一步步分析和定位这个问题?

给你的准备建议:回答时尽量结合你过去项目中的实际经历。对于概念性问题,清晰准确地定义是关键;对于场景题,展示你的排查思路和分析逻辑比直接给出一个“正确”答案更重要。祝你面试顺利!

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,同时执行属性回调,这时候可以实现所有靠近的玩家都会发现箱子已经被别人开过了。