Unity面试题集(不断更新)

问题

C#基础

值类型与引用类型的区别

答:区别:
1.值类型存储在内存栈中,引用类型数据存储在内存堆中,而内存单元中存放的是堆中存放的地址。
2.值类型存取快,引用类型存取慢。
3.值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针和引用。
4.栈的内存是自动释放的,堆内存是.NET中会由GC来自动释放。
5.值类型继承自System.ValueType,引用类型继承自System.Object。

简述ArrayList和List的区别

答:ArrayList是非泛型列表,存储数据时把所有的数据都当成object类型存储,存在装箱问题,取出来使用的时候存在拆箱问题,装箱拆箱会使性能变差,而且存在数据安全问题,但是优点在于可以让值类型和引用类型互相转换。
List是泛型列表,在使用的时候才去定义数据类型,泛型避免了拆箱装箱的问题,存入读取速度较快,类型也更安全。

简述GC(垃圾回收)产生的原因,并描述如何避免

答:当我用new创建一个对象时,当可分配的内存不足GC就会去回收未使用的对象,但是GC的操作是非常复杂的,会占用很多CPU时间,对于移动设备来说频繁的垃圾回收会严重影响性能。
避免:
1)减少new产生对象的次数
2)使用公用的对象(静态成员)
3)如果字符串拼接多的将String换为StringBuilder

下列代码在运行中会产生几个临时对象

string a = new string("abc");
a= (a.ToUpper() + "123").Substring(0, 2);

答:第一行是会出错的。应该这样初始化:
string b = new string(new char[]{'a','b','c'});
产生三个对象:
第一个是string a产生的
第二个是string("abc")产生的
第三个是赋值操作产生的,就是说静态池里创建了一个new String("abc")的拷贝,实际上是把静态池里的对象传给了a 。这就叫做写时拷贝。

sealed用在类的声明和函数声明时的作用

当一个类有sealed关键字修饰,其它类无法继承这个sealed类
示例:sealed类B可以继承A,但是C不可以继承B

class A { }
sealed class B : A { }
//class C : B { } //错误:C无法从B派生

当一个类中的一个方法或属性用sealed修饰,则这个类的派生类无法重写此虚方法或虚属性。
必须是重写才能密封,所以和override一起使用

