面经-ue知识
本文最后更新于:2026年4月27日 凌晨
智能指针
UE 里常见的「类智能指针」各干什么?
| 类型 | 作用(白话) | 典型用途 |
|---|---|---|
TObjectPtr<UXXX> |
参与 UPROPERTY 的强引用,配合增量 GC、写屏障 |
类成员里引用另一个 UObject(替代裸 UObject*,新项目/UE5 规范向) |
TWeakObjectPtr<UXXX> |
弱引用:不延长 UObject 生命;对象没了会变成无效 | 缓存「可能已销毁」的对象、解耦循环引用、回调里判断 IsValid |
TSoftObjectPtr<T> / FSoftObjectPath |
软引用:默认不强制加载;需要时再异步加载 | 资源按需加载、减小内存与启动成本 |
TStrongObjectPtr<T>(非 UObject 成员时常用) |
在非 UObject 或原生代码里强引用住一个 UObject | 临时持有、非反射路径的强引用(需包含头文件并遵守用法) |
TWeakObjectPtr
缓存、回调里「顺便记一下」、打断循环引用(A 强引用 B,B 用弱引用指回 A)。
1 | |
TObject和SoftObject的区别?垃圾回收有什么区别这两个
硬引用(Hard Reference)
定义:
直接指针引用,如 UObject、UClass
资源在包含它的对象加载时会被自动加载到内存
1 | |
优点:
使用简单,直接访问
自动管理,无需手动加载
类型安全,编译时检查
缺点:
内存占用:资源会立即加载
加载时间:形成依赖链,导致大量资源一起加载
循环依赖风险:可能导致资源无法卸载
使用场景:
核心资源,必须立即可用
小资源,内存占用可接受
频繁使用的资源
软引用
定义:
只存储资源路径字符串,不立即加载资源
使用 TSoftObjectPtr
、TSoftClassPtr 或 FSoftObjectPath
1 | |
优点:
延迟加载:只在需要时加载
减少内存占用:不立即加载到内存
加快启动速度:避免加载不必要的资源
更好的资源管理:可以控制加载时机
缺点:
需要手动加载:代码更复杂
可能为空:需要检查资源是否加载成功
异步加载:需要处理回调
使用场景:
可选资源:可能不使用的资源
大型资源:纹理、模型等
按需加载:根据游戏状态动态加载
减少启动时间:延迟加载非关键资源
GC区别
硬引用:阻止 GC,对象会一直保留在内存中
软引用:不阻止 GC,对象可以被回收,需要时重新加载
弱引用:不阻止 GC,用于避免循环引用
对象销毁后行为
FSoftObjectPtr 在一定时间内仍然可以访问已销毁的对象,直到垃圾回收期间。FWeakObjectPtr 会自动失效(置为空指针),不会访问到已销毁的对象。
UMG和SlateUI的区别?
UMG是蓝图,可以绑脚本
Slateui更底层,就是编辑器那些的ui
手柄
手柄的组合键是什么做的?
动态修改InputSetting里的ActionMapping按下技能组合键时,把原先 ”X键映射Attack” 删掉,新增一条 ”X键映射Skill1”松开技能组合键时,把 ”X键映射Skill1” 删掉,重新加入 ”X键映射Attack”
这样做有个问题,有可能出现时序问题

解决办法:加一道工序,如果正在按下,就松开的时候再替换,绑一个回调

思路就是修饰键
组合键通常需要一个“修饰键”(如 GamepadUseSkill)作为触发条件
按下修饰键时,临时改变其他按键的行为
释放修饰键时,恢复原始映射
这样可以实现:
单独按 y:执行原始功能
按住 x + 按 y:执行组合功能(如技能1)
按住 x + 按其他键:执行对应的组合功能
这是典型的手柄组合键实现方式,类似键盘的 Ctrl/Cmd + 其他键的组合。
enhance输入什么的
增强输入:
https://dev.epicgames.com/documentation/zh-cn/unreal-engine/enhanced-input-in-unreal-engine
IMC Mapping和Action的区别是什么
这是 UE 增强输入(Enhanced Input) 里两个不同层的东西。
Input Action(动作)
含义:逻辑上的「玩家意图」,例如:跳跃、开火、打开背包、确认。
特点
:
- 和具体按键无关,只定义「游戏里要响应什么」。
- 可以带数值类型:布尔、一维轴、二维轴(例如移动向量)。
作用:给玩法 / UI 代码一个稳定接口(监听某个 Action 触发),底层是键盘还是手柄由别处决定。
Input Mapping Context(映射上下文)
含义:一张(或多张)把物理输入映射到 Action 的表,例如:WASD →
IA_Move,空格 →IA_Jump。特点
:
- 可以有多份 IMC(战斗、载具、菜单),用优先级叠在一起,实现「菜单打开时覆盖移动」等。
- 通常按模式整体启用/禁用(切场景、打开界面时换一套映射)。
作用:在不改 Action 含义的前提下,换键位、换手柄布局、做多语言/多平台差异。
一句话对比
| Action | IMC | |
|---|---|---|
| 回答的问题 | 「游戏里要识别哪种行为?」 | 「用哪些键/摇杆去触发这些行为?」 |
| 类比 | API 名 / 事件名 | 快捷键配置表 |
关系:IMC 里引用并绑定 Action;Action 是抽象,IMC 是「硬件 → Action」的配置层。我们项目里一般是:玩法只绑 Action,策划/程序在 IMC 里配键位和上下文切换,这样换键、加手柄映射不用改 C++/Lua 里的逻辑名。
按键响应的顺序是什么?

