面试Unity面试题&答案
Posted 软泡芙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试Unity面试题&答案相关的知识,希望对你有一定的参考价值。
文章目录
C#
1.结构体和类有何区别?
结构体是一种值类型,而类是引用类型。那么结构体就是当成值来使用的,类则通过引用来对实际数据操作
2.值类型和引用类型有何区别?
1值类型的数据存储在内存的栈中;引用类型的数据存储在内存的堆中,引用类型的变量持有的是数据的引用,
2.值类型存取速度快,引用类型存取速度慢。
3.值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用
4.值类型继承自System.ValueType,引用类型继承自System.Object
5.栈的内存分配是自动释放;而堆在.NET中会有GC来释放
6.值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址,即对象的引用。
3.Heap与Stack有何区别?
1.heap是堆,stack是栈。
2.stack的空间由操作系统自动分配和释放,
heap的空间是手动申请和释放的,heap常用new关键字来分配。
3.stack空间有限,heap的空间是很大的自由区。
4.请简述ArrayList和List的主要区别?
List是接口,ArrayList是一个实现了该接口的类,可以被实例化
ArrayList存在不安全类型(ArrayList会把所有插入其中的数据都当做Object来处理)
装箱拆箱的操作(费时)
5.请简述装箱拆箱
装箱 就是把“值类型”转换成“引用类型”(Object);
拆箱 就是把“引用类型”转换成“值类型”;
6.请简述sealed关键字用在类声明时与函数声明时的作用
sealed修饰的类为密封类,类声明时可防止其他类继承此类,在方法中声明则可防止派生类重写此方法。
7.请简述private,public,protected,internal的区别
public:对任何类和成员都公开,无限制访问
private:仅对该类公开
protected:对该类和其派生类公开
internal:只能在包含该类的程序集中访问该类
8.请描述Interface与抽象类之间的不同
都可以被继承
都不能被实例化
都可以包含方法声明
抽象类是部分抽象,单继承,接口是完全抽象,多继承。
9.ref参数和out参数是什么?有什么区别?
ref引用参数和out输出参数的效果一样,都是通过关键字找到内存地址,
不同点就是输出参数必须对参数进行初始化。
10.C#的委托和事件
委托(delegate)类似于一种安全的指针引用,委托可以把一个方法作为参数代入另一个方法。 委托可以理解为指向一个函数的引用。事件是一种特殊的委托
11.C#中的排序方式有哪些?
选择排序,冒泡排序,快速排序,插入排序,希尔排序,归并排序
12.重载和重写的区别?
重写(overriding):子类的方法覆盖父类的方法,要求返回值、方法名和参数都相同。
方法重载(overloading):重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,
13.概述序列化:
序列化简单理解成把对象转换为容易传输的格式的过程。比如,可以序列化一个对象,然后使用HTTP通过Internet在客户端和服务器端之间传输该对象
14.概述c#中代理和事件?
代理就是用来定义指向方法的引用。
C#事件本质就是对消息的封装,用作对象之间的通信;发送方叫事件发送器,接收方叫事件接收器
15.在类的构造函数前加上static会报什么错?为什么?
构造函数格式为 public+类名,如果加上static会报错(静态构造函数不能有访问修饰符)
原因:静态构造函数不允许访问修饰符,也不接受任何参数;
无论创建多少类型的对象,静态构造函数只执行一次;
运行库创建类实例或者首次访问静态成员之前,运行库调用静态构造函数;
静态构造函数执行先于任何实例级别的构造函数;
显然也就无法使用this和base来调用构造函数。
16.C# String类型比stringBuilder类型的优势是什么?
如果是处理字符串的话,用string中的方法每次都需要创建一个新的字符串对象并且分配新的内存地址,而stringBuilder是在原来的内存里对字符串进行修改,所以在字符串处理方面还是建议用stringBuilder这样比较节约内存。但是string 类的方法和功能仍然还是比stringBuilder类要强。
17、C# 函数Func(string a, string b)用Lambda表达式怎么写?
Func<int,string,string> t=(int x, string b) => (x.ToString() + b);
18、数列1,1,2,3,5,8,13…第n位数是多少?用C#递归算法实现
通项公式应该是an = a(n-1) + a(n-2) 这样就可以做递归了
Unity
1.Unity3D的协程和C#线程之间的区别是什么?
协程:在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行。在每帧结束之后去检测yield的条件是否满足,任一指定时刻只有一个协程在运行,并且这个正在运行的协同程序只在必要时才被挂起。
多线程程序同时运行多个线程 ,除主线程之外的线程无法访问Unity3D的对象、组件、方法,缺点:协同程序并非真线程,协程也失去了标准线程使用多CPU的能力。可能会发生堵塞。
2.动态加载资源的方式?
1.Resources.Load();
2.AssetBundle
通过Resources模块,调用它的load函数:可以直接load并返回某个类型的Object,前提是要把这个资源放在Resource命名的文件夹下,Unity不关有没有场景引用,都会将其全部打入到安装包中。
2.通过bundle的形式:即将资源打成 asset bundle 放在服务器或本地磁盘,然后使用WWW模块get 下来,然后从这个bundle中load某个object。
3.如何安全的在不同工程间地迁移asset数据?三种方法
1.将Assets目录和Library目录一起迁移
2.导出包,export Package
3.用unity自带的assets Server功能
4.Unity提供了几种光源,分别是什么
四种。
平行光:Directional Light
点光源:Point Light
聚光灯:Spot Light
区域光源:Area Light
5.Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期,请列出系统自带的几个重要的方法。
Awake——>OnEnable–>Start——>Update——>FixedUpdate——>LateUpdate——>OnGUI——>OnDisable——>OnDestroy
6.物理更新一般在哪个系统函数里?
FixedUpdate,每固定帧绘制时执行一次,和update不同的是FixedUpdate是渲染帧执行,如果你的渲染效率低下的时候FixedUpdate调用次数就会跟着下降。FixedUpdate比较适用于物理引擎的计算,因为是跟每帧渲染有关。Update就比较适合做控制。
7.如何在不同分辨率下保持UI的一致性
UGUI通过锚点和中心点和分辨率也解决这个问题
8.Unity中,照相机的Clipping Planes的作用是什么?调整Near、Fare两个值时,应该注意什么?
剪裁平面 。从相机到开始渲染和停止渲染之间的距离。
9.请描述游戏动画有哪几种?
主要有关节动画、单一网格模型动画(关键帧动画)、骨骼动画。
关节动画把角色分成若干独立部分,一个部分对应一个网格模型,部分的动画连接成一个整体的动画,角色比较灵活Quake2中使用了这种动画;
单一网络模型动画由一个完整的网格模型构成,在动画序列的关键帧里记录各个顶点的原位置及其改变量,然后插值运算实现动画效果,角色动画较真实。
骨骼动画,广泛应用的动画方式,集成了以上两个方式的优点,骨骼按角色特点组成一定的层次结构,由关节相连,可做相对运动,皮肤作为单一网格蒙在骨骼之外,决定角色的外观。皮肤网格每一个顶点都会受到骨骼的影响,从而实现完美的动画。
10.Unity和Android与iOS如何交互?UnitySendMessage
UnitySendMessage(“Cube111”,“methodName111”,“传给unity。。。”);
参数1:场景中的模型名称,Cube111就是我们定义的一个箱子。
参数2:脚本方法名称methodName111就是上面脚本中的方法,
参数3:为一个char *类型的可以向Unity中传递数据。
11.将图片的TextureType选项分别选为““Texture”和“Sprite”有什么区别
Sprite作为UI精灵使用,Texture作用模型贴图使用。Sprite需要2的整次幂,打包图片省资源
Unity引擎使用的是左手坐标系
12.游戏对象B是游戏对象A的子物体,游戏对象A经过了旋转,请写出游戏B围绕自身的Y轴进行旋转的脚本语句,以及游戏对象B围绕世界坐标的Y轴旋转的脚本语句。
绕世界坐标旋转:transform.Rotate (transform.upspeedTime.deltatime);
绕自身Y轴旋转:transform.Rotate (Vector.upspeedTime.deltatime);
13.为什么u3d会出现组件上数据丢失的情况
一般是组件上绑定的物体对象被删除了。
14.当删除Unity工程Assets目录下地meta文件时会导致什么?为什么?
会导致在场景中游戏对象看不到,或者报错,材质找不到资源。多人协作的时候会导致资源的重复产生。
动画切换(玩家从休息切换到战斗)
如何知道两个物体使用了同一个贴图。
15、在物体发生碰撞的整个过程中,有几个阶段,分别列出对应的函数三个阶段
1.OnCollisionEnter 2.OnCollisionStay 3.OnCollisionExit
16、Unity3d的物理引擎中,有几种施加力的方式,分别描述出来
rigidbody.AddForce/AddForceAtPosition,都在rigidbody系列函数中。
17.alpha blend 工作原理
alpha blend 用于做半透明效果。Color = (源颜色 * 源系数) OP ( 目标颜色* 目标系数);其中OP(混合方式)有加,减,反减,取最小,取最大;
18.写光照计算中的diffuse的计算公式
漫反射光(diffuse)计算公式为:Idiffuse = DintensityDcolorN.L ; (Dintensity表示漫反射强度,Dcolor表示漫反射光颜色,N为该点的法向量,L为光源向量)
其他,3D渲染中,物体表面的光照计算公式为:
I = 环境光(Iambient) + 漫反射光(Idiffuse) + 镜面高光(Ispecular);
其中,环境光(ambient)计算公式为:
Iambient= Aintensity* Acolor; (Aintensity表示环境光强度,Acolor表示环境光颜色)
漫反射光(diffuse)计算公式为:
Idiffuse = DintensityDcolorN.L ; (Dintensity表示漫反射强度,Dcolor表示漫反射光颜色,N为该点的法向量,L为光源向量)
镜面光照(specular)计算公式为:
Ispecular = SintensityScolor(R.V)n; (Sintensity表示镜面光照强度,Scolor表示镜面光颜色,R为光的反射向量,V为观察者向量)
综上所得:整个光照公式为:
I = Aintensity* Acolor+ DintensityDcolorN.L + SintensityScolor(R.V)n ;
将一些值合并,并使用白色作为光照颜色,则上述公式可简化为:
I = A + D*N.L + (R.V)n
19.Vertex Shader是什么?怎么计算?
顶点着色器,怎么计算哦???
20.用u3d实现2d游戏,有几种方式?
1.用本身的GUI
2.把摄像机的Projection调成Orthographic,物体的Z轴不考虑了。
21.u3d中碰撞器和触发器的区别?
碰撞器会有碰撞的效果,IsTrigger = false,可以调用OnCollisionEnter/Stay/Exit函数。 触发器没有碰撞效果,isTrigger = true,可以调用OnTriggerEnter/stay/exit函数
22.物体发生碰撞的必要条件
其中至少一个物体(运动的)必须带有碰撞器(collider)+刚体(Rigidbody)或者CharacterController,另一个物体也必须至少带有collider。
23.CharacterController和Rigidbody的区别
CharacterController自带胶囊碰撞器,里面好像封装了一个刚体
Rigidbody就是刚体,使物体带有物理的特性
24.什么叫做链条关节
Hinge Joint ,他可以模拟两个物体间用一根链条连接在一起的情况,能保持两个物体在一个固定距离内部相互移动而不产生作用力,但是达到固定距离后就会产生拉力。
25.物体自旋转使用的函数叫什么
transform.Rotate
26.物体绕某点旋转使用函数叫什么
transform.RotateAround
27.u3d提供了一个用于保存读取数据的类,(playerPrefs),请列出保存读取整形数据的函数
PlayerPrefs.SetInt(“CoinNum”,100);
28.移动相机动作在哪个函数里,为什么在这个函数里。
LateUpdate,在每帧执行完毕调用,他是在所有update结束后才掉,比较适合用于命令脚本的执行。官网上例子是摄像机的跟随,都是在所有update操作完才跟进摄像机,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。
29.当游戏中需要频繁创建一个物体对象时,我们需要怎么做来节省内存。
动态的创建。需要几个我们就
30.一个场景放置多个camera并同时处于活动状态,会发生什么
游戏界面可以看到很多摄像机的混合。可以用depth(深度),Layer(层)+ Culling Mask,enable = false/true来控制
31.简述prefab的用处和环境
Prefab在实例化的时候用到,主要用于经常会用到的物体,属性方便修改。
32.如何销毁一个UnityEngine.Object以及其子类
Destory
渲染
1.什么是渲染管道?
图形数据在GPU上经过运算处理,最后输出到屏幕的过程
主要步骤有:顶点处理->图元装配->光栅化->像素处理->缓存。
2.LOD是什么,优缺点是什么?
LOD(Level of detail)多层次细节,是最常用的游戏优化技术。它按照模型的位置和重要程度决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
3.MipMap是什么,作用?
MipMapping:在三维计算机图形的贴图渲染中有常用的技术,为加快渲染进度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为MipMap。
4.两种阴影判断的方法、工作原理。
本影和半影
本影:景物表面上那些没有被光源直接照射的区域(全黑的轮廓分明的区域)。
半影:景物表面上那些被某些特定光源直接照射但并非被所有特定光源直接照射的区域(半明半暗区域)
5.有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?
把A组物体的渲染对列大于B物体的渲染队列,通过shader里面的渲染队列来渲染
6.问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?
没有区别,因为不管几张贴图只渲染一次。
框架
1.客户端与服务器交互方式有几种?
socket通常也称作”套接字”,实现服务器和客户端之间的物理连接,并进行数据传输,主要有UDP和TCP两个协议。Socket处于网络协议的传输层。
http协议传输的主要有http协议 和基于http协议的Soap协议(web service),常见的方式是 http 的post 和get 请求,web 服务。
TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
优化
一.如何优化内存?
1.压缩自带类库;
2.对象池,使用预设(Prefab)。
3.释放AssetBundle占用的资源;
4.降低模型的片面数,降低模型的骨骼数量,降低贴图的大小;
5.使用光照贴图,
2.请简述GC(垃圾回收)产生的原因,并描述如何避免?
GC回收堆上的内存
避免:1.减少new产生对象的次数
2.使用公用的对象(静态成员)
3.将String换为StringBuilder
3.什么叫动态合批?跟静态合批有什么区别?
如果动态物体共用着相同的材质,那么Unity会自动对这些物体进行批处理。动态批处理操作是自动完成的,并不需要你进行额外的操作。
区别:动态批处理一切都是自动的,不需要做任何操作,而且物体是可以移动的,但是限制很多。静态批处理:自由度很高,限制很少,缺点可能会占用更多的内存,而且经过静态批处理后的所有物体都不可以再移动了。
4.顶点数和Draw Call数?如何降低Draw Call数?
Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call。DrawCall越高对显卡的消耗就越大。
降低DrawCall的方法:
-
Dynamic Batching(动态批处理)
-
Static Batching(静态批处理)
-
高级特性Shader降级为统一的低级特性的Shader。
5.ITY3d在移动设备上的一些优化资源的方法
1.使用assetbundle,实现资源分离和共享,将内存控制到200m之内,同时也可以实现资源的在线更新
2.顶点数对渲染无论是cpu还是gpu都是压力最大的贡献者,降低顶点数到8万以下,fps稳定到了30帧左右
3.只使用一盏动态光,不是用阴影,不使用光照探头
粒子系统是cpu上的大头
4.剪裁粒子系统
5.合并同时出现的粒子系统
6.自己实现轻量级的粒子系统
animator也是一个效率奇差的地方
7.把不需要跟骨骼动画和动作过渡的地方全部使用animation,控制骨骼数量在30根以下
8.animator出视野不更新
9.删除无意义的animator
10.animator的初始化很耗时(粒子上能不能尽量不用animator)
11.除主角外都不要跟骨骼运动apply root motion
12.绝对禁止掉那些不带刚体带包围盒的物体(static collider )运动
NUGI的代码效率很差,基本上runtime的时候对cpu的贡献和render不相上下
13每帧递归的计算finalalpha改为只有初始化和变动时计算
14去掉法线计算
15不要每帧计算viewsize 和windowsize
16filldrawcall时构建顶点缓存使用array.copy
17.代码剪裁:使用strip level ,使用.net2.0 subset
18.尽量减少smooth group
19.给美术定一个严格的经过科学验证的美术标准,并在U3D里面配以相应的检查工具
来源
[Unity面试] 2021年Unity面试题分享(面试题Lua突破3.8已更新)
【CSND】Unity游戏开发学习群
加入我们一起学习吧:1022366216
备注来源:csdn~~ 阿里嘎多
联系小小老师~可以获取学习游戏开发大礼包!
群内还有更多素材资源领取!!
【重点面试题】代表面试的时候问到的题目
光背答案是没有用的,一定要动手操作一下,才能知道答案为什么是这个。
最新的大厂面试问题,在页面最下面更新了
本文章力求从简单的形式到深入理解原理,再到扩展,丰富知识的层次感,知其所以然。
推荐学习资料
链接1: 游戏编程模式.
链接2: 设计模式.
2021年Unity面试题分享
- 一、C#语言和面向对象OOP(已更新2021.3.8)
- 二、Unity脚本基础(已更新2021.3.8)
- 三、Unity性能优化(必问)(已更新2021.3.8)
- 四、设计模式
- 五、Unity编辑器基础
- 六、数据结构和算法(已更新2021.2.27)
- 六、Lua语言和Xlua热更(已更新2021.3.8)
- 七、实际面试中遇到的问题 (已更新2021.3.8)
一、C#语言和面向对象OOP(已更新2021.3.8)
1、【重点面试题】面向对象的三大特性
封装 :隐藏对象的属性,并实现细节(方法),对外提供接口,
public全局,protected子类,internal同集,隐藏private
同类,public属性器,private字段,对赋值进行限定。
sealed修饰符的子类是不能被继承的。
设计上:分而治之,封装变化、高内聚低耦合
数据上:把一些基本数据复合成一个自定义类型的数据
方法上:隐藏实现细节,向外提供接口
继承:重用现有代码
多态:静态多态重载,动态多态重写。
父类行为由子类具体实现,包含virtual虚方法,abstract抽象方法,interface接口
可以涉及题目虚方法、抽象方法、接口的区别
重载和重写区别
静态重载:返回值无关,与参数个数,类型相关。编译阶段。便于扩展和维护
动态重写override(运行时,改写了方法表的新地址)。
抽象方法的父类必须是抽象类,子类是抽象类可以不重写,抽象类不可以被实例化。
举例子非常重要
基类抽象人物工厂(接口),子类具体玩家工厂,子类怪物工厂,子类npc工厂,抽象产品(接口)具体魔法师,弓箭手产品~
资源管理工厂,UI资源管理工厂,音频资源管理工厂,资源管理,UI资源管理,音频资源
2、【重点面试题】值类型和引用类型区别
值类型:包含了所有简单类型(整数、浮点、bool、char)、struct、enum。
继承自System.ValueTyoe
引用类型包含了string,object,class,interface,delegate,array
继承自System.Object
内存区域上的区别
值类型:数据存储在栈上,超出作用域就自动清理
引用类型:数据存储在托管堆上,引用地址在线程栈上,地址指向数据存放的堆上
托管堆会由GC来自动释放 ,线程栈数据在作用域结束后会被清理。
拷贝策略:值类型是拷贝数据,引用类型是拷贝引用地址
如果值类型为传值参数,传值参数会在栈上新开辟一个副本,原先的值类型数据不会改变
如果引用类型是传值参数,传值参数会创建一个新的引用地址,两个引用地址会指向同一个对象实例的数据,实例数据会随着改变进行改变。(这种行为被称为副作用,一般实际项目不会这么操作,要么return返回参数,要么使用ref或者out修饰符)
【扩展Ref引用参数,Out输出参数可以利用这一副作用机制】
通常来讲 变量的值分配 与其声明该变量的位置有关。 局部变量的值 总是在 栈上的。 实例变量的值则和实例本身一起储存在实例储存的地方。 引用类型实例和静态总是储存在 堆上的。
数组的元素、引用类型中的值类型字段等,引用类型的确总是分配在托管堆上, 但是值类型并非总是分配在线程栈上有可能分配在堆上。
值类型和引用类型互相转换:拆箱和装箱
装箱:值类型====》引用类型object
1.分配内存堆
2.值类型数据拷贝到新的内存堆中
3.栈中分配一个新的引用地址指向内存堆
拆箱:引用类型object====》值类型
1.检查确保对象是给定值类型的一个装箱值
2.将该值数据复制到栈中的值类型
string是特殊的引用类型,如果传入参数是string,在方法里修改,原string数值不变。
原因是string的不变性,系统内部做了特殊处理。
链接: B站刘铁猛C#入门精要.
【重点面试题】3、装箱和拆箱的区别
值类型和引用类型的最终基类是Object
装箱:值类型转换成引用类型的过程,生成新的引用
拆箱;引用类型转换成值类型的过程
装箱操作:托管堆分配内存,值类型拷贝数据,object地址指向托管堆对象
拆箱操作:根据object引用地址找到托管堆上的数据,栈上数据拷贝
避免装箱操作,生成新的应用,解决办法就是第一是重载,第二是泛型
链接: 参考资料.
4、public、private、protected、internal、sealed的区别
public全局、private类内部、protected派生类、internal本程序集
sealed声明类就不能继承,声明方法就是不能被重写
【重点面试题】6、什么是接口,描述一下接口的成员具体实现(手撸代码和注意修饰符)
接口interface,不能定义字段,可以定义【非静态的】属性、索引器、事件、方法
默认public,但不能写任何访问修饰符
接口是引用类型,可以通过as运算符强转,获取某对象的接口的引用
接口可以继承N个接口,继承类要实现所有接口的方法
声明接口IA > 继承接口的类B > 类B实现接口所有方法
接口要小而精,定义一组方法,继承接口的派生类要实现接口的所有方法。
接口和抽象类是不能被实例化的对象(引用类型)。
public delegate void DelegateTest();
public interface ITest //只能包含非静态成员函数,隐式public,但不允许访问修饰符
void Method(string a); //方法
string Property //属性
get; set;
event DelegateTest EventTest; //事件,需要先定义一个委托
int this[int index] //索引器
get; set;
举个例子:游戏门:抽象类,不能实例,很多行为,定义接口,破坏可以击碎
系统接口鼠标行为,停留进入离开
很多设计模式,是对接口的应用,面向接口编程,实现层面更加有层次。
【参考C#图解第十五章接口】
【重点面试题】7、foreach迭代器遍历和for循环遍历的区别
如果集合需要foreach遍历,是否可行,存在一定问题
foreach中的迭代变量item是的只读,不能对其进行修改,比如list.Remove(item)操作
foreach只读的时候记录下来,在对记录做操作,或者直接用for循环遍历
foreach对int[]数组循环已经不产生GC,避免对ArrayList进行遍历
for语句中初始化变量i的作用域,循环体内部可见。
通过索引进行遍历,可以根据索引对所遍历集合进行修改
unity中for循环使用lambda表达式注意闭包问题
Foreach遍历原理
任何集合类(Array)对象都有一个GetEnumerator()方法,该方法可以返回一个实现了 IEnumerator接口的对象。
这个返回的IEnumerator对象既不是集合类对象,也不是集合的元素类对象,它是一个独立的类对象。
通过这个实现了 IEnumerator接口对象A,可以遍历访问集合类对象中的每一个元素对象
对象A访问MoveNext方法,方法为真,就可以访问Current方法,读取到集合的元素。
List<string> list = new List<string>() "25", "哈3", "26", "花朵" ;
IEnumerator listEnumerator = list.GetEnumerator();
while (listEnumerator.MoveNext())
Console.WriteLine(listEnumerator.Current);
枚举器的实现(枚举器可用于读取集合中的数据,但不能用于修改集合)
链接: 参考资料.
【重点面试题】8、string和stringbuilder和stringBuffer区别
String不变性,字符序列不可变,对原管理中实例对象赋值,会重新开一个新的实例对象赋值,新开的实例对象会等待被GC。
string拼接要重新开辟空间,因为string原值不会改变,导致GC频繁,性能消耗大
StringBuffer是字符串可变对象,可通过自带的StringBuffer.方法来改变并生成想要的字符串。对原实例对象做拼接的实例,不会生成新的实例对象。
拼接使用StringBuilder和StringBuffer,只开辟一个内存空间,这是性能优化的点。
StringBuilder是字符串可变对象,基本和StringBuilder相同。
唯一的区别是StringBuffer是线程安全,相关方法前带synchronized关键字,一般用于多线程
StringBuilder是非线程安全,所以性能略好,一般用于单线程
三者性能比较 StringBuilder>StringBuffer>String
相关方法
StringBuilder.Append 将信息追加到当前 StringBuilder 的结尾。
StringBuilder.AppendFormat 用带格式文本替换字符串中传递的格式说明符。
StringBuilder.Insert 将字符串或对象插入到当前 StringBuilder 对象的指定索引处。
StringBuilder.Remove 从当前 StringBuilder 对象中移除指定数量的字符。
StringBuilder.Replace 替换指定索引处的指定字符。
9、使用List的区别
list=new list()会导致每增加一个内容就增加新内存,导致原内存浪费,GC频繁
需要添加一个固定参数,只开辟一个内存,list = new list(50)
性能优化的点
10、字符串比较
先用string 变量存储 obj.name ,这用只有一个内存空间保存
如果不存储 obj.name每一次比较都会产生新的内存空间、
比较obj.tag==”Tag“不使用,而是使用避免GC的obj.CompareTag(“tag”)
射线检测SphereColliderNoAlloc可以避免GC,比直接使用SphereCollider性能要好
【重点面试题】11、请简述GC垃圾管理器,和GC产生的原因,并描述如何避免
GC垃圾回收机制,避免堆内存溢出,定期回收那些没有有效引用的对象内存
GC优化,就是优化堆内存,减少堆内存,即时回收堆内存
GC归属于CLR
如何避免
1.减少new的次数
2.字符串拼接使用stringbuilder,字符串比较先定义一个变量存储,防止产生无效内存
3.list,new时候,规定内存大小
4.如果要射线检测,应该使用避免GC的方法XXXXNoAlloc函数
5.foreach迭代器容易导致GC(目前Unity5.5已修复),使用For循环
6.使用静态变量,GC不会回收存在的对象,但静态变量的引用对象可能被回收
7.使用枚举替代字符串变量
8.调用gameobject.tag=="XXX"就会产生内存垃圾;那么采用GameObject.CompareTag()可以避免内存垃圾的产生:
9.不要在频繁调用的函数中反复进行堆内存分配,比如OnTriggerXXX,Update等函数
10.在Update函数中,运行有规律的但不需要每一帧执行的代码,可以使用计时器,比如1秒执行一次某些代码!!!
链接: 参考文章.
12、请描述interface和抽象类之间的不同
接口是一种行为,抽象类是一种不能实例化的对象。
接口interface可以定义方法、属性、索引器、事件
抽象类abstract可以定义字段、静态字段和方法、抽象方法、属性、构造函数
接口可以继承多个接口,抽象类只能继承一个类
接口直接实现所有成员,抽象类重写override抽象方法
接口和抽象都不能被实例化,派生类必须实现基类或接口的方法
抽象类可以派生自另一个抽象类,接口可以多重实现,抽象类只能单一继承
举个例子:抽象类门,多接口继承【可破坏、金属】的行为方法,派生类实例化这个门,接口的实现类实现具体行为,派生类创建这样具体的可破坏的铁门
链接: 参考资料.
【重点面试题】13、反射的实现原理?
定义:运行时,动态获取类型信息,动态创建对象,动态访问成员的过程。
另一种定义:审查元数据并收集元数据的信息。
元数据:编译后的最基本数据单元,就是一堆表,反射就是解析这些元数据。
反射是在运行期间获取到类、对象、方法、数据的一种手段
主要使用类库System.Reflection
反射要点:如何获取类型,根据类型来动态创建对象,反射获取方法以及动态调用方法,动态创建委托
一、动态获取类型信息
1.System.Reflection.Assembly.Load(“XXXX.dll”) 动态加载程序集
2.System.Type.GetType(“XXXX类名”); //动态获取某程序集中某类信息
3.obj.GetType(); //已知对象获取类信息 ——或者——typeof(类型) //已知类类型
二、动态创建对象实例(上一步操作后获得类对象)
System.Activator.CreateInstance(Type type);
三、动态访问成员调用方法(上一步操作后已获取实例对象)
System.Reflection.MethodInfo method = type.GetMethod(“方法名”);//获得方法
System.Reflection.MethodInfo.Invoke(object , new object[]参数) //调用的类实例和实例参数
核心类
System.Reflection.Assembly 描述程序集
System.Type 描述类
System.Reflection.FieldInfo 描述了类的字段
System.Reflection.ConstructorInfo 描述构造函数
System.Reflection.MethodInfo 描述类的方法
System.Reflection.PropertyInfo 描述类的属性
反射耗性能,lua是动态语言,一种小巧的脚本语言,会使用反射机制。
知识扩展
手机端不支持编译,需要热更方案,通过lua的反射机制将旧的DLL文件替换成新的DLL文件。
Xlua是lua框架,由TX鹅肠进行维护,方便了C#与lua相互调用,C#端实现lua虚拟机
链接:参考资料太多,主要搜索,C#反射机制,lua,xlua性能等等。
14、.Net 与 Mono 的关系?
.Net是一个语言平台
Mono为.Net提供集成开发环境,集成并实现了
.NET的编译器、CLR 和基础类库,
使得.Net既可以运行在windows也可以运行于 linux,Unix,Mac OS 等。
15、在类的构造函数前加上 static 会报什么错?为什么?
静态构造函数不允许添加访问修饰符,且必须无参数
原因:无论创建多少类型的对象,静态构造函数只执行一次
类实例化或者首静态成员调用之前,运行库会先调用静态构造函数
静态构造函数优先级高于任何其它构造函数
也无法使用this和base来调用静态构造函数
一个类只能有一个静态函数,如果有静态变量,系统也会自动生成静态函数
16、C# String 类型比 stringBuilder 类型的优势是什么?
string功能性更强,通用性更好,用途更广泛
string不可变性,线程栈同步
编译器已将把string,并通过操作优化成stringbuilder,在性能上不差,一般可以用string代替stringbuilder
17、C# 函数 Func(string a, string b)用 Lambda 表达式怎么写?
Lambda表达式(任意参数)=> 表达式 ; => 读作goesto
(a,b)=> ;
【重点面试题】18、C#中有哪些常用的容器类,各有什么特点,性能区别?
Stack栈:先进后出,入栈和出栈,底层泛型数组实现,入栈动态扩容2倍
Queue队列:先进先出,入队和出队,底层泛型数组实现,表头表尾指针,判空还是满通过size比较
Queue和Stack主要是用来存储临时信息的
Array数组:需要声明长度,不安全
ArrayList数组列表:动态增加数组,不安全,实现了IList接口(表示可按照索引进行访问的非泛型集合对象),Object数组实现
List列表:底层实现是泛型数组,特性,动态扩容,泛型安全
将泛型数据(对值类型来说就是数据本身,对引用类型来说就是引用)存储在一个泛型数组中,添加元素时若超过当前泛型数组容量,则以2倍扩容,进而实现List大小动态可变。(注:大小指容量,不是Count)
LinkList链表
1、数组和List、ArrayList集合都有一个重大的缺陷,就是从数组的中间位置删除或插入一个元素需要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。
2、LinkedList(底层是由链表实现的)基于链表的数据结构,很好的解决了数组删除插入效率低的问题,且不用动态的扩充数组的长度。
3、LinkedList的优点:插入、删除元素效率比较高;缺点:访问效率比较低。
C#则List和LinkedList的区别
List是数组列表,LinkedList是双向链表,List读取速度快,时间复杂度是O(1),增删比较麻烦,时间复杂度是O(n).
LinkedList读取时间复杂度是O(n),增删时间复杂度是O(1)
HashTable哈希表(散列表)
概念:不定长的二进制数据通过哈希函数映射到一个较短的二进制数据集,即Key通过HashFunction函数获得HashCode
装填因子:α=n/m=0.72 ,存储的数据N和空间大小M
然后通过哈希桶算法,HashCode分段,每一段都是一个桶结构,一般是HashCode直接取余。
桶结构会加剧冲突,解决冲突使用拉链法,将产生冲突的元素建立一个单链表,并将头指针地址存储至Hash表对应桶的位置。这样定位到Hash表桶的位置后可通过遍历单链表的形式来查找元素。
1、Key—Value形式存取,无序,类型Object,需要类型转换。
2、Hashtable查询速度快,而添加速度相对慢
3、Hashtable中的数据实际存储在内部的一个数据桶里(bucket结构体数组),容量固定,根据数组索引获取值。
Directionary<TKey,TVaule>字典,有序,泛型存储不需要进行类型装换(不需要装箱拆箱),碰撞阈值扩容~
HashSet:一组不包含重复的元素集合【LeetCode算法217存在重复元素】
性能排序:
插入性能: LinkedList > Dictionary > HashTable > List
遍历性能:List > LinkedList > Dictionary > HashTable
删除性能: Dictionary > LinkedList > HashTable > List
小结:
在修改较频繁,且查找和删除也较多时,首选LinkedList,
在主要以删除为主,插入为辅,且查找较少时,首选Dictionary,
在查找频繁,而又无需修改的情况下,则首选List。
//哈希表结构体
private struct bucket
public Object key;//键
public Object val;//值
public int hash_col;//哈希码
//字典结构体
private struct Entry
public int hashCode; // 除符号位以外的31位hashCode值, 如果该Entry没有被使用,那么为-1
public int next; // 下一个元素的下标索引,如果没有下一个就为-1
public TKey key; // 存放元素的键
public TValue value; // 存放元素的值
private int[] buckets; // Hash桶
private Entry[] entries; // Entry数组,存放元素
private int count; // 当前entries的index位置
private int version; // 当前版本,防止迭代过程中集合被更改
private int freeList; // 被删除Entry在entries中的下标index,这个位置是空闲的
private int freeCount; // 有多少个被删除的Entry,有多少个空闲的位置
private IEqualityComparer<TKey> comparer; // 比较器
private KeyCollection keys; // 存放Key的集合
private ValueCollection values; // 存放Value的集合
链接: Stack参考链接.
链接: Queue参考链接.
链接: ArrayList参考链接.
链接: List参考链接.
链接: HashTable参考链接.
链接: Dictionary参考链接.
19、C#中常规容器和泛型容器有什么区别,哪种效率高?
常规容器有拆箱和装箱操作,速度慢,消耗性能
泛型容器效率更高
20、有哪些常见的数值类?
简单数值类型:整数型、字符型、布尔型、实数型
复合类型:结构类型、枚举类型
21、C#中委托和接口有什么区别?各用在什么场合?
委托delegate:unity事件与委托密切相关,回调机制,减少对象之间数据交互
接口interface:多人协作,完全抽象,类单继承
委托是约束方法的集合
接口是约束类具备的功能集合,解决类单继承问题
22、C#中unsafe关键字是用来做什么的?什么场合下使用?
unsafe 非托管代码,配合fixed一起使用 ,用在需要指针操作的场合
项目背包系统的任务装备栏使用到
【重点面试题】23、C#中ref和out关键字有什么区别?知道Ref的深层原理是什么?
ref修饰引用参数。参数必须赋值,带回返回值,又进又出
out修饰输出参数。参数可以不赋值,带回返回值之前必须明确赋值,
引用参数和输出参数不会创建新的存储位置
如果ref参数是值类型,原先的值类型数据,会随着方法里的数据改变而改变,
如果ref参数值引用类型,方法里重新赋值后,原对象堆中数据会改变,如果对引用类型再次创建新对象并赋值给ref参数,引用地址会重新指向新对象堆数据。方法结束后形参和新对象都会消失。实参还是指向原始对象,值不够数据改变了
【参考C#图解教程:引用类型作为值参数和引用参数】
24、For,foreach,Enumerator.MoveNext的使用,与内存消耗情况
for通过索引或下标一次进行遍历
foreach和Enumerator.MoveNext通过迭代进行遍历
内存消耗本质没有多少区别
迭代器有一个状态机
before
running:yield return 或 yield break 或迭代结束
after
25、函数中多次使用string的+=处理,会产生大量内存垃圾(垃圾碎片),有什么好的方法可以解决。
使用stringbuilder的append
26、当需要频繁创建使用某个对象时,有什么好的程序设计方案来节省内存?
Unity对象池
设计单例模式全局实例化一次
27、Foreach循环迭代时,若把其中的某个元素删除,程序报错,怎么找到那个元素?以及具体怎么处理这种情况?(注:Try…Catch捕捉异常,发送信息不可行)
foreach迭代器不能进行操作
在循环中记录索引值或者key值,在迭代结束后,查找到这个元素,在进行删除操作
28、GameObject a=new GameObject() GameObject b=a 实例化出来了A,将A赋给B,现在将B删除,问A还存在吗?
存在
a引用地址在线程栈中,数据内容在托管堆中
b引用地址在线程栈中,数据内容指向A的托管堆中的内容
B删除,只是删除b的引用地址
【重点面试题】29、C#引用和C++指针的区别
C#不支持指针,但可以使用Unsafe,不安全模式,CLR不检测
C#可以定义指针的类型、整数型、实数型、struct结构体
C#指针操作符、C#指针定义
使用fixed,可以操作类中的值类型
相同点:都是地址
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
不同点:
指针是个实体,引用是个别名。
sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
引用是类型安全的,而指针在不安全模式下
【重点面试题】30、using的作用
资源:实现了IDisposable接口的类或结构。
using语句确保这些资源能够被适当的释放(Resource.Dispose)
using原理
using(分配资源) 使用资源 ——> 释放资源 (隐式)
使用资源(可能会导致异常)会被放进Try块里,释放资源(有无异常)都会放进在finally块
using(分配资源)
try 使用资源
finally Resource.Dispose
using指令,using+命名空间(或命名空间一个类型) 在源文件的顶端声明
也可以不使用using,直接命名空间.类.成员方法
【重点面试题】31、字典Dictionary的内部实现原理
泛型集合命名空间using System.Collections.Generic;
任何键都必须是唯一
该类最大的优点就是它查找元素的时间复杂度接近O(1),实际项目中常被用来做一些数据的本地缓存,提升整体效率。
实现原理
1.哈希算法:将不定长度的二进制数据集给映射到一个较短的二进制长度数据集一个Key通过HashFunc得到HashCode
2.Hash桶算法:对HashCode进行分段显示,常用方法是对HashCode直接取余
3.解决碰撞冲突算法(拉链法):分段会导致key对应的桶会相同,拉链法的思想就像对冲突的元素,建立一个单链表,头指针存储到对应的哈希桶位置。反之就是通过确定hash桶位置后,遍历单链表,获取对应的value
Key值 HashFunc Buckets桶 Entries入口(最小数据结构)
Dictionary字典中最小的数据结构体Entry,调用Add(Key,Value)方法添加的元素都会被封装在这样的一个结构体中。
private struct Entry
public int hashCode; // 除符号位以外的31位hashCode值, 如果该Entry没有被使用,那么为-1
public int next; // 下一个元素的下标索引,如果没有下一个就为-1
public TKey key; // 存放元素的键
public TValue value; // 存放元素的值
Collection版本控制,字典重要变量version,这个变量,在每一次新增、修改和删除操作时,都会使version++
之后每一次迭代过程都会检查版本号是否一致,如果不一致将抛出异常。
这样就避免了在迭代过程中修改了集合,造成很多诡异的问题。
链接: Dictionary实现原理资料.
【重点面试题】32、泛型是什么
多个代码对 【不同数据类型】 执行 【相同指令】的情况
泛型:多个类型共享一组代码
泛型允许类型参数化,泛型类型是类型的模板
5种泛型:类、结构、接口、委托、方法
类型占位符 T 来表示泛型
泛型类不是实际的类,而是类的模板
从泛型类型创建实例
声明泛型类型》通过提供【真实类型】创建构造函数类型》从构造类型创建实例
类<T1,T2> 泛型类型参数
性能:泛型不会强行对值类型进行装箱和拆箱,或对引用类型进行向下强制类型转换,所以性能得到提高
安全:通过知道使用泛型定义的变量的类型限制,编译器可以在一定程度上验证类型假设,所以泛型提高了程序的类型安全。
【重点面试题】33、结构体和类有什么区别
二、Unity脚本基础(已更新2021.3.8)
【重点面试题】1、Unity3D中的协程(coroutine),C#线程和进程之间的区别是什么?
简记:协程和线程区别
协程(协同程序Coroutine): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。 Unity提供了StartCoroutine来开启协程,当你在 StartCoroutine 的函数体里处理一段代码时,利用 yield语句等待执行结果,这期间不影响主程序的继续执行,可以协同工作。
举个例子:LoadLevelAsync(异步加载关卡)后台加载场景的方法。允许你在后台加载新资源和场景,再利用协同,你就可以在前台用 loading 条或动画提示玩家游戏处于加载中,同时后台协同处理加载的事宜。
进程progress:进程是线程的容器。
线程thread: 同一时间可以同时执行多个线程。开辟多条线程开销很大。线程适合多任务同时处理,并发并行。
协程:具体多返回点的方法,时间分片(帧),Unity只能是单线程,只能在主线程调用Api,对象
2、Unity3D 是否支持写成多线程程序?如果支持的话需要注意什么?
支持,如果掌握的Unity多线程的方法,就可以从容的使用多个硬件处理器或处理很难划分管理数据块。
【注意】
1、只能从主线程中访问 Unity3D 的组件,对象和 Unity3D 系统调用
2、如果同时你要处理很多事情或者与 Unity 的对象互动,可以用 thread,可以通过排序来解决一个线程改变一个数据的问题,否则使用协程coroutine。
3、C#中有 lock 这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象
【重点面试题】3、OnEnable、Awake、Start 运行时的发生顺序?哪些可能在同一个对象周期中反复的发生?
Awake > OnEnable>Start 推荐看脚本生命周期顺序
OnEnable可以在同一周期反复的发生
SetActive(true)就会反复触发OnEnable事件
SetActive(false)就会反复触发OnDisable事件
其中Awake函数一般用于实现单例模式;当脚本被实例化时,调用awake,完成成员变量的初始化,在单例模式中会有一个虚方法OnStart在awake中调用,在实际脚本中重写OnStart方法
OnEnable函数是在游戏对象可以调用时调用;
OnDisable是在游戏对象不可用时调用;
Start函数则是在场景中显示该游戏对象前调用一次,用于开始设置物体属性和渲染;
FixedUpdate函数具有固定更新频率,一般进行游戏对象的物理引擎的更新;
Update函数则是渲染帧更新,每秒更新一定频率;
LateUpdate函数是延迟更新,只有在每一帧的所有Update函数都执行完了过后才会执行;
而OnGUI函数则是在每一帧更新时调用。
4、Unity3D 如何获知场景中需要加载的数据?如何动态资源加载?
instantiate:最简单的一种方式,以实例化的方式动态生成一个物体。
Assetsbundle:即将资源打成 asset bundle 放在服务器或本地磁盘,然后使用WWW模块get 下来,然后从这个bundle中load某个object,unity官方推荐也是绝大多数商业化项目使用的一种方式。
Resource.Load:可以直接load并返回某个类型的Object,前提是要把这个资源放在Resource命名的文件夹下,Unity不管有没有场景引用,都会将其全部打入到安装包中
AssetDatabase.loadasset :这种方式只在editor范围内有效,游戏运行时没有这个函数,它通常是在开发中调试用的。
5、Unity中碰撞器(Collider)和触发器(Trigger)的区别?
碰撞器(Collider)有碰撞效果,IsTrigger=false,可以调OnCollisionEnter/Stay/Exit函数
触发器(Trigger)没有碰撞效果,isTrigger=true,可以调用OnTriggerEnter/Stay/Exit函数
6、U3D中,几种施加力的方式,描述出来
首先需要对象要有rigidbody组件
Rigidbody.AddForce /AddForceAtPosition
2D Constant Force
Force/Relative Force/Torque
7、物体自旋转使用的函数叫什么?物体绕某点旋转使用函数叫什么?
transform.Rotate
transform.RotateAround
8、u3d 提供了一个用于保存读取数据的类,(playerPrefs),请列出保存读取整形数据的函数
PlayerPrefs类是一个本地持久化保存与读取数据的类
PlayerPrefs类支持3中数据类型的保存和读取,浮点型,整形,和字符串型。
分别对应的函数为:
SetInt();保存整型数据;GetInt();读取整形数据;
SetFloat();保存浮点型数据; GetFlost();读取浮点型数据;
SetString();保存字符串型数据; GetString();读取字符串型数据;
9、unity3d 从唤醒到销毁有一段生命周期,请列出系统自己调用的几个重要方法。
(init)Awake>OnEnable>Start > (Physic)FixedUpdate> (GameLogic)Update>Yield >LateUpdate>OnGui>OnDisable>OnDistroy
10、物理更新一般在哪个系统函数里?
FixedUpdate,每固定帧绘制时执行一次,和 update 不同的是 FixedUpdate 是渲染帧执行,如果你的渲染效率低下的时候 FixedUpdate 调用次数就会跟着下降。
FixedUpdate 比较适用于物理引擎的计算,因为是跟固定帧渲染有关。
Update 就比较适合做游戏逻辑更新。
LateUpdate比较适合相机更新,update后更新,防止视角移动,游戏对象发生空帧未出现。
11、反向旋转动画的方法是什么?
1.将动画速度调成-1
2.改代码animation.speed=-1
【重点面试题】12、用代码实现第三人称角色控制器?第一人称角色控制器
大致思路:
摄像机与角色的距离范围
摄像机旋转、平移
鼠标控制摄像机
//代码稍后会在博客中贴出,转链接,目前未实现
13、获取、增加、删除组件的命令分别是什么?
获取:GetComponent
增加:AddComponent
删除:Destroy
14、Animation.CrossFade 是什么?
动画淡入淡出
15、Application.LoadLevel 命令作用是什么?
加载关卡,已弃用
现在使用SceneManager.LoadScene
16、调式记录到控制台的命令是什么?
Debug.Log();
17、编辑器类存放路径是什么?
Asset/Editor
18、使用原生 GUI 创建一个可以拖动的窗口命令是什么?
GUI.DragWindow
19、localPosition 与 Position 的使用区别?
localPosition :自身坐标系,相对于父级的位置
Position :世界坐标系中的位置
20、Mathf.Round和Mathf.Clamp和Mathf.Lerp含义?
Mathf.Round:四舍五入
Mathf.Clamp:左右限值
Mathf.Lerp:插值
【重点面试题】21、写一个计时器工具,从整点开始,格式为00:00:00
分小时、分、秒
22、写出 Animation 的五个方法
AddClip 将 clip 添加到名称为 newName 的动画中。
Blend 在后续 time 秒中将名称为 animation 的动画向 targetWeight 混合。
CrossFade 在后续 time 秒的时间段内,使名称为 animation 的动画淡入,使其他动画淡出。
CrossFadeQueued 使动画在上一个动画播放完成后交叉淡入淡出。
IsPlaying 名称为 name 的动画是否正在播放?
PlayQueued 在先前的动画播放完毕后再播放动画。
RemoveClip 从动画列表中移除剪辑。
Sample 对当前状态的动画进行采样。
Stop 停止所有使用该动画启动的正在播放的动画。
23、用鼠标实现在场景中拖动物体,用鼠标滚轮实现缩放(用一个 Cube 即可)
在场景中添加一个Plan,Camera,Directional Light,Cube。添加两个脚本一个挂在Camera上,另一个挂在Cube上。
1.鼠标滚轮实现缩放:将摄像机的镜头拉近或者拉远,调整摄像机的视角就可以实现2.鼠标实现在场景中拖动物体:解决思路就是将世界坐标转换成屏幕坐标,然后计算物体与鼠标之间移动量,循环鼠标被按下操作,得到鼠标的当前位置,加上计算好的移动量,将新的坐标赋值给物理就行了。 具体代码实现:http://www.cnblogs.com/hewencong/p/4299722.html
24、<愤怒的小鸟>给予初速度以后,怎么让小鸟受到重力和空气阻力的影响而绘制抛物线轨迹,说出具体的计算方法
Vector3 v 代表初速度 v’代表现在的速度, 假设小鸟是沿的 z 轴也就是transform.forward 方向,运动的质量为 m,那么 v‘=v-new Vector3(0,mgt,ft),transform.Translate(v’)做的就是抛物线运动(g 为重力加速度不要用现实中的需要自己调试,f 为阻力也要自己调试
设置,t 为时间)
25、当游戏中需要频繁创建一个物体时,我们需要怎样做能够节省内存?
1.使用预制体对象
2.使用对象池技术
26、碰撞检测需要物体具备什么属性?
能检测碰撞发生的方式有两种,一种是利用碰撞器,另一种则是利用触发器
27、如何使子控件居中,如果使用UGUI怎么实现
锚点设置为中心
28、去掉敏感字的程序(手写程序)
字符串replace
29、写出WWW的几个方法
WWW.LoadFromCacheOrDownload:可被用于将Assets Bundles自动缓存到本地磁盘
WWW.Dispose :释放现有的 WWW 对象。
WWW.isDone:是否完成下载?(只读)
WWW.progress:下载进度(只读)。
【重点面试题】30、启用MipMaps对内存的影响是?MipMap的作用?如何操作?
增加约33%的内存,1/4 +1/16
Lod相关知识
31、采用Input.mousePosition来获取鼠标在屏幕上的位置
左下角为原点(0,0),右上角为(Screen.Height,Screen.Width)
32、Unity中销毁GameObject的方式,简述Destroy和DestroyImmediate的区别
Destroy销毁消息对象,内存中还是存在,只有内存不够才被清除释放内存
DestroyImmediate立即销毁对象,并释放内存
33、如何检测物体是否被其他对象遮挡
射线检测
EventSystem.IsPointerOverGameObject
是否具有给定 ID 的指针是否位于 EventSystem 对象上
34、UnityAction和UnityFunc的区别
unity中需要带上修饰event,事件与委托密切相关,两行代码变一行代码
public event Action myEvent;
UnityAction本质上就是委托,带泛型参数最多4个,且没有返回值的方法
Action<T1,T2,T3>
UnityFunc本质上也是委托,带泛型参数最多4个,可以有返回值的方法
Func<T1,T2,T3,Return>
Action和Func的重要区别:
Action只用于没有返回值的方法,Func只用于有返回值的方法
它们泛型里的区别:
Action的泛型里要和方法参数的类型相同,且只有一种泛型
Func的泛型里前者和方法参数类型相同,最后一个与返回值类型相同
一般用于回调方法,注册事件,类直接数据交互松耦合
链接: 参考资料.
【重点面试题】35、unity常用资源路径有哪些
//获取的目录路径最后不包含 /
//获得的文件路径开头包含 /
Application.dataPath; //Asset文件夹的绝对路径
//只读
Application.streamingAssetsPath; //StreamingAssets文件夹的绝对路径(要先判断是否存在这个文件夹路径)
Application.persistentData ; //可读写
//资源数据库 (AssetDatabase) 是允许您访问工程中的资源的 API
AssetDatabase.GetAllAssetPaths; //获取所有的资源文件(不包含meta文件)
AssetDatabase.GetAssetPath(object) //获取object对象的相对路径
AssetDatabase.Refresh(); //刷新
AssetDatabase.GetDependencies(string); //获取依赖项文件
Directory.Delete(p, true); //删除P路径目录
Directory.Exists(p); //是否存在P路径目录
Directory.CreateDirectory(p); //创建P路径目录
AssetDatabase //类库,对Asset文件夹下的文件进行操作,获取相对路径,获取所有文件,获取相对依赖项
Directory //类库,相关文件夹路径目录进行操作,是否存在,创建目录,删除等操作
【重点面试题】36、向量的点乘、叉乘以及归一化的意义?、
叉乘cross:可以获得两个向量A和B所构成平面,垂直的向量C,和左手坐标系类似,可以用来判断角色移动方向,判断顺时针还是逆时针旋转
点乘 dot :用来求向量之间的夹角,判断向量是否在同一方向、以及B向量在A向量上的投影
a·b>0 方向基本相同,夹角在0°到90°之间
a·b=0 正交
a·b<0 方向基本相反,夹角在90°到180°之间
归一化normalized:用在只关系方向,不关心大小的情况下
三、Unity性能优化(必问)(已更新2021.3.8)
lod 是什么,优缺点是什么
MipMap 是什么?作用?
当游戏中需要频繁创建一个物体对象时,我们需要怎么做来节省内存。
如何优化内存?
动态加载资源的方式?和区别
请简述一下对象池原理,什么情况下使用?
19.使用mipmap有什么好处?什么情况下使用?
Unity内存优化?GC垃圾回收
你认为unity在开发过程中哪些地方比较容易造成内存泄漏和内存泄漏问题?如何避免?
如何解决过多创建和删除对象带来的卡顿问题
Unity资源加载的有几种方式,简述asset bundie
背包系统中只有20个格子,现在有总共有100个物体,除了显示在视野中的20个外,对其他的处理方法?(注:将其他隐藏起来不可行,对象池得有具体的说明)
四、设计模式
1、用过哪些设计 以上是关于面试Unity面试题&答案的主要内容,如果未能解决你的问题,请参考以下文章 2022年Unity 面试题 五萬字 二佰道 Unity面试题大全,面试题总结全网最全,收藏一篇足够面试