class A
    {
        protected virtual void MethodA() { }
        protected virtual void MethodB() { }
    }

    class B : A
    {
        protected override void MethodA() { }
        protected sealed override void MethodB() { }
    }

    class C : B
    {
        protected override void MethodA() { }
        protected override void MethodB() //错误
        {//错误:方法B是密封的不能重写}
    }

protected、internal的区别

public 关键字是类型和类型成员的访问修饰符。公共访问是允许的最高访问级别,对访问公共成员没有限制。
protected 关键字是一个成员访问修饰符。受保护成员在它的类中可访问并且可由派生类访问。
private 关键字是一个成员访问修饰符。私有访问是允许的最低访问级别。私有成员只有在声明它们的类和结构体中才是可访问的。
internal 关键字是类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的。

C#反射的实现原理

反射是System.Reflection命名空间,可以读取metadata,并使用metadata,是微软提供的一个帮助类,在各个场景中都会使用到,而其主要作用是“解耦”,降低对细节的依赖。审查元数据并收集关于它的类型信息的能力。
实现原理:在运行时根据程序集及其中的类型得到元数据。

结构体和类有什么区别

1、类是对一件事物的抽象,可以有自己的访问方式(如public),成员变量,成员函数,继承和被继承这样的关系。
2、结构体,只是用来表示一个结构的,它有成员变量,成员函数(c++后来加入的……)。但是没有访问方式和继承这样的关系,它只是用于表示一种数据结构。

冒泡排序的原理

每次对相邻的两个元素进行比较,若前者大于后者则进行交换,如此一趟下来最后一趟的就是最大元素,重复以上的步骤,除了已经确定的元素

哈希表是什么

哈希表可以存储各种类型的数据,当我们从哈希表中查找所需要的数据时,理想情况是不经过任何比较,一次存取便能得到所查记录,那就必须在记录的存储位置和它的关键字之间建立一个确定的对应关系 ,使每个关键字和结构中一个唯一的存储位置相对应。(关键字就是所要存储的数据,存储位置相当于数组的索引)

泛型是什么

泛型将接口的概念进一步延伸,“泛型”的字面意思就是广泛的类型。类、接口和方法代码可以应用于非常广泛的类型,代码与它们能够操作的数据类型不再绑定在一起,同一套代码可以用于多种数据类型,这样不仅可以复用代码,降低耦合性,而且还提高了代码的可读性以及安全性。

反射是什么

指程序可以访问、检测和修改它本身状态或行为的一种能力

ASP中Session对象默认有效期为多少分钟?

20分钟

类和接口

1.类不可以多继承,而接口可以多实现
2.抽象类自身可以定义成员,而接口不可以
3.抽象类和接口都不能被实例化
4.一个类只能单继承,接口可以多实现

Unity基础

线程和协程

Unity是否支持多线程,如果支持的话需要注意什么

答:Unity支持多线程,如果同时要处理很多事情或者与Unity的对象互动小可以用thread,否则使用coroutine。
注意:
1.虽然支持多线程,但是仅能从主线程中访问Unity3D的组件,对象和Unity3D系统调用,所以如果使用的话需要把组件中的数值传到开启的新线程中。
2.C#中有lock这个关键字,以确保只有一个线程可以在特定时间内访问特定的对象

Unity的协程与线程之前的区别是什么

1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程实际上是在一个线程中,只不过每个协程对CPU进行分时,协程可以访问和使用unity的所有方法和component
2.线程,多线程是阻塞式的,每个IO都必须开启一个新的线程,但是对于多CPU的系统应该使用thread,尤其是有大量数据运算的时刻,但是IO密集型就不适合;而且thread中不能操作unity的很多方法和component

什么是协同程序?

答:在主线程运行时同时开启另一段逻辑处理,来协助当前程序的执行。换句话说,开启协程就是开启一个线程。可以用来控制运动、序列以及对象的行为。

四元数

简述四元数的作用,四元数对欧拉角的优点

答:所谓四元数,就是把4个实数组合起来的东西。4个元素中,一个是实部,其余3个是虚部
作用:四元数用于表示旋转
优点:
1)能进行增量旋转
2)避免万向锁
3)给定方位的表达方式有两种,互为负(欧拉角有无数种表达方式)
4)四元数不会有欧拉角存在的 gimbal lock 问题[万向节死锁]
5)四元数由4个数组成,旋转矩阵需要9个数
6)两个四元数之间更容易插值
7)四元数、矩阵在多次运算后会积攒误差,需要分别对其做规范化(normalize)和正交化 (orthogonalize),对四元数规范化更容易
8)与旋转矩阵类似,两个四元组相乘可表示两次旋转

矩阵、向量

向量的点乘、叉乘以及归一化的意义

点乘的意义:根据点乘公式和余弦可以推导,点乘的值为正负代表着两向量之间的夹角大小,也可以通过点乘值逆推两向量夹角,点乘结果代表两向量的一致性,归一化两向量的点乘值越接近于1,两向量的方向一致性越高
叉乘的意义:向量叉乘的结果为垂直于两向量组成平面的向量,可以根据顶点信息求取顶点法线,得到的结果为符合右手坐标系的向量
归一化的意义:将向量a等比例缩放为单位矢量,在计算时我们无需考虑具体的模长所带来的影响,只考虑向量的方向,可以理解为物理学中的功

矩阵相乘的意义及注意点

矩阵乘法,很重要的一点就是要注意矩阵的order,即AxB不一定等于BxA。另外,要做AxB运算时,要保证A的列要与B的行所属物理意义相同。这样两个矩阵相乘才有意义。这也是做矩阵乘法时为何要保证A的列数=B的行数的原因之一。

UI篇

为何大家都在移动设备上寻求Unity原生的GUI的替代方案

答:
1.不美观
2.OnGUI很耗费时间
3.使用不方便
4.drawcall很高

如何在不同分辨率下保持UI的一致性