AActor生命周期
- PostLoad/PostActorCreated - 执行构建 Actor 所需的任何设置。PostLoad 用于序列化 Actor,PostActorCreated 用于生成 Actor。
- AActor::OnConstruction - Actor 的构造函数,蓝图 Actor 在此函数中创建其组件并初始化蓝图变量。
- AActor::PreInitializeComponents - 在对 Actor 的组件调用 InitializeComponent 之前调用
- UActorComponent::InitializeComponent - actor 的 components 数组中的每个组件都会被调用初始化函数(如果该组件的 bWantsInitializeComponent 为 true)。
- AActor::PostInitializeComponents - 在 Actor 的组件初始化完成后调用
- Actor::BeginPlay - 关卡开始时调用
UE 动画系统框架介绍及使用 - TurBo强的文章 - 知乎
IK
Two Bone IK - silvergp的文章 - 知乎
其实很简单,就是想象最后是一个三角形,所以可以这样就知道了三个边的长度(因为ac=at),然后就可以求出角的大小,角的大小就是bat-bac,然后就可以旋转过去,这里用个旋转矩阵就可以了,然后就又可以求出其他的了

动画系统
UE 动画系统框架源码解析 - TurBo强的文章 - 知乎
这个文章还介绍了许多大佬的文章
Motion Mathcing
Motion Matching 中的代码驱动移动和动画驱动移动 - 小木子的文章 - 知乎
GC
增量回收
增量可达性分析
UE使用增量可达性分析对其进行了改进。 现在用户能够将垃圾回收器的可达性分析阶段分散到多帧,并可配置每帧的软时间限制。 引擎通过TObjectPtr属性跟踪可达性迭代之间的UObject引用。 这意味着对暴露了TObjectPtr的UPROPERTY进行任何赋值,都会在垃圾回收进行时立即将对象标记为可达。 这也被称为垃圾回收器写屏障。
引擎已转换为在将UObject暴露给垃圾回收器的所有地方使用TObjectPtr而不是原始C++指针,包括所有UObject或FGCObject AddReferencedObjects函数。 要在使用虚幻引擎编译的项目中使用增量可达性分析,必须将所有UPROPERTY实例转换为使用TObjectPtr而不是原始C++,否则垃圾回收可能过早回收一些UObject的内存。 我们目前初步将此功能发布为试验性的功能,因为可达性分析阶段仍有可能超出指定的时间限制。
传统做法:GC 的可达性分析(Mark)在一帧里尽量做完,引用图一大就容易卡顿。
增量可达性分析:把 Mark 拆到多帧里做,每帧只干一小段时间(软时间上限,可配)。这样单帧压力小,但会带来新问题:
- 第 1 帧扫到一半时,第 2 帧里你又给某个
UPROPERTY赋了新 UObject; - 若 GC 看不到这次赋值,可能误以为新指向的对象不可达 → 误删(过早回收)。
所以引擎要一种机制:赋值一旦发生,就立刻让 GC「知道」这个对象至少暂时是可达的。这就是文档里的 写屏障(Write Barrier) 和 TObjectPtr 的配合。
GC优化方法?
这篇有优化相关的介绍
通常GC会引起问题都是在LevelStreaming的时候,不过如果你在代码中申请了大规模的UObject,在不再使用的时候也不删除。或者频繁而无意义的调用ForceGC,自然也可能会造成性能问题。
为了避免LevelStreaming造成的GC瞬间成本,可以通过缩小细分关卡的规模来进行。
这样的话在进行角色的移动时,就可以形成小规模的载入和移除,而不是一次性的大规模变更。
设置这个可以减少遍历成本

