前言
终于决定了要好好学习一番Unity,或许,这就是我的第一部选择吧。
本文章将简单梳理unity相关的必知知识点,边写边学。
结构参考于csdn:https://blog.csdn.net/qq_34937637/article/details/79653525
一、什么是协同程序
在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行。
协程很像多线程,但不是多线程。
Unity 协程在每帧结束后去检测 yield 的条件是否满足。
详见:Unity-探索协程
二、Unity3d 中的碰撞器和触发器的区别
碰撞器是触发器的载体,触发器只是碰撞器的一个属性。(2d/3d 碰撞器都是这样)
当
isTrigger = false
时,为碰撞器,会根据物理引擎产生碰撞效果,其相关的回调函数为OnCollisionEnter/Stay/Exit
,会在碰撞的三个时期调用其内部逻辑代码。当
isTrigger = true
时,为触发器,不产生碰撞效果,其回调函数为OnTriggerEnter/Stay/Exit
, 在碰撞盒与其他物体碰撞盒碰撞的三个期间调用其内部逻辑代码。
效应器往往应用在 不产生碰撞效果,但是需要的得知物体是否接触的情况,例如:收集金币的效果。
三、 物体发生碰撞的必要条件
- 两个物体必须有碰撞器
- 其中一个必须为刚体
- 运动的物体带有 Rigidbody 刚体脚本才能检测到碰撞。
这里还有:Unity-CharacterController 碰撞与触发器之间关系
四、ArrayList 与 List 的区别
C# 中的 ArrayList 与 java 还是有所不同的。这里就说 C# 的ArrayList
ArrayList 与 List 最大区别就是装箱和拆箱的问题。
- ArrayList 是个不安全的类型,会将所有其中数据当作 object 来处理,这样装箱与拆箱也是一笔不小的开销
- List 与ArrayList 类似,但是泛型,在声明时就限制了存储的类型,其性能优于ArrayList。
五、如何安全在不同工程间迁移 asset数据
- 将 asset 目录与 library 目录一起迁移
- 导出包
- unity 自带的 asset service功能
六、OnEnable、Awake、Start 发生顺序
Awake -> OnEnable -> Start, OnEnable在同一周期可反复发生。
七、MeshRender 中 material 和 sharedMaterial 的区别
修改 sharedMaterial 将改变所有使用此材质的物体的外观,以及存储工程中的设置。所以不推荐用 sharedMaterial 修改材质。
八、Unity提供了几种光源,分别是什么
平行光:Directional Light
点光源:Point Light
聚光灯:Spot Light
区域光源:Area Light
九、简述一下对象池,你觉得FPS中那些东西适合适用对象池
对象池是存放一些常被创建与销毁的对象的一个空间,当一个对象会频繁创建与销毁时,会十分费时,可将对象存放到对象池中,但需要使用此对象时,将会访问对象池是否有可用对象,如果有则直接拿出来使用;当没有时,才会重新创建。
在FPS游戏中,比如子弹会大量创建与销毁,就会使用到对象池。
详解:Unity-对象池
十、CharacterController 与 Rigidbody 的区别
Rigidbody 是 Unity 物理系统中最为基本的组件,具有完全真实物理特性。
CharacterController 是 Unity 为了方便第一人称的开发而封装的组件,他具有一定的物理特性,但不完全。
需要注意的是,两者最好不要同时使用,可能会产生“角色一飞冲天”的情况。
解决办法可见:Unity-人物转向一飞冲天问题
十一、简述prefab的用处
prefab相当于一个模板,对已有的素材,脚本,参数进行默认配置,便于后期修改。同时也便于导入导出。
十二、请简述sealed关键字用在类声明时与函数声明时的作用
类似于 java 中的 final ,修饰类将不被继承,修饰方法,则不会被重写。
十三、请简述private,public,protected,internal的区别
- public:对任何类和成员都公开,无限制访问(默认)
- private:仅对该类公开
- protected:对该类和其派生类公开
- internal:只能在包含该类的程序集中访问该类
十四、Unity3d 实现2d游戏
- GUI/UGUI
- 把摄像机的Projection(投影)值调为Orthographic(正交投影),不考虑z轴
- 2d插件,如: 2DToolKit 和 NGUI
十五、几种施加力的方式
都为 Rigidbody 的方法
- addForce
- addForceAtPosition
十六、链条关节
Hinge Joint , 可模拟两个物体用一根链条连接起来的情况,当两物体之间达到一定距离会产生拉力。
十七、物体自身旋转
1 | Transform.Rotate(); |
十八、Unity3d提供了一个用于保存和读取数据的类(PlayerPrefs),请列出保存和读取整形数据的函数
只能存储基础类型
1 | PlayerPrefs.SetInt(); |
十九、Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期,请列出系统自带的几个重要的方法。
Awake——>OnEnable–>Start——>Update——>FixedUpdate——>LateUpdate——>OnGUI——>OnDisable——>OnDestroy
二十、物理更新一般放在哪个系统函数里?
FixedUpdate,固定时间间隔执行 可以在edit->project setting->time设置 update 是在渲染帧执
行,和Update不同的是FixedUpdate是渲染帧执行,如果你的渲染效率低下的时候FixedUpdate调
用次数就会跟着下降。FixedUpdate比较适用于物理引擎的计算,因为是跟每帧渲染有关。Update
就比较适合做控制。
二十一、在场景中放置多个Camera并同时处于活动状态会发生什么?
游戏界面可以看到很多摄像机的混合。
二十二、如何销毁一个UnityEngine.Object及其子类?
使用Destroy()方法;
二十三、请描述为什么Unity3d中会发生在组件上出现数据丢失的情况
一般是组件上绑定的物体对象被删除了。
二十四、LOD是什么,优缺点
LOD(Level of detail)多层次细节,最常用的游戏优化技术。它根据模型的位置和重要程度来决定资源分配,降低非重要物体的面数和细节度,从而获取高效的渲染运算。
缺点是增加了内存。
详见:Unity-探索LOD
二十五、何为MipMap,作用
MipMaping 是在三维计算机图形渲染中比较常见的技术,为了加快渲染和减少图像锯齿,贴图被处理成由一系列被预先计算和优化过的图片组成的文件。
二十六、请描述Interface与抽象类之间的不同
这是几个基础C# 的概念。
参考 Java :
二十七、.Net与Mono的关系
mono 是 .net的一个开源跨平台工具,类似 java 的虚拟机,java本身不是跨平台语言,但虚拟机能实现跨平台。.net只能在 window 下运行,mono 可以实现跨平台,可运行在 linux,Unix,Mac OS 等。
二十八、Unity3d 中用于记录节点空间的几何信息的组件名称,以及父类名称
Transform 父类是 Component
二十九、向量的点乘、叉乘以及归一化的意义
高数知识:
- 点乘描述两个向量的相似程度,结果越大两向量越相似,还可以表示投影。
- 叉乘得到的向量垂直于原来的两个向量
- 标准化向量:用在只关心方向,不关心大小的时候
见:向量--快速回顾
三十、为何大家都在移动设备上寻求U3D原生GUI的替代方案
不美观,OnGUI耗时长,效率不高,使用不方便
推荐使用 UGUI(官方联系 NGUI 的开发者共同开发的 UGUI,更简易)
三十一、请简述如何在不同分辨率下保持ui的一致性
NGUI 很好的解决了此问题。
屏幕分辨率的自适应原理:计算出屏幕宽高比与原来的预设屏幕分辨率求出一个比值,随后修改摄像机的 size 。
UGUI通过锚点和中心点和分辨率也解决了此问题。
三十一、什么是LightMap
LightMap:就是指在三维软件里实现打好光,然后渲染把场景各表面的光照输出到贴图上,最后又通过引擎贴到场景上,这样就使物体有了光照的感觉。
三十二、C# 与 C++ 的区别
两者其实都是面向对象语言,不过其不同简单而言:
- C# 与 java 类似,是个完全的面向对象语言; C++ 是对 C语言的扩展,不是完全的面向对象语言。
- C# 基于 IL 中间语言和 .NET Framework CLR ,在可移植性,可维护性和强壮性都比 C++ 有很大改进。
- C# 的设计目的是用来快速开发稳定可扩展的应用程序。
三十三、结构体和类的区别
结构体是一种值类型(栈中),类是一种引用类型(堆中)。
在数据存储角度来讲,结构体类型用于存储数据的值,引用类型用于存储对实际数据的引用。
结构体当成值来使用,类则是引用来对实际数据操作。
C# 结构体和 C 语言相同,其性能较好,但是当结构体比较庞大时,则损失巨大。
三十四、ref 参数和 out 参数是什么,有什么区别
ref 和 out 效果一样,都是通过关键字找到定义在主函数里面的变量的内存地址,并通过方法体内的语法改变他的大小。简单看作是传递地址(引用传递,或地址传递,类似指针)。
不同:
- ref 需要先初始化,ref 的参数是引用
- out 不需要初始化,参数为输出参数
三十五、C# 委托
委托类似于一种安全的指针引用,在使用它时是当做类来看待而不是一个方法,相当于对一组方法的列表的引用。
用处:使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。
可参见: 浅谈C#委托机制
三十六、C#的排序方式有哪些
选择排序、冒泡排序、快速排序、插入排序、希尔排序、归并排序。
三十五、 射线检测碰撞物的原理
射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,就会停止发射。
三十六、Unity中照相机的 Clipping Planes 的作用是什么、调整 Near、Fare 两个值时,要注意什么
Clipping Planes:剪裁平面
从相机开始渲染和停止渲染之间的距离。
三十七、如何让已存在的 GameObject 在 LoadLevel (同步加载)后不被卸载掉
1 | void Awake(){ |
三十八、简述GC(垃圾回收)产生的原因,并描述如何避免?
产生原因:
在游戏运行时,数据主要存储在内存中,当游戏的数据在不需要的时候,存储当前数据的内存就会被回收以再利用。内存垃圾是指当前废弃数据所占的内存,垃圾回收(GC)是将废弃的内存重新回收再次使用。
unity 中将垃圾回收当作内存管理的一部分,如果游戏废弃数据占用大,则游戏性能会受到极大的影响,此时垃圾回收会成为游戏性能的一大障碍点。
内存回收机制十分耗时,尤其当废弃内存较大时。
避免:
- 减少 new 的使用。
- 适量使用公用对象(静态成员,常量),这些的生命周期是整个应用程序,可以避免被回收,但是不可滥用,太多则会占用过多的内存。
- 字符串使用 StringBuilder 。使用时必须前初始化。
- 使用对象池
三十九、反射的实现原理 *回头研究*\
审查元数据并收集关于它的类型信息的能力。。
原理: 在运行时根据程序集以及其中的类型得到元数据。
实现步骤:
- 导包
using System.Reflection
Assembly.Load("程序集")
加载程序集,返回一个 Assembly- 得到程序集中所有类的名称
1 | foreach(Type type in assembly.GetTypes()){ |
Type type = assembly.GetType("程序集.类名");
获取当前类的类型- 获取
1 | Activator.CreateInstance(type); // 创建此类型实例 |
四十、简述四元数的作用,四元数对欧拉角的优点
四元数用于表示旋转。
优点:
- 能进行增量旋转。
- 避免万向锁
- 给定位的表达方式有两种,互为负(欧拉角有无数种表达方式)
四十一、移动相机放哪个函数中,为什么
LateUpdate,因为其在 Update 之后调用,适合命令脚本的执行。可以防止相机抖动,比如相机已经移动但是角色还没移动。
四十二、GPU工作原理
GPU图像(处理)流水线(顺序不一定按以下顺序):
顶点处理: 这阶段GPU读取描述 3D 图形外观的顶点数据确定3D图形的形状及位置关系,建立起 3D 图形骨架。支持 DX 系列规格的 GPU 中,这些工作由硬件实现的 Vertex Shader (顶点着色器)完成。
光栅化计算: 显示器实际显示的图像时由像素组成的,我们需要将上面生成的图形点和线通过一点的算法转换到相应的像素点。*把一个矢量图转换成一系列像素点的过程就是光栅化 。
例如:一条数学表示的斜线段,最终被转化成阶梯状的连续像素点。
纹理贴图: 顶点单元生成的多边形之构成 3D 物体的轮廓,而纹理映射(texture mapping)工作完成对多边形表面的贴图。TMU(Texture mapping unit)用来完成此工作。
像素处理: 此阶段(对每个像素进行光栅化处理期间)GPU 完成对像素的计算和处理,从而确定每个像素的最终属性。在支持 DX8 和 DX9 规格的 GPU 中,这些工作由硬件实现的 Pixel Shader (像素着色器)完成。
最终输出: 由 ROP(光栅化引擎)最终完成像素的输出,1帧渲染完毕后,被送到显存帧缓冲区。
总结:GPU 工作通俗来讲时完成 3D 图形的生成,将图形映射到相应像素点上,对每个像素进行计算确定最终颜色并完成输出。
详见:GPU工作原理
四十三、什么是渲染管线
在显示器上为了显示出图像而经过一些列必要操作。
渲染管线由很多步骤,都要将几何图形从一个坐标中变换到另一个坐标系中。
主要步骤:
本地坐标 -> 视图坐标 -> 背面裁剪 -> 光照 -> 裁剪 -> 投影 -> 视图变换 -> 光栅化
或
物体空间 -> 世界空间 -> 观察空间 -> 裁剪空间 -> 屏幕空间
详见:渲染管线
四十四、如何优化内存
- 将暂时不用但以后会用的物体隐藏起来而不是直接 Destory 。
- 释放 AssetBundle 占用的资源。
- 降低模型的片面数,降低模型的骨骼数量,降低贴图大小。
- 使用光照贴图,使用多层次细节(LOD),使用着色器(Shader),使用预设(Prefab)。
- 代码中少的产生临时变量。
四十五、动态加载资源的方式,区别
Resources.Load();
- AssetBundle
区别
其实这与 Android 的两种读取资源方式类似。res与asset - Resources 是动态内部调用,读取 Resource 文件夹下的资源。Resources会把需要的资源打包到安装包中,那么在打包的时候就要检索内部资源比较费时。在进入app时,会加载res目录下的索引信息,会增加加载事件。由于 Resources 是被打包到包中,读取的内部资源,因此并不利于后期扩展,版本升级。往往 Resources 适用于长久不变且较小的资源。
- AssetBundle 是动态外部调用,需要将资源打包为 .assetblundle 文件。在调用资源时,只要读取存储在外部存储中的 bundle 包,十分便于后期扩展。但是在卸载或者更改 bundle 包时,可能会导致一些数据资源的丢失。
所以通常比较推荐使用 AssetBundle 加载方式。
四十六、描述游戏动画有哪几种,以及其原理
主要有关节动画,骨骼动画,单一网格模型动画(关键帧动画)。
关节动画:把角色分成若干独立部分,一个部分对应一个网格模型,部分的动画连接成一个整体的动画,角色比较灵活,Quake2中使用这种动画。
骨骼动画:广泛应用的动画方式,骨骼按角色特点组成一定的层次结构,有关节相连,可作相对运动,皮肤作为单一网格蒙在骨骼之外,决定角色的外观。
单一网格模型动画:由一个完整的网格模型构成,在动画序列的关键帧里记录各个顶点的原位置以及其改变量,然后插值运算实现动画效果,角色动画较真实。
四十七、Alpha Blend工作原理
Alpha Blend 实现透明效果,不过只能针对某块区域进行 alpha 操作,透明度可设置。
四十八、值类型和引用类型有何区别
- 值类型的数据存储在内存的栈中;引用类型的数据存储在内存的堆中,而内存单元中只存放堆中对象的地址。
- 值类型存取速度快,引用类型存取速度慢。
- 值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针或引用
- 值类型继承自System.ValueType,引用类型继承自System.Object
- 栈的内存分配是自动释放;而堆在.NET中会有GC来释放
- 值类型的变量直接存放实际的数据,而引用类型的变量存放的则是数据的地址,即对象的引用。
四十九、Shader
详细看博客文章。