NGUI中有一个屏幕分辨率的自适应性,原理就是计算出屏幕的宽高比跟原来预设的屏幕分辩率的对比值,然后修改摄像机的size。UGUI通过锚点和中心店的分辨率也能解决这个问题。

为什么dynamic font在unicode的环境优于static font

答:Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。
使用动态字体时,Unity将不会预先生成一个与所有字体的字符纹理。当需要支持亚洲语言或者较大的字体的时候,若使用正常纹理,则字体的纹理将非常大。

Shader

写光照计算中的diffuse的计算公式?

实际光照强度 l=环境光(lambient)+ 漫反射光(Idiffuse)+ 镜面高光(lspecular)
环境光:lambient=环境光强度(Aintensity)* 环境光颜色(Acolor)
漫反射光:ldiffuse=镜面光照强度(Dintensity)* 镜面光颜色(Scolor)*(光的反射向量(R).观察者向量(V))^镜面光指数(n)

Unity3d提供了几种光源类型,分别是哪几种?

答:四种。
平行光:Directional Light
点光源:Point Light
聚光灯:Spot Light
区域光源:Area Light

MeshRender中material和shader的区别?

答:MeshRender是模型渲染的组件,有此组件物体才能显示出来
Material是材质球,实际就是shader的实例,并进行赋值,贴图、纹理、颜色等。
Shader是着色器,实际上是一段程序,还可以用来实现一些仅靠贴图不容易实现的效果,如玻璃。

Shader大致分为:

1.表面着色器
2.顶点和片元着色器
3.固定功能着色器

光照贴图 的优势是什么?

答:
1.使用光照贴图比使用实时光源渲染要快
2.可以降低游戏内存消耗
3.多个物体可以使用同一张光照贴图

MeshRender中的material和sharedmaterial的区别

使用material属性的时候,每次都会new一份新的material作用与它,但不会改变本地工程中的材质material;sharedMaterial是共享材质,无论使用多少次,内存中都只会占用一份内存,但是会影响其他使用同一材质球的对象。所以,从效率上来说,sharedMaterial的效率更高。

Render的作用?描述MeshRender和SkinnedMeshRender的关系与不同

答:render是渲染器,渲染器可以使物体显示在屏幕上。
MeshRender是网格渲染,SkinnedMeshRender是蒙皮网格渲染器

简述SkinnedMesh的实现原理

答:骨骼蒙皮动画,模型本身是静态的,是因为通过蒙皮,使模型每个点都有Skin数据,Skin数据包括顶点受到哪些骨骼影响以及这些骨骼影响顶点的权重值,还有动画数据,有了Skin数据的模型就可以根据动画数据进行显示动画了。

摄像机

如果场景中同事放置多个Camera并同时处于活动状态会放发生什么

答:游戏界面会看到很多摄像机的混合图像

为什么Unity中会发生组件上数据丢失的情况

答:因为组件上的对象被删除了

如何安全的在不同工程间迁移asset数据,三种方法

答:
1)将Assets目录和Library目录一起迁移
2)导出资源包
3)用unity自带的assets Server功能(了解就行)

MeshCollider和其他Collider的一个主要不同点

答:MeshCollider是网格碰撞器,对于复杂网状模型上的碰撞检测,比其他的碰撞检测精确的多,但是相对其他的碰撞检测计算也增多了,所以一般使用网格碰撞也不会在面数比较高的模型上添加,而会做出两个模型,一个超简模能表示物体的形状用于做碰撞检测,一个用于显示。

简述OnBecameVisible和OnBecameInvisible的发生时机,以及意义

答:当物体是否可见切换之时。可以用于只需要在物体可见时才进行的计算。
当renderer(渲染器)在任何相机上都不可见时调用:OnBecameInvisible 当renderer(渲染器)在任何相机上可见时调用:OnBecameVisible

碰撞

当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况。如何处理。

答:穿透(碰撞检测失败)
避免的方法:把刚体的实时碰撞检测打开Collision Detection修改为Continuous Dynamic

在unity3d中物体发生碰撞的整个过程中,有几个阶段,分别列出对应的阶段函数

