|
2021年春招总结:2021年Unity客户端春招面试题总结
今年就要毕业了,这是作者最后的参加校招春招了也已经结束,拿到了自己满意的offer。下面是我2022年春招的总结,希望能给后来者有所帮助,共勉。下面所面的公司基本上都是深圳大部分公司和广州的一小部分公司,因为家在深圳,所以只想在深圳长留,然后公司相关的信息就不提供了。
首先,给大家一个建议:秋招很重要!秋招很重要!秋招很重要!秋招的招聘人数会多于春招,难度也是低于春招,建议是直接参与秋招,如果没有想要的Offer再考虑参加春招。
一:
面试官很看重项目经验和Unity的掌握程度,但是可以看得出来最看重的是实习部分的经历,并没有提问基础问题,针对实习项目对于图集打包很喜欢提问,对于项目作品喜欢提问功能上的实现。
1、什么是图集?图集的作用?
2、DrawCall是什么?DrawCall过高会有什么影响?
3、老版的Sprite Packer和新版的Sprite Altas的区别(这里是因为我是使用过了这两个东西,简历里面有提及的)
4、聊了下项目中UI框架的实现思路(也是简历有提及的)
5、Lua如何实现面向对象的三大特性
6、实习经历
7、项目经历
二:
经历了三轮,一轮笔试,一轮主程面,一轮技术总监面,三轮都在一个下午进行。
笔试:题目感觉还行,没有特别难,主要是分为Unity基础(UGUI的注意事项)、语法基础(委托和事件的区别和用法)、数据结构基础(数组、链表、字典的区别和优弱)、熟悉哪些设计模式、对面向对象的特点(封装、继承、多态的看法)和常见的优化手段。
主程面:前端主要问了资源管理模块,特别是对AssetBundle的原理,问到的很细,如何从Bundle加载一份资源到Game里面,需要经过几次或者几个内存区,如何管理AB包,如何安全卸载AB包或者Asset如何解决依赖等,然后又根据回答的内容继续抛出细节的提问,一直细挖到不会为止(感觉上是想看看你理解的深度在哪,自己是不是实际开发中使用了,有没有合理的规划和设计资源管理模块)。然后就是对于渲染方面的,因为我比较弱,就问了一下渲染流水线。最后是在C#和数据结构还有Lua上面问到的多一些,语言方面问到的比较少,如C#、Lua就是考了一下基础语法,数据结构上喜欢问常见的数据结构的底层原理,例如:List的底层原理、Dictionary的底层原理。
技术总监面:感觉可能是对于我做过联网项目很感兴趣,在客户端(前端部分)问到的很少,基本都是在讨论我们项目中的后端怎么处理,然后前端如何去展示(例如聊天模块,如果我想拓展一下,加入系统/组队/公会/好友/或者别的频道,服务端怎么做、传输协议要写什么,内容用什么数据结构合适,然后等等一直聊)。再接着讨论了一下渲染的东西(最大的弱项)。讨论了计算机组成原理、操作系统的一些简单且常见的校招问题,然后又问了一次数据结构List和Dictionary的底层机制,接着是HashMap的底层机制,哈希表问的很深很细特别是对于Dictionary和哈希表之间的区别。讨论到了.net framework对于这两种数据结构的源码实现是怎么做的。
三:
两个面试官一起面:体验感很差,全程感觉面试官很严肃而且不说话,光我一个人在说,也没有给予我很好的互动感和体验感,中间还问了我英语好吗以及一些感觉很说不清道不明的不爽的问题,以后是不会再投了再考虑了,但是HR很好,十分感谢她,办事效率很高,刚刚联系完就开始准备会议面试了。
面试内容主要是针对了两个联网项目进行的提问:
1、HUB血条的优化有实现过吗?
2、使用过哪些性能分析工具?性能主要是在考虑哪方面的因素影响?
3、装修拆箱?事件委托?
4、计算机网络部分
5、UI使用动静分离的原因,为什么这样子做可以防止重刷,重刷是什么机制造成等?
6、UGUI的优化?实现过最复杂的UI面板是什么?简述一下自己项目中实现的UI框架?
7、多线程使用?死锁的机制?
8、数据结构的底层原理?(例如:C#的List它的本质就不是链表,是一个数组,每个数组是一个节点,节点里面有一个Data和一个指向下一个节点的指针。接着又问那么节点类型是什么,是Struct还是Class等等?)
后面的几个就是针对项目经历里面的两个联机游戏发起提问了,某某功能模块是怎么实现的,我是共享的屏幕,所以,基本上就是演示+代码解析+思路的讲解。
四:
主要是两面,第一面是项目主程,第二面是技术总监
一面:
1、XLua如何与C#进行交互?
2、Lua如何与C#进行交互?
3、C#的异步和Unity的协程?
4、常用哪些数据结构?它们一般使用在哪些场景?(例如,stack我自己一般在实现消息弹窗上、queue用于处理消息队列等)
5、问了Lua基础语法,XLua使用情况与熟悉程度?(因为我实习项目使用的是Xlua代码热更方案,面试官所在的项目组使用的代码热更方案也是XLua,所以问了下之前所做的活动啥的,问了Xlua有没有遇过什么坑、或者有遇到过什么困难)
6、生命周期函数?
7、垃圾回收机制?
8、项目经历
二面:
1、Dictionary 底层原理?
2、TCP和UDP的原理?
3、TCP和UDP的区别?
4、TCP和UDP的优缺点?
5、骨骼动画的原理?
6、渲染管线?
7、快速排序算法的原理?
8、Coroutine的原理?
9、Coroutine在哪些场景会被用到?
10、排序算法有哪几种?说一下它们的时间复杂度、简述一下每种排序算法的核心思想?
11、项目经历
五:
1、广度优先和深度优先算法?
2、面试过程思想和面向对象思想,讲一下自己的看法?
3、浅拷贝和深拷贝,使用代码实现某个实例类它的浅拷贝和深拷贝?
4、C#基础?
5、OOP的三大特性?
6、DC的优化手段?
7、const和reonly?
8、点乘和叉乘的原理以及公式?
9、屏幕有两个点连成的一条线,如果想要在Unity里面把它进行一次旋转,怎么做?
11、用过哪些设计模式?
11、一道简单的算法题?
12、项目经历
六:
线上笔试(十五道题目)+面试一条龙
1、2-3道算法题(好像是三道)
2、StringBuilder和String
3、点乘和叉乘的公式
4、下面代码有什么问题?
List<int> list = new List<int>(new int[] { 1, 2, 3, 4, 5 });
foreach (var item in list)
{
Console.WriteLine(item * item);
list.Remove(item);
}
5、垃圾回收机制
6、Lua基础
7、C#基础
8、给定一个功能的需求,讲一下实现的思路(2-3道)
其他的题目就记不起来了。。。。。
七:
一共也是两面,感谢HR小姐姐,上午电话刚刚联系完,下午就面试了,办事效率很高。
一面:
1、项目经历、主要问了项目中一些模块和管理器的实现
2、数据结构基本上除了数、图,其他的都问了,然后特别是对常用的List和Dictionary问的比较深入。
3、线程和进程?
4、OSI七层模型?
5、值类型和引用类型?
6、Struct和Class的区别,分别存放在哪个内存区?
7、对象池,问了重复依赖和循环依赖的话怎么处理?
二面(二面面的时间很长,具体多久我都有点忘记了,但是肯定一小时以上了,面试官人很好,跟聊天一样聊技术):
感觉主要可以分为四个模块:
第一个模块:Unity熟悉程度
主要考察:
1.Animation\Animator
2.协程原理
3.优化工具(我主要就用四个:Profiler、UPR、OverdrawMonitor、ProjectAuditor它们的使用还有主要用于分析什么,每个有什么区别讲了一遍,感觉这部分给我加了很大的分)
4.TileMap、Tile Extra、Tile、Brash等
5.2D游戏里面有四种方法让一个Sprite显示在另一个Sprite前面,然后让我回答哪四种方法。
6.Unity垃圾回收机制
第二个模块:优化手段
1.DC是什么?它的优化?
2.合批的原理,合批有哪些,区别是什么?
3.LOD是什么,优缺点是什么?
4.MipMap是什么,优缺点是什么?
5.OverDraw是什么,过高会有什么影响,怎么优化OverDraw?
6.频繁触发GC会造成什么情况?如何避免频繁的GC?(其实就是问减少GC Alloc分配或者手动管理GC,)
7.Animator的性能缺陷?
8.对一个物体进行显示/隐藏有哪几种方式?说说它们的优缺点?
第三个模块:基础原理
1.Unity的协程和C#的异步
2.C#的多线程
3.状态机的实现思路
4.渲染流水线
5.String源码里面的StringCache的作用
6.String和StringBuilder
第四个模块:联网功能实现与优化
服务端这边其实我是小白,我的主要方向还是客户端方面的,所以面试官在这方面并没有给我设题考问我,而是让我说说遇到的坑和难点,目前存在的问题然后讲讲有没有思路,再然后就是自己用到了什么技术等等,估计是想看看联网项目是不是自己做的吧。最后,很感谢面试官,让我觉得很亲和,没有在我弱点这里刻意为难我刁难我,反而这样子的聊天方式让我感到很舒适。(因为笔者之前,真的被人搞了心态,说了服务端是小白,一直问我弱处,处于阴影中了属于是)。
=============下面就是面试的问题不做归类了,主要是忘记了哪些是哪家的==================
会用哪些设计模式?你是怎么判断当前需求需要用哪些设计模式?
简单讲下网络通信流程?
项目中UI的自适应是怎么做的?
ProtoBuf的基本原理是什么?
Lua中的metatable和table?
table的内存?
lua和C#如何进行交互?
项目中断线重连是如何实现的?
讲下C#跟Lua的异同,Lua里面如何实现OOP的概念?
xlua源码是否看过?大概讲下xlua的启动流程?
请描述游戏动画有哪几种,以及其原理?
UGUI的理解,简单聊聊你对Image和RawImage的理解?
UGUI的重绘顺序是怎样的?
.Net与Mono的关系?
UGUI如何实现裁剪的(Mash和RectMash2D)?
Unity3D的协程和C#线程之间的区别是什么?
对UI进行SetActive这个操作为什么要避免频繁进行,具体做了些什么内容,有什么方法可以代替它?
UI上显示3D模型的方法有哪些,举例聊聊?
讲下你对Tilemap的理解?有什么优缺点?
Unity生命周期?
简单讲下光照烘焙哪些参数会影响烘焙速度?如何解决问题?
射线检测碰撞物的原理是?
简单讲讲你对骨骼动画的理解?
一个物体是如何显示到Scene或者Game屏幕上的?
什么是序列化?
什么是图集?图集为什么可以优化DC?
========================补充=======================
首先感谢评论区的款冬大佬对面试三中“C#的List它的本质就不是链表,是一个数组,每个数组是一个节点,节点里面有一个Data和一个指向下一个节点的指针。接着又问那么节点类型是什么,是Struct还是Class等等?”指出的错误。我也回去看了.net 的源码对于list的实现list.cs (microsoft.com),确实如大佬所说。下面贴出部分源码,进行解析:
// 首先分析一下各个字段:
/* _defaultCapacity
* 自动扩容是以当前数组元素的两倍或InsertRange目标list的元素个数来扩容(哪个大选哪个)。
* 如果有比较确定的大小可以考虑提前设置,因为每次自动扩容需要重新分配数组和copy元素,性能损耗不小。
*/
private const int _defaultCapacity = 4;// 默认的数组长度为4
private T[] _items; // 泛型数组,数据实际存储在这里
[ContractPublicPropertyName(&#34;Count&#34;)]
private int _size; // 当前List的元素,相对于Count,注意与Capacity区分开,两者不等价
/* _version 从字面意思上看是版本号,但它的工作可不是真的就是版本号信息。
* 在遍历时如果发现_version变了立即退出并抛出遍历过程集合被修改异常,
* 比如在foreach里remove或add元素就会导致这个异常。更常见的是出现在多线程时一个线程遍历集合,
* 另一个线程修改集合的时候,每次改变数组,版本号都会加1.
* 简单点总结:通过version来跟踪集合是否发生改变(remove, insert, sort),如果在foreach遍历时发生改变则抛出异常。
*/
private int _version;
[NonSerialized]
private Object _syncRoot;
/* _emptyArray
* 这是个静态只读的空数组,所有没有元素的List<T>都是用这个数组
* 它的用法可以看下面List<T>的无参构造函数的实现
*/
static readonly T[] _emptyArray = new T[0];
public List() {
// 所以如果当List<T>内部没有元素时候,_items与emptyArray是等价
_items = _emptyArray;
}
// 再补充一点关于Capcity和Count的知识
先看源码:
public int Count {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
return _size;
}
}
public int Capacity {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
return _items.Length;
}
set {
if (value < _size) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
}
Contract.EndContractBlock();
if (value != _items.Length) {
if (value > 0) {
T[] newItems = new T[value];
if (_size > 0) {
// 这意味着每次扩容要花费O(n)的时间,若估算问题中元素个数在10~15之间,应在初始化List大小而不用默认大小
// 所以扩容是一件很耗时间的事情,我们尽量在初始化的时候就给定大小最好
Array.Copy(_items, 0, newItems, 0, _size);
}
_items = newItems;
}
else {
_items = _emptyArray;
}
}
}
}
1. Capcity与Count都是属性,只是Count是只读不可改而Capcity可读可改
2. 我们的扩容实际操作是在Capcity set方法中,设置容量大小时List中的数据被复制到新开辟的泛型数组内,复杂度O(n)
3 List的默认容量为4,但是之后在扩容上不是简单的每次都去乘二,其中还有一个int min这个最小值的判断,如下
// Ensures that the capacity of this list is at least the given minimum
// value. If the currect capacity of the list is less than min, the
// capacity is increased to twice the current capacity or to min,
// whichever is larger.
private void EnsureCapacity(int min) {
if (_items.Length < min) {
int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
if (newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
}
希望如果有人发现错误了,可以给我在评论区留言下,我都会看的,也会更新这篇文章,尽量确保知识面上的输出是正确无误的,万分感谢指出错误的朋友,谢谢你。
做个自我总结吧:
em..................害,整个过程有喜有悲,认识到了自己的短板与不足,后续努力学习填补自己的缺陷。给后来者一些建议就是不要小瞧基础,好的地基才能支撑你写出稳定的代码,不要只是停留在编程语言上的学习,要多多深入的了解,可以买一本叫《CLR via C#》通读一遍,可能里面的部分知识点你会记不住或者一辈子都用不上,但是建议你为了面试也应该好好看看。另外如果没有通过自己心仪的公司也不要灰心,面试真的是有一定运气成分存在,也是看眼缘的,希望你们都能努力付出之后能得到回报,收获自己心仪公司的Offer。
最后感谢两位前辈:LeeCarry 、放牛的星星
第一位:LeeCarry (B站、知乎同名),附上两年前的一次对话,那时候的我还在刚刚起步阶段,学习如何使用Unity,与他的这次对话一直没有删,十分感谢LeeCarry的指点,让那时候很迷茫的我有了清晰的方向,希望也能对你们也有所帮助。LeeCarry - 知乎 (zhihu.com)
第二位:放牛的星星(知乎同名),很厉害的大佬,我后来有写文章与博客的念头也是来自这位大佬的教程分享。大佬的Unity入坟系列真的是太干货满满了,太多干货了,算是硬核的入门教程系列(我到现在也还没看完这个系列),而且还自发的创建了学习群,大家里面讨论技术。此外自己还亲自组织活动,例如群友面试,技术分享会,读书会等等活动,一直都在Unity社区里面做出贡献,我也算是幸运者,遇到了大佬,一直无偿的给我解答我的问题,也十分感谢你的教程。
放牛的星星 - 知乎 (zhihu.com)
Unity基础教程系列(新)——Unity引擎入门和C#编程入门 - 知乎 (zhihu.com)
想进微信群的话私信我一下就行。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|