最近有位同学面试Unity,面试的公司采用Lua的方案来做公司项目,我们把面试时问道的真题列举出来,并配上参考回复。
1、Lua热更文件时,文件是重写的,还是只写一部分?
热更分为资源更新和代码更新,资源更新的颗粒度是基于ab包的,是基于一个个资源包来进行下载和替换。做代码热更新的时候,如果热更代码被打入了ab包,那么下载的时候,也是整个代码所在的ab包一起下载。如果热更代码是单独部署的,我们就可以基于对应的文件颗粒度来下载替换。一般做lua热更新的时候,代码打成ab包后,可能只有几百k,并不很大,那么我们打一个ab包就可以了。如果lua代码打包成ab包后很大,我们可以考虑把lua代码分成几个ab包,这样下次热更的时候,就是基于lua代码所在的ab包来热更。对于其它热更技术也类似。热更代码是打一个ab包,还是打多个ab包,完全取决于代码ab包的大小;
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!
2: lua是怎么热更的?
step1:lua做热更时,通过版本对比,md5文件差异比较,把更新的lua代码所在的ab包下载下来;
step2: 当最新代码下载下来以后,我们首先去下载目录下加载lua代码所在的ab包,如果没有,就到本地StreammingAssets目录下加载,如果没有,就报错。
step3: Lua 虚拟机添加 customloader, 当有require来加载lua代码的时候,我们就从来到 customloader的函数,这个函数从Lua代码所在的ab包里面,根据
lua文件路径,把文本资源读出出来,并装载到lua虚拟机里面执行。
由于每次都是优先从下载目录下加载lua, ab包,所以热更的时候,能加载执行到最新代码。
3:Lua语言中 require的顺序是怎样的
step1:这个是require的语法,首先是lua虚拟机从文件中读取lua代码,
step2: 把lua代码装在进lua虚拟机;
step3: 执行lua代码里面的代码指令和函数调用;
step4: 如果有return, 返回结果;
step5: 如果重复require, 就只会执行里面的函数调用与代码指令,不会反复的装载;
4、说说lua的传值与传引用
lua分成基本的数据类型和引用对象数据类型:
字符串,表,数组,属于引用类型,变量保存的是它对象的引用,我们通过引用访问它;
数字,bool值等基本数据类型,变量直接存储他们的数据;
对于基本数据类型而言,赋值语句就是数据copy;
对于引用数据类型而言,赋值语句,就是让这两个变量指向同一个内存对象;
5: 垃圾回收机制(C# Lua)
Lua虚拟机内置了自己的垃圾回收机制和接口,我们在封装lua虚拟机的时候,需要在特定的时候,来调用,Lua的gc接口来回收相关的垃圾,一般我们会在Lua虚拟机封装的时候,在c# 的update里面,设定一些lua垃圾回收的触发条件,比如,每隔100ms调用一次gc, 回收一次等,具体的策略,可以根据实际情况来定。同时lua可以允许开发者自己在特定的时机来调用垃圾回收。
7、垃圾回收造成卡顿,怎么办
当某个时候,有大量的垃圾需要回收的时候,会由于gc所造成卡顿。这个时候,我们能做的就是回收一部分,另外的部分后面去回收,将gc回收的时机,不断地延后,平均到某个update里面,使得过度地时候帧率更加地平滑。这个时候我们需要留意在GC高峰期,来做一些事情,比如,场景地图切换地时候,这个时候容易引发gc高峰,时刻监测,如果发现切换高峰地时候GC造成的卡顿,我们就可以按照上面的思路来处理,主要是减少每次GC的量,延迟GC到后面的update,避免波峰的冲击。
8:说说你们项目中的战斗系统的架构与设计:
做战斗系统和架构的时候,我们一般把代码逻辑分成3层来设计,同时把数据独立出来,我们的项目设计如下,不同公司可能不一样,我们之前公司是这样做的:
1: 我们会把战斗中的功能,做成组件,比如,动画切换,伤害计算等; 我们叫做功能层;
2: 我们会把战斗单元做一个组件,比如Charactor, 然后让Charactor来has 功能组件,并在Charactor中提供标准的通用的策略,比如,行走,技能释放等; 同时不是的角色,我们会编写Player, Enemy等来继承自Charactor,并绑定对应角色的战斗数据,用战斗数据来驱动统一的逻辑;
3: 操作层:我们会把战斗中的操作独立出来,比如UI操作,网络事件,AI事件等,通过事件模块,来调用到战斗中的具体策略,这样,可以实现不同操作层来驱动战斗,调用战斗策略;
4: 战斗中的数据,我们一般都用excel表格来给策划填写,更具策划的游戏需求来制定好对应的数据格式。如果有必要,还可以做一些可视化工具(技能编辑器),来给策划使用,最后导出战斗数据。
5: 技能编辑器:可视化的制定技能的一些数据,比如buff时间,攻击时间,等具体要根据游戏需求来定;
9: 说说项目中网络同步,延迟问题 如何解决的?
网络同步 延迟问题 是做网络游戏开发中比较经典的问题,要考虑这个问题,我们首先要搞清楚,我们的游戏同步采用的是帧同步还是状态同步。
如果游戏是状态同步,那么要解决网络延时问题,只能通过传输来解决,一般用可靠的UDP来做,比如kcp等。减少网络延时,和网络波对对游戏的体验。由于状态同步是服务端跑逻辑,客户端根据状态来展示,所以除了底层通过可靠UDP来减少网络延时以外,没有其它的办法。
如果是帧同步,每一帧,服务端会把所有客户端的操作转发出去,这个时候要解决网络延时问题,也是用UDP来代替传统的TCP,来做数据通讯,如果某个数据包卡住的情况下,客户端,可以用上一帧的操作,延长几帧的处理时间,做所谓的"预演",如果下一帧来的操作,刚好和上一帧一样,那么预演成功,客户端感觉不出来卡顿,不成功,客户端会卡顿or鬼畜。
10: 帧同步要注意哪些点?
铲屎官,你好,关于帧同步要注意哪些点,我这边总结如下:
1: 首先要注意点就是什么样的游戏,能采用帧同步。
a: 同一局游戏,对战的玩家的数目是有限的,一般小于 < 50人左右,比如MMORPG,这种就不适合帧同步;
b: 如果一局游戏,很长时间无法结束,那么不能使用帧同步,比如MMORPG这种一直可以玩没有结束的游戏这种不适合帧同步;
2: 接下来帧同步要解决的问题就是通讯选择,目前主流的做法是TCP/UPD/可靠UDP(如kcp等),帧同步有用TCP, 有用UDP,也有用可靠UDP的,具体可以根据团队的技术能力,技术积累,游戏的发布平台等综合考虑。比如,H5,我们大概率会采用TCP作为帧同步。如果是做手机游戏,可以考虑用UDP,kcp等,有些运营的平台不允许用UDP,只能用TCP,所以在做项目之前要综合考虑好。UDP确实有更好的体验,但是TCP,部署安全等,会更方便。
3: 帧同步服务端的广播频率的选择,15~20FPS左右,一般常见的事件广播频率。
4: 帧同步确定性的选择,包括定点数,随机数,根据自己的游戏类型,提前确定好所需要做确定性的代码库,比如确定性无力引擎,确定性的RVO等。
最后可能不同的项目还会有具体要注意的点,这个需要具体项目具体分析。