主要是三个阶段:
1.Collider.OnCollisionEnter 进入碰撞,当collider/rigidbody开始触动另一个rigidbody/collider时OnCollisionEnter被调用。
2.Collider.OnCollisionStay 逗留碰撞,每个collider/rigidbody触动rigidbody/collider,将在每帧调用OnCollisionStay。通俗的说, 一个碰撞器或刚体触动另一个刚体或碰撞器,在每帧都会调用OnCollisionStay,直到它们之间离开不接触。
3.Collider.OnCollisionExit 退出碰撞, 当 collider/rigidbody停止触动另一个 rigidbody/collider时,OnCollisionExit被调用。

Unity系统API

物理更新一般在哪个系统函数里?

答:FixedUpdate,每固定帧绘制时执行一次,和update不同的是FixedUpdate是渲染帧执行,如果你的渲染效率低下的时候FixedUpdate调用次数就会跟着下降。FixedUpdate比较适用于物理引擎的计算,因为是跟每帧渲染有关。Update就比较适合做控制。

OnEnable、Awake、Start运行时发生的顺序?那些可能在同一个对象周期重复发生

答:Awake –>OnEnable->Start
OnEnable在同一周期中可以反复地发生

动态加载资源的方式?区别是什么?

答:
1.Resources.Load();
2.AssetBundle
区别:
Resources是动态内部调用,Resources在编辑环境下是project窗口的一个文件夹,调用里面的资源,可以用Resources类,比如Resources.Load,打包后这个文件夹是不存在的,会统一生成assets资源,AssetBundle 是外部调用,要用AssetBundle 首先要先把资源打包为.assetbundle文件,再动态的去加载这个文件,本地或者网络服务器都可以。 简单说,Resources资源的加载是动态加载内部的,AssetBundle 是动态加载外部的

Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期,请列出系统自带的几个重要的方法。

答:Awake——>Start——>Update——>FixedUpdate——>LateUpdate——>OnGUI——>Reset——>OnDisable——>OnDestroy

脚本的生命周期

First Scene Load 第一个场景加载
Awake:这个函数是在Start函数之前以及预制物体实例化后被调用。
OnEnable:(仅在对象激活状态下可用):这个函数在对象可用之后被调用。
Before the first frame update 第一帧更新之前
Start:如果脚本实例化被启用,则Start函数在第一帧更新之前被调用。
In between frames 执行期间
FixedUpdate: FixedUpdate()比Update()函数调用的更频繁。当帧率比较低时,它每帧被调用多次,如果帧率比较高,它有可能就不会被调用。所有的物理计算和更新都立即发生在FixedUpdate()之后。当在FixedUpdate()中计算物体移动时,你不需要乘以Time.deltaTime。因为FixedUpdate()是基于可靠的定时器的,不受帧率的影响。
Update() 每帧调用一次。这是帧更新的主要函数。
LateUpdate: 在Update()执行后,LateUpdate() 也是每帧都被调用。在Update()中执行的任何计算都会在LateUpdate()开始之前完成。LateUpdate()的一个常见应用就是第三人称控制器的相机跟随。如果你把角色的移动和旋转放在Update()中,那么你就可以把所有相机的移动旋转放在LateUpdate()。这是为了在相机追踪角色位置之前,确保角色已经完成移动。
Coroutine 协同程序(协程)
yield:协程在所有的Update函数于下一帧调用后继续执行。
yield WaitForSeconds(2):在一个指定的时间延迟后继续执行,在所有的Update函数被调用之后。
yield WaitForFixedUpdate():在所有脚本上所有的FixedUpdate被调用之后继续执行。
When the Object is Destroyed 当对象被销毁时
OnDestroy: 这个函数在所有帧更新之后被调用,在对象存在的最后一帧(对象将销毁来响应Object.Destroy或关闭一个场景)。
When Quitting 当退出时
OnApplicationQuit:在应用退出之前所有的游戏对象都会调用这个函数。在编辑器中当用户停止播放时它将被调用。在webplayer中,当网页关闭时被调用。
OnDisable: 当行为不可用或非激活时,这个函数被调用。

移动摄像机的动作放在哪个系统函数中,为什么放在这个函数中?