Cluster
UE机关同步,上下线怎么同步?
比如一个门打开了, 再上线怎么直接是打开?
常见实现方式(任选或组合)
| 方式 | 适用 |
|---|---|
| 动画跳到最后一帧 | 序列帧 / 关卡 Sequence:SetPosition(1.f)、JumpToEnd()、或 AnimMontage SetPosition(Length)。 |
| 直接改 Transform | 门就是旋转/位移:算出「开」的 RelativeRotation/Location,Set 过去,不播 Timeline。 |
| 两个状态机节点 | 动画蓝图里「Opened」是独立 Pose,直接 SetBool bOpened 为 true,不经过过渡。 |
| Static Mesh 换姿态 | 简单门:关/开两套 Mesh 或一个 Mesh 直接设最终矩阵。 |
RepNotify / OnRep 里怎么写(避免再播一次
1 | |
lua
怎么做一个eventmanager?
1 | |
lua元方法
定义(面试口径)
在 Lua 里,元表(metatable) 是一张普通表,用来描述「另一张表在特定操作下该怎么表现」。
元表里以双下划线开头的特殊键,叫做 元方法(metamethod)。当 Lua 对某张表做某种运算或内建操作时,如果发现该表有对应元方法,就会改走元方法,而不是默认行为。
可以一句话记:元方法 = 通过元表给表“重载”语言内置行为的一组钩子。
常见元方法(按用途记)
__index:用t.k或t[k]取值时,t上没有这个键 → 去__index里找(可以是表或函数)。面向对象、继承、读默认值几乎都靠它。__newindex:给t.k赋值且t上原本没有该键时触发;常用来做只读代理、属性校验、懒创建子表。__call:t(...)把表当函数调。- 算术:
__add__sub__mul__div__mod__pow__unm等。 - 比较:
__eq__lt__le(注意~=``、>、>=` 由引擎用这些组合出来,有细节)。 __tostring:tostring(t)。__pairs/__ipairs(Lua 5.2+ 起 ipairs 行为有变化,具体看版本):自定义遍历。__gc:userdata 回收时(Lua 5.2+ 对 table 的__gc支持因版本而异,面试提 userdata 更稳)。
和「用过」怎么对应到项目
在你们这种 EM + UnLua 项目里:
- 日常业务 Lua
大量是Class({ ... })、组件、self:XXX,底层往往是 用元表 +__index(以及可能的__newindex) 做类、继承、Super 调用。你不一定每张表手写setmetatable,但语义上就是在用元方法。 - 自己显式写元表
相对少,但会出现,例如:- 做一层 配置 / 只读代理;
- 缓存 + 懒加载的访问器;
- 极少数 运算符重载(比如向量式数据在纯 Lua 里模拟)。
- 和 UE 的关系
UObject 从 Lua 访问时,字段、函数很多也是通过绑定层和元表机制接到 C++ 上的;面试可以说:脚本侧的“点出来一个 UFunction”背后,和元方法式的分发是同一类思路(具体实现是引擎/插件细节)。
1. __index 是「表」和是「函数」时分别发生什么?
共同点:访问 t.k 时,若 t 自身没有键 k,Lua 会去看 t 的元表里有没有 __index。
1 | |
- 语义:
t.k等价于「若t没有k,就去M里取M.k」。 - 典型用途:原型 / 单继承:实例表很薄,方法都放在
M上,所有实例共享一份方法表,省内存。 - 链式查找:若
M里也没有k,不会自动再对M做__index(那是另一张表的元表的事);要多层继承需要自己设计(例如M的元表再指向父类方法表)。
1 | |
- 每次「实例上没有
k」都会调用f,你可以在函数里写任意逻辑:多级查找、getter、缓存、按k拼路径懒加载等。 - 代价:每次未命中都要进一次 Lua 函数,比表查找慢。
项目语境(UnLua)
类体系里常见的是「方法表 + __index 指向方法表或带查找逻辑的函数」; UObject 上点成员时,绑定层也可能在「查不到」时走 C++ 侧解析,思路和「函数式 __index」类似:灵活但比纯表字段贵。
2. 性能直觉(面试够用)
- 热路径(每帧、列表滚动里大量访问):尽量让数据直接挂在对象上,或让
__index指向一张固定的父表,避免函数式__index里再做大字符串拼接或表创建。 - 函数式
__index:适合不频繁的键、或需要动态规则的地方;可配合结果写回实例(见下)摊销成本。 __newindex:每次给「原本没有的键」赋值都可能触发,滥用会做大量额外调用;属性系统要小心。
3. rawget(t, k) / rawset(t, k, v) 和元表的关系
rawget:只读t自身的槽位,完全忽略__index。用来打破递归(例如在__index函数里查实例字段)、或避免触发 getter。rawset:只写t自身,忽略__newindex。用来避免赋值被拦截、或同样在元方法里避免死循环。
常见坑:在 __newindex 里对同一 t 做普通赋值想「绕过」,若逻辑不对仍会再进 __newindex;这时往往要用 rawset(t, k, v) 真正把值落到实例上。
一个小模式(缓存 + 函数 __index)
第一次用 __index 算出一个值后 rawset(t, k, value),以后访问就走实例自身,等价于把动态查找变成一次性成本(要注意是否允许后续失效,若配置会变要配套清理)。
深拷贝怎么写?
1 | |
visited版本,防止循环引用
1 | |
UProperty
用过。在我们 EM 工程 C++ 里很常见,和 编辑器细节面板、蓝图、反射、GC、网络复制 都绑在一起;脚本侧 UnLua 能直接 self.SomeProp,背后也依赖这些成员被反射暴露出来(该用 UPROPERTY / UFUNCTION 的地方要对上)。
定义(面试怎么说)
UPROPERTY 是 UnrealHeaderTool(UHT) 识别的宏,给 UObject 派生类里的 C++ 成员变量打上一组 元数据,让引擎做几件事:
- 注册到反射系统:生成
FProperty/FField,名字、类型、容器、嵌套结构都能被 序列化、编辑器、蓝图、详情面板 查询。 - 垃圾回收(GC):对
UObject*、TSubclassOf、FSoftObjectPath等 引用关系 参与 GC 扫描;没标UPROPERTY的裸UObject*可能被误回收(经典坑)。 - 可选能力:复制(
Replicated)、保存到关卡/配置(SaveGame)、编辑器可编辑(EditAnywhere)、蓝图读写(BlueprintReadWrite)等,都由 Specifiers 组合决定。
没有 UPROPERTY 的普通 C++ 变量,对 UObject 体系来说通常是 “引擎看不见的字段”。
常见 Specifiers(按场景记)
| 方向 | 例子 | 作用 |
|---|---|---|
| 编辑器 | EditAnywhere / VisibleAnywhere |
是否在细节面板可改 / 只读 |
| 蓝图 | BlueprintReadOnly / BlueprintReadWrite |
蓝图图里能否读/写 |
| 生命周期 | Transient |
默认不序列化到磁盘(运行时缓存常用) |
| 网络 | Replicated + DOREPLIFETIME |
属性复制 |
| 容器 | TArray / TMap + UPROPERTY |
同样参与反射与 GC |
具体组合以你们引擎版本文档为准,面试里强调 “Specifiers 决定可见性与是否进存档/复制” 即可。
和项目相关的例子
例如 Source/EM 里 UIManagerComponent.h 里就有典型写法:VisibleAnywhere 给编辑器只读展示、EditAnywhere, BlueprintReadWrite, Category="EM" 给可调参数、Transient 标运行时临时引用等——这就是日常 UI / 管理器组件 里 UPROPERTY + Category 组织细节面板 的用法。
易错点(加分项)
UObject*成员:该标就标,避免 GC 回收仍在用的对象。TObjectPtr/ 裸指针:UE5 里推荐用引擎指导的类型;面试可提 追踪生命周期、和 GC 的配合。- 与
UFUNCTION分工:UPROPERTY管 状态字段;行为用UFUNCTION暴露给蓝图/Lua。 - Lua:属性要在反射里可见,Lua 才能稳定访问;纯 C++ 未反射成员脚本侧通常碰不到。
一句话收尾:UPROPERTY = 把 C++ 成员挂进 UObject 反射与 GC 体系,并用 Specifiers 控制编辑器、蓝图、序列化、复制等行为;我们项目在 UI 组件、Manager 等头文件里一直在用。
lua和C++互相调用
下面只谈 原生 Lua 官方 C API 和 C/C++ 互调,不涉及 UnLua。
1. 核心模型:虚拟机 + 栈
嵌入 Lua 时,C++ 侧先 luaL_newstate() 得到 lua_State*。
Lua 和 C 之间传参、返回值,几乎都走 虚拟栈(stack):
- C 压入参数 → 调用 Lua 函数 → 从栈上 取出返回值。
- Lua 调 C 时,运行时会把参数压在栈上,C 函数用 索引(正数从底往上,负数从顶往下)读写栈。
所以「互相调用」= 一方往栈上摆数据,另一方按约定读写栈。
2. C++ 调 Lua
典型步骤:
lua_getglobal(L, "foo"):把全局函数foo压栈。- 依次
lua_push*(lua_pushnumber、lua_pushstring、lua_pushboolean等)压入参数。 lua_pcall(L, nargs, nresults, errfunc)执行;nargs/nresults是参数个数和期望返回值个数。- 用
lua_tonumber/lua_tostring/lua_toboolean等从栈顶取返回值。 - 出错时
lua_pcall返回非 0,错误信息在栈顶,要lua_tostring(L, -1)再lua_pop。
跑文件/字符串:luaL_dofile / luaL_dostring(内部也是 load + pcall)。
3. Lua 调 C++:注册 C 函数
C 侧写一个符合签名的函数:
typedef int (*lua_CFunction)(lua_State *L);
约定:
- 从栈上
lua_tointeger(L, 1)等读 第 1、2… 个参数(Lua 传的)。 - 把返回值
lua_push*压栈。 return n表示 返回给 Lua 的返回值个数。
用 lua_pushcfunction(L, my_c_fn) 再 lua_setglobal(L, "myfn"),Lua 里就能 myfn(...)。
也可以用 luaL_Reg + luaL_newlib 做成 table 模块(Lua 5.2+ 常用 require 加载 .dll/.so 里的 luaopen_xxx)。
4. 在 Lua 里表示「C++ 对象」:userdata + 元表
Lua 没有指针类型,一般用:
- full userdata:
lua_newuserdata分配一块内存,常用来 嵌入T*或 struct 副本; - light userdata:只传一个 void*,不参与 GC,适合「由 C++ 保证生命周期」的句柄。
再在 userdata 上 setmetatable,__index 里挂 方法表,Lua 里就变成 obj:Method()(语法糖等价 obj.Method(obj))。
销毁、GC 时可用 __gc 元方法(userdata)通知 C++(注意 Lua 版本对 table 的 __gc 支持)。
UnLua怎么通信?
UnLua解析(一)Object绑定lua - 南京周润发的文章 - 知乎
至此,我们就回答了第一个问题:为什么在Lua中调用UE4.UWidgetBlueprintLibrary.Create,可以最终调用到C++的Create函数?,这里我们总结一下回答:
- Lua代码执行到UE4.UWdigetBlueprintLibrary的时候,执行了RegisterClass(“UWdigetBlueprintLibrary”)函数,做了这样几件事: (1) UnLua框架代码在G表里创建了一个名为【“UWdigetBlueprintLibrary”的表】 (2)为这个表定义了【C++类型的__Index元方法】 (3)将这个类型的【FClassDesc】记录到了UnLua的反射信息库中
- Lua代码执行到UE4.UWdigetBlueprintLibrary.Create的时候,执行了【C++类型的__Index元方法】,做了这样几件事: (1)通过【FClassDesc】和函数名“Create”注册Field,组装了【UFunctionDesc】,记录到了UnLua的反射信息库中 (2)在【“UWdigetBlueprintLibrary”的表】创建了key为“Create”,value为【C++函数ClassCallUFunction + 函数反射信息UFunctionDesc指针的闭包】 (3)将【C++函数ClassCallUFunction + 函数反射信息UFunctionDesc指针的闭包】返回给Lua层
- Lua代码执行到UE4.UWidgetBlueprintLibrary.Create(_G.GetCurrentWorld(), prefab, nil)的时候,执行了【C++函数ClassCallUFunction + 函数反射信息UFunctionDesc指针的闭包】,也就是执行了C++函数ClassCallUFunction,做了这样几件事: (1)执行PreCall,根据【UFunctionDesc】和Lua参数,将Lua参数转换成C++参数,再根据【UFunctionDesc】反射信息,将C++参数写入到一个缓存区中 (2)执行 UObject::ProcessEvent(FinalFunction, Params),参数FinalFunction是UFunction,参数Params是前面保存有C++参数的缓存区。ProcessEvent执行时,即调用了真正我们想调用的C++ Create函数,然后把C++返回值放入了Params缓存区中 (3)执行PostCall,从Params缓存区中读出C++返回值,转换成Lua返回值,Push进Lua栈,返回给Lua。
UnLua监听了新UObject被创建出来的事件,回调函数是上图的NotifyUObjectCreated,因此,当C++ Create函数创建出一个新的UserWidget的时候,会调到NotifyUObjectCreated,并把新UObject传入,我们以创建出了HelloWorldUMG为例,这个UserWidget触发了回调,下面我们看看它做了什么事情。
至此,Manager->Bind函数全部执行完毕,而新UObject创建后触发NotifyUObjectCreated调用的内容,其实就是从新UObject中,尝试获取UObject绑定的Lua脚本路径,然后进行Manager->Bind。总结一下Manager->Bind做了哪些事情:
(1)Manager->Bind绑定的是:新创建的UObject + Lua 对象(根据新创建的UObject找到lua路径后创建的) (2)为新UObject 注册(RegisterClass)元表 (3)根据Lua模块,重写新UObject中可被重写的的UFunction的反射信息,注意这里是直接在UFunction上改写 (4)创建Lua对象,并做设元表、设Object等变量、放入全局引用等初始化,并把Lua对象和lightuserdata(UObject指针)的映射放入ObjectMap中,ObjectMap是Lua中的对象 (5)使新UObject被全局持有,并把Lua对象索引和UObject映射放入AttachedObjects中,AttachedObjects是C++中的对象,和Lua中的ObjectMap对象相似
可以知道,当新的UObject实例被创建时,UnLua做了这些准备工作,然后把Lua对象和C++对象的映射保存了起来,C++存在AttachedObjects中,Lua存在ObjectMap中,容易猜到这是在后面的转换做准备。
问题2:C++的Create函数返回的是一个UserWidget对象,而Lua这边用”local UMG”接住的是一个Lua对象,是怎么做到C++这边Return一个UObject,Lua这边接住的是一个Lua Table的呢,这个C++对象和Lua对象之间又有什么关系?
- 在lua CallUE函数执行到 UObject::ProcessEvent(FinalFunction, Params)时,调用了C++Create函数,这时创建了一个新的UObject,触发了NotifyUObjectCreated回调,在这个回调中,根据UObject创建了Lua对象,并将Lua对象和UObject的映射关系保存在了Lua中的ObjectMap中
- 在Lua CallUE函数执行到PostCall的时候,根据Params缓存区的返回值,在ObjectMap中索引到了对应的Lua对象,将这个Lua对象返回给了Lua
以此实现了Lua对象和C++对象之间的转换,Lua对象和C++对象之间的关系:
Lua对象的元表是“UAGame.Utils.HelloWorldUMG”Lua模块,该Lua模块的元表是通过RegisterClass创建出的UObject元表,它里面包含了UObject的反射信息、Class_Index元方法等内容可供与C++交互,同时Lua对象的Object对象存有UObject的二级指针,可通过该Lua对象取到UObject。
问题3:为什么执行“UMG.centerText”,就直接可以对它进行SetText操作了?
3)问题3回答总结:
因为上面Create返回的UMG是一个LuaInstance,之前设置了它的元表,并且在Lua的ObjectMap中将它和相应UObject进行了绑定,调用到centerText时,通过反射和映射关系,找到了对应UObject和属性信息,然后又创建了一次新的Userdata以及对应关系放回给了Lua,最后再用这个Userdata调用SetText,和之前调用Create函数一样,触发元方法,根据FieldName找到UFunction,根据userdata去ObjectMap中找到UObject,然后返回一个包含函数和反射信息的闭包,然后PreCall、UObject::ProcessEvent、PostCall,最后将结果返回给Lua,完成一整套调用。
公司真题随手记录
网易
实现一个队列,要求不重复怎么搞?
listview怎么优化的?
恢复这个任务怎么恢复的?会不会影响场景中的东西?
深蓝
植被随机变稀疏是怎么搞得?
样条曲线实现逻辑
节点怎么跳到任务?
萨罗斯
Ue的game play框架?Ds、基础的类分别有什么用?
C++怎么到lua?lua怎么到C++?
反射机制如果暴露给蓝图的?
自研引擎和ue有啥区别?
TCPheUDP区别?射击游戏一般用哪种?PUBG用了哪种?UE用的哪种?
UDP如何实现握手?几种方式?可靠性如何保证?
永星
ue常用的反射宏有哪些?绑定的时候有没有踩什么坑?
native和一个什么没听清有什么区别
Uboject的生命周期?会遇到什么函数