问题1: 你们公司项目时如何做战斗系统的?
面试官你好,做战斗系统和架构的时候,我们一般把代码逻辑分成3层来设计,同时把数据独立出来,我们的项目设计如下,不同公司可能不一样,我们之前公司是这样做的:
1: 我们会把战斗中的功能,做成组件,比如,动画切换,伤害计算等; 我们叫做功能层;
2: 我们会把战斗单元做一个组件,比如Charactor, 然后让Charactor来has 功能组件,
并在Charactor中提供标准的通用的策略,比如,行走,技能释放等; 同时不是的角色,我们会编写Player, Enemy等来继承自Charactor,并绑定对应角色的战斗数据,用战斗数据来驱动统一的逻辑;
3: 操作层:我们会把战斗中的操作独立出来,比如UI操作,网络事件,AI事件等,通过事件模块,来调用到战斗中的具体策略,这样,可以实现不同操作层来驱动战斗,调用战斗策略;
4: 战斗中的数据,我们一般都用excel表格来给策划填写,更具策划的游戏需求来制定好对应的数据格式.
如果有必要,还可以做一些可视化工具(技能编辑器),来给策划使用,最后导出战斗数据。
5: 技能编辑器:可视化的制定技能的一些数据,比如buff时间,攻击时间,等具体要根据游戏需求来定;
对惹,这里有一 个游戏开发交流小组 ,希望大家可以点击进来一起交流一下开发经验呀!
问题2: 项目中出现多个spine卡顿怎么办
目前cocos creator 提供spine的动画组件,他有几种模式,
性能最好的是预先Bake模式,就是把每个骨骼在某一帧的位置预先计算出来然后存起来,这样能提升性能;
可以开机spine动画的合批模式,降低Drawcall,但是有限制,每个spine只有一种混合模式,一张贴图才能进行Drawcall合并。
如果多个spine还是卡顿,那么就把spine换成帧动画,提升一些性能。
问题3: 百人同屏如何优化drawcall?
如果是2D游戏,只要保证角色的动画是同一个图集的帧动画(spine动画好像无法合批,待确认)就能最大限度地合批,
同时把角色UI属性地相关内容,和原来的2D角色分开,把UI单独做,然后UI节点和角色节点做位置同步,
这样,角色的动画就可以再一个图集合批,不会被自己的昵称,血条等打断合批。
如果是3D游戏,就要将3D动画的每个顶点的位置,Baker到一个纹理里面,然后使用GPU Instancing合批,来优化掉3D动画组件,从而合批,同样,UI等,都要单独独立开发,这样防止打乱合批。
问题4: 你们项目的场景切换是怎样做的?
目前主流的游戏开发中场景切换做法有3个,不同的公司可能不一样:
1:直接把场景做好,然后内容方场景里面,调用cocos API, 来直接加载与运行对应的场景;
2: 直接把场景做成场景资源,打入ab包中,来调用cocos API,从资源加载中加载场景,然后运行;
3: 直接只用一个场景,通过预制体来做相关的内容展示,不存在场景切换。
具体的选择,可以根据框架与项目来决定。比如,3D游戏中需要场景中做静态光照,我们就可以采用方法2,把场景看作是地图。比如简单的游戏就可以直接使用方法1 or方法3。
建议采用方法2, or 方法3。
方法1最大的问题,是场景无法分ab包,全部都打入到main包里面,这样做分包的时候会有问题;
问题5: 动画的帧率是多少最为合适?
动画的帧率,要看,都可以,主要根据动画的类型来定,可以是15FPS, 30FPS, 60FPS.一般目前骨骼动画这些帧率都是控制在15~30FPS,有些可以是10FPS
具体要根据,帧率,资源大小等,做一个平衡,比如帧动画,帧过多,就会导致内存占用过大,帧过少,动画又不流畅。
问题6: Gpu Instance 怎么用的?
1: 要满足GPU instancing合批的条件,同一个材质,同一个shader,同一个mesh;
2: 渲染的时候,不能被别的物体打乱;
3: 在材质的地方勾选Gpu instancing选项,就可以实现Instancing 合批;
问题7: 你在游戏开发中是如何做内存管理得;
面试官你好,关于使用Cocos Creator开发做内存管理,可能需要注意得点,我是这样看待的:
Cocos Creator开发游戏的内存占用主要是由以下部分组成,
1: 逻辑数据的内存占用,比如,节点,组件实例,字符串对象等;
2: 纹理,模型顶点等显存的内存占用;
3: 就是加载资源,场景切换过程中的一些中间状态的内存占用,比如,解码一个png的图片到内存,可能会要从资源里面把资源数据读到内存中再解码。
对于3的中间状态,最终会被引擎所释放,我们只要关注切换,加载时候的内存峰值,不要让内存峰值引发奔溃就可以了,如果内存峰值很高,这个时候,我们可以考虑
延后加载等。具体还要根据项目来定位。
对于2,我们一般是把不用的资源即时的给他释放掉,这个时候,我们做资源管理的时候,要尽量的把同一个功能场景的资源,打入一个ab包,这样,用的时候整个ab包都用,不用的时候都可以释放。
对于2,我们只要根据内存的峰值情况,再特定的时机,把不用的资源释放掉即可,如果我们的内存可以承受,那么可以不释放。
对于1, TypeScript/JavaScript 一般的都有垃圾回收的机制,我们一般不用考虑释放的问题,直接new 就可以了,但是也要避免大量的反复的new, 比如,在update里面不断地new 一个对象;
这种要尽量地避免。当我们地内存出现峰值地时候,可以主动地启动垃圾回收来进行回收处理。对于大量反复创建地节点,我们可以考虑使用缓存池来处理,这样避免直接像系统反复地new/free。
目前是我对Cocos Creator开发,关于内存要注意地点,可能有遗漏,具体项目还要根据实际情况具体分析。
问题8.你认为怎样的编码才算规范?
编码规范这个不同的项目,不同的公司可能要求不一样,我理解的规范的代码,大概从几个方面讲:
1: 用英文来做好命名,命名要能代表函数or变量or类的功能和作用,命名的习惯可以统一,比如
私有变量用_开头等;
2: 要注意权限,改私有的私有,改公有的公有;
3:命名规范的时候,可以和引擎做适当的一些区分;
4: 把逻辑流程的代码与具体功能代码来分开,流程代码负责流程,功能代码负责具体功能。
5: 写代码要符合项目的真实性,符合大家的习惯性认识,尽量少造概念等。
6:注释的一些要求,如果看具体项目和公司的团队成员的水平与协作来决定注释要写到什么程度
...
具体不同的项目规范不一样,还是可以提前规划好。
如何来做好项目中的性能优化
游戏项目的性能是游戏开发长关注的一些点,关于如何做好游戏项目中的优化,我在实际的管理项目中从以下几个方面来谈。
1: 及时的监测开发版本中的性能问题,如果有,尽早地发现性能问题,是解决性能问题地最好地方式之一,早发现早解决,
能够知道与哪些功能,哪些方式开发相关。很多项目等项目要上线了才开始测试性能,测试兼容性等,这样会给项目上线
造成很大地被动,所以一般我们管理项目研发地时候,越早的引入性能检测,越早能发现问题,并解决。
2: 制定一些常见的开发规范,避免性能问题,
比如,update函数里面,不断地 new 对象,可以考虑在开始地时候把对象数据先new 出来等;
比如,图集的贴图大小,我们是2048x2048的范围内;
一开始就建立好,根据高,中,低机型来做适配的机制,包括核心的Shader等;
提前做好项目预研与技术公关,来最早时间确立立项地可行性。
...
3: 当项目遇到性能问题后,首先我们要定位是哪里出了性能问题,而不是盲目的猜测,对性能和消耗时间与内存等做一个摸排和统计,
尝试定位出来时哪里有问题。如果定位一个项目的性能问题,我们一般先看一些cocos 的性能参数。包括 物理引擎开销,
render 渲染开销, GameLogic游戏逻辑开销等。来初步查看性能热点是出在,渲染,游戏逻辑,物理引擎等方面。来初步定位可能的性能问题。
查看当前的CPU占用率,和系统各进程线程的整体开销情况,方便分析。比如,某个进程突然占用了很多CPU,导致游戏进程的帧率直线下降等。
分析完成后,我们可以来做一些对比实验,来进一步确认问题,比如,要确认是渲染的问题,还是物理引擎的问题,我们可以做一个demo,
场景中拖入等量内容,的场景,不做任何游戏逻辑,来查看渲染和帧率,看是否导致FPS下降,并看以下整体占用多少。如果渲染没有问题,那么就
可以定位到可能是游戏逻辑代码(包括物理引擎)这块导致的。然后进一步定位是哪里的问题。从而一步步的找到准确的问题,最后解决。
4: 项目开发中常见的性能问题:
a: IO卡住了main thread 导致当时的FPS游戏帧率下降,常见的就是将大量的数据在main thread 保存到磁盘等,这种很容易卡住住线程导致帧率下降;
当游戏开发中某个物体要被创建出来的时候,要同步去加载对应的资源,产生的IO,也有可能卡住main thread, 卡一段时间后又恢复,想这种情况,
我们可以考虑 资源提前加载,异步读写文件等方式,不让主线程main thread被卡住,导致FPS下降,玩家体验不好。
b: 物理引擎引发的性能问题
物理引擎经常是游戏性能的瓶颈,一般如果我们定位到是物理引擎迭代发生的问题,采取的方式就是,选择性能更好的碰撞器,配置一些物理引擎的参数,
减少迭代,换物理引擎的内核,选择更高效的引擎,比如,98K的物理引擎等;
c: 具体算法耗时: 在runtime,跑一些具体的算法的时候,可能会耗时,这个时候,可以采用多线程or预先计算结果查表的方式来做空间换时间;
d: 游戏开发中的内存占用过高,导致系统的负担比较重,其它的一些系统线程用来做内存交换,占据了相当一部分的CPU,这个时候就要考虑优化内存占用;
e: 动画引发的性能问题:
2D动画: 骨骼动画的计算量 > 帧动画, 有大规模的骨骼动画的时候, 我们可以考虑合并 骨骼动画的drawcall以及骨骼动画的预先Bake模式;
或者使用帧动画来代替骨骼动画;
3D动画:动画组件每帧都要做顶点采样,所以会消耗CPU,可以考虑先把每帧的每个顶点的位置都保存到一个纹理里面,来代替动画组件,这种长用于大规模的3D物体的渲染,
比如500个小兵等,即节约drawcall,又节约动画采样计算。
f: 垃圾回收导致的FPS下降,
垃圾回收的时候,可能会导致某个时刻的FPS下降,像这种情况,一般会出现在场景切换等过程中,我们要做的就是减少垃圾回收,或者一部分一部分的进行垃圾回收;
或者使用缓存池等,反复的使用之前创建的内存对象,避免垃圾回收;
g: 渲染导致的性能问题;
(1)阴影,光照计算等渲染效果导致的性能问题,可以根据机器的不通的性能等级来做好开关;
根据机器的不同的等级,来做好Shader LOD的切换,比如底端机器用最简单的Shader,高端机器,用复杂的Shader;
使用阴影贴图来代替阴影实时计算等,具体就不展开叙述;
(2) 注意一些Drawcall优化,与set passcall 的相关,尽量能核批,同时避免 set pass call的产生;
Drawcall优化,包含3D 与2D,3D主要是采用,静态,动态,Instancing合批,2D主要是靠图集与场景渲染顺序,Label会打乱2D的drawcall,
当我们做一些任务滚动列表的时候,可以将文字与图片做两个不同的content,让图片和文字分开,来节约drawcall; 具体就不展开叙述;
setpasscall, 尽量让游戏场景中的大部分服务,选择使用同一个shader,如果有些特效的,比如描边的角色,我们尽量把描边和非描边的统一以下,用同一个Shader
来节约 set pass call; 具体就不展开叙述;
(3) 根据机器的 高中低配置,来区分与开关渲染效果;
(4) 优化模型的面数等相关:优化渲染,减少渲染的三角形的规模是优化的最有效的手段,
1: 采用模型减面工具,来重新生成模型;
2: 改造遮挡剔除算法,把肯定被挡住的物体,提前隐藏掉,比如 FPS射击游戏里面,房间后面的房间,这些,可以通过隐藏节点,不提交渲染,最大限度地排除要渲染地物体;
... 具体不展开叙述;
h: 时刻监视 update中的代码,避免在update中做反复的new/free, 反复重复的大量计算,尽量让update函数变得简单;
I: 针对不同的机型做整体FPS的适配,高(60FPS), 中(30FPS) 低(15FPS);
j: 如果是平均的慢,也可以考虑基于webAssembly来提升整体程序的性能;
可能还有一些具体的问题,这边就不过多的展开叙述,具体问题再进一步的讨论。
面试题1: 2D游戏多人在线游戏,一般采用的是状态同步还是帧同步
网络游戏一般分成两种模式,开放世界与房间模式,
比如,开放世界,单幅一个地图,允许几千人在一起游戏,彼此能看到对方;
如传统的RPG游戏。
房间模式,是几个人在一个房间里面进行游戏,比如王者荣耀3v3, 守望先锋 10VS10,腾讯吃鸡等。
状态同步是服务端跑游戏逻辑,状态改变了同步给客户端,客户端再进行操作与播放动画,
所有的逻辑都是在服务端处理。
帧同步,服务端每个逻辑帧,将所有玩家的操作同步给房间里面的每个人。然后客户端像单机游戏一样,
操作来自服务端,业务逻辑计算,都在客户端由服务端的逻辑帧推动。
状态同步,开放世界与房间模式都可以,比如RPG,腾讯的吃鸡,就采用状态同步。
帧同步,只能用于房间模式的游戏,比如王者荣耀。同时帧同步不能用于一局时间太长的游戏中。
比如,一局游戏有3小时,这样使用帧同步就不合适。
帧同步的实时性比较好,所以对操作要求搞得一些游戏,可以采用帧同步,比如Moba。
帧同步不能用在RPG等大型多人在线上,比如(单服3000人)主要是:
帧同步的客户端,要每帧同步每个客户端,所以3000,客户端性能带不上;
RPG游戏没有结束时间,所以用帧同步也不合适。
状态同步处理多人同时在线时,采用AOI技术,实际每个客户端只要处理失业内的,一般只有几十个。
总结一下:
对于2D游戏来说,如果是房间模式,对操作要求比较高,同时每一局时间不长的游戏,我们可以采用帧同步。
否者我们采用状态同步。
面试题2: 一张2D主城和副本地图,一般是多大
游戏地图多大,主要是根据游戏玩法设计来,本质上是由策划决定的。
从技术的角度来说,地图可以任意大。
如果地图太大,导致我们不好处理,我们就可以基于分块来进行处理。
从技术上来说,这些都是由解决方案。
如果地图大,寻路有瓶颈,我们寻路也可以分块。
所以根据项目的需求来确定就可以了。
面试题3: 一个主城大概同时容纳多少人,会影响性能
对于上线运营来说,我们要根据需求,进行部署,一旦服务器的机器确认,
部署上去了以后,我们都会设计一个极限值,比如单服5000人。
超过这个,我们就要把流量导入到其他服务器上。
当我们有10W人同时在线的时候,我们部署20个主城逻辑实例,就可以吃掉10W人。
理论上来说,同时在线人数,没有上线,根据负载,分配到不同的逻辑服实例就可以了。
单服的性能,是由游戏类型,机器参数等决定的。我们根据运营计划选择合适的机器参数,
得到对应的单服性能极限,然后 导入 <= 这个极限的人流,就可以不出运营事故了。
面试题4: 下副本组队的情况下,如何与其他频道的匹配
对于组队来说,就是根据条件筛选出玩家,当玩家进入游戏地图or副本的时候,将两个玩家导入到一个地图上就可以了。
拿地图副本来说,假设玩家A,玩家B 组队开启地图副本,
那么我们就创建一个组队列表,把A与B,放到组队列表里面,然后创建一个房间副本,将组队列表里面的所有玩家都导入这个房间,
这样,A与B,就在一起打一个副本了。
面试5: 剧情系统一般如何开发
不同的项目,剧情是不一样的,我们根据需求来选择合适的数据结构。
一般来说,项目剧情由两种模式,一种是线性模式,一种是选择模式。
线性模式比较简单,一个剧情到下一个剧情,线性的排布好就可以了。
而有些剧情,是根据玩家选择,来推动的,可能不同的选择就由不同的剧情,
这个是典型的数据结构:
剧情1===》子剧情1
===》 子剧情2
===》 子剧情3;
这样就形成了一个剧情树。每个剧情节点包括:
孩子剧情;
选择值映射
本身内容。
父亲剧情节点;
可以根据项目的需求来做一个剧情编辑器,也可以直接手写Json格式等树形结构。
当到剧情根节点时候,当获取玩家选择,根据选择值映射,进入哪个子剧情即可。
面试题6:
不管采用状态同步还是帧同步,场景怪物都是服务器生产嘛
状态同步,是服务器跑游戏逻辑+地图,所以刷怪这些事服务器计算的,然后怪物出来后,服务器通知客户端。
帧同步,服务器只管同步玩家操作,不管游戏逻辑,逻辑都是客户端算的,所以刷怪是客户端刷。客户端什么时候
刷怪,是根据逻辑帧(每秒服务器发客户端20次操作)来推动与决定的,这样保证客户端的一致性。
面试题7:红点系统改如何设计?
面试官你好,这个问题,我是这样来看的,红点系统我把它分为了两个部分,红点显示与红点数据管理。
先说关于红点显示,这个比较简单,主要考虑以下几个方面:
1: 方便有红点需求的地方,调用一个接口就可以把红点展示出来,所以我们会提供一个显示红点的接口,只要调用,就能在特定的位置显示红点;
2: 红点可能会有反复的创建与删除,这里我们根据游戏红点通常的规模,做一个红点节点池即可;
3: 红点的显示有对应的层级,我们会把红点单独的放一个层级,这样避免红点来打乱界面的合批,同时能让红点在一起渲染。
4: 提供一个接口,方便删除某个红点;
接下来说下关于红点的数据管理,
红点数据,不同的界面层级,有不同的红点数据,比如,一级界面的红点可能显示的是,任务,邮件,商城,奖励等。
而二级界面下面可能又有不同,比如奖励,下面就有未领取的奖励需要显示红点,而正式因为有未领取的奖励,所以一级界面"奖励"那里才有红点。
针对这样的特性,我们一般做一个红点树形结构的数据来维护处理。比如一级红点数据【任务,邮件,商城,奖励等】, 二级红点数据 比如,商城里面的
某个类型的某个新上架的商品。我们用树形结构来维护,当孩子有红点时,父亲也会有红点,父亲的父亲也会有红点。当孩子的红点清楚以后,我们还会去
判断父亲的红点是否应该被清除,这样我们就做好了红点提示功能。最后不同的游戏,数据与UI的展示层级不一样,这个可能要具体分析来设计数据结构。
更多教学视频