答:LateUpdate,在每帧执行完毕调用,它是在所有Update结束后才调,比较适合用于命令脚本的执行。官网上例子是摄像机的跟随,都是在所有Update操作完才跟进摄像机,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。

Unity3d提供了一个用于保存和读取数据的类(PlayerPrefs),请列出保存和读取整形数据的函数

答:
PlayerPrefs.SetInt()
PlayerPrefs.GetInt()

哪个函数在游戏进入新场景后会被马上调用?

答:MonoBehaviour.OnLevelWasLoaded

如何销毁一个UnityEngine.Object及其子类对象

答:Destory

获取、增加、删除组件的命令分别是什么?

答:
获取:GetComponent
增加:AddComponent
没有删除组件只有让组件不生效:enable

Application.loadLevel命令是什么?

答:加载关卡

调试记录到控制台的命令是什么?

答: Debug.Log();

LayerMask.NameToLayer()这个方法有什么作用?

答:层索引

localPosition与Position的使用区别?

答:localPosition:自身位置,相对于父级的变换的位置,局部坐标其实就是自身的坐标,会随着物体的旋转而变化的。

Position:在世界坐标transform的位置,世界坐标是不会变的,一直以世界坐标轴的XYZ为标准。

物体自身旋转使用的函数?

答:Transform.Rotate()

物体围绕某点旋转使用的函数?

答:Transform.RotateAround()

用于记录节点空间几何信息的组件名称,及其父类的名称

Transform 父类名称是Component

UI的自适应原理

可编程渲染管线的流程,VertexShader和SurfaceShader的不同之处

预制体

Prefab的作用?如何在移动环境的设备下恰当地使用它?

Prefab是预制物,一般当游戏中需要频繁创建一个物体时,使用预制物可以节省内存,方便创建,方便对游戏物体进行操作,方便对属性进行修改。

unity 当需要频繁创建一个物体对象时,怎样减少内存

答:动态加载再实例化,如果自己不主动清理内存的话,再次加载不会增加内存的,会自动去取之前已经加载好的assets,如果这一个assets你都嫌多的话,那你只能减资源了,比如,模型面数,纹理尺寸等

动画

请描述游戏动画有哪几种,以及其原理。

答:主要有关节动画、单一网格模型动画(关键帧动画)、骨骼动画。
1.关节动画:把角色分成若干独立部分,一个部分对应一个网格模型,部分的动画连接成一个整体的动画,角色比较灵活,Quake2中使用这种动画。
2.单一网格模型动画由一个完整的网格模型构成,在动画序列的关键帧里记录各个顶点的原位置及其改变量,然后插值运算实现动画效果,角色动画较真实。
3.骨骼动画,广泛应用的动画方式,集成了以上两个方式的优点,骨骼按角色特点组成一定的层次结构,有关节相连,可做相对运动,皮肤作为单一网格蒙在骨骼之外,决定角色的外观,皮肤网格每一个顶点都会受到骨骼的影响,从而实现完美的动画。

延伸

lod是什么,优缺点是什么?

答:LOD是Level of detail简称,意为多层次细节,是最常用的游戏优化技术,LOD技术指根据物体模型的几点在显示环境中所处的位置和重要性,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
优点:可根据距离动态的选择渲染不同细节的模型
缺点:增加美工工作量,增大了游戏的容量。

MipMap是什么?作用?

答:MipMapping:在三维计算机图形的贴图渲染中有常用的技术,为加快渲染进度和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件,这样的贴图被称为MipMap。

如何优化内存?

答:1.压缩自带类库
2.将暂时不用的以后还需要使用的物体隐藏起来而不是直接Destroy掉
3.释放AssetBundle占用的资源
4.降低模型的片面数,降低模型的骨骼数量,降低贴图的大小
5.使用光照贴图
6.使用多层次细节(LOD)
7.使用着色器(Shader)
8.使用预设(Prefab)等

简述可编程渲染管线的流程?

本文大多数回答来自
作者:雷潮
链接:https://www.jianshu.com/p/4a9f77f2aa57
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(Unity面试题集(不断更新))