Unity 面试题汇总(三)Unity 基础相关
目录
0、FSM(状态机)、HFSM(分层状态机)、BT(行为树)的区别
4、七:简述四元数Quaternion的作用,四元数对欧拉角的优点?
5、如何安全的在不同工程间安全地迁移asset数据?三种方法
6、OnEnable、Awake、Start运行时的发生顺序?哪些可能在同一个对象周期中反复的发生?
10、简述一下对象池,你觉得在FPS里哪些东西适合使用对象池?
11、CharacterController和Rigidbody的区别?
20、在物体发生碰撞的整个过程中,有几个阶段,分别列出对应的函数 三个阶段
21、Unity3d的物理引擎中,有几种施加力的方式,分别描述出来
24、Unity3d提供了一个用于保存和读取数据的类(PlayerPrefs),请列出保存和读取整形数据的函数
25、Unity3d脚本从唤醒到销毁有着一套比较完整的生命周期,请列出系统自带的几个重要的方法。
27、在场景中放置多个Camera并同时处于活动状态会发生什么?
28、如何销毁一个UnityEngine.Object及其子类?
30、请描述为什么Unity3d中会发生在组件上出现数据丢失的情况
39、Unity3D是否支持写成多线程程序?如果支持的话需要注意什么?
41、U3D中用于记录节点空间几何信息的组件名称,及其父类名称
46、当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?
47、请简述OnBecameVisible及OnBecameInvisible的发生时机,以及这一对回调函数的意义?
56、八十三:Unity中,照相机的Clipping Planes的作用是什么?调整Near、Fare两个值时,应该注意什么?
57、如何在Unity3D中查看场景的面试,顶点数和Draw Call数?如何降低Draw Call数?
61、将Camera组件的ClearFlags选项选成Depth only是什么意思?有何用处?
62、如何让已经存在的GameObject在LoadLevel后不被卸载掉?
63、在编辑场景时将GameObject设置为Static有何作用?
64、有A和B两组物体,有什么办法能够保证A组物体永远比B组物体先渲染?
65、将图片的TextureType选项分别选为Texture和Sprite有什么区别
66、问一个Terrain,分别贴3张,4张,5张地表贴图,渲染速度有什么区别?为什么?
67、什么是DrawCall?DrawCall高了又什么影响?如何降低DrawCall?
69、Unity的Shader中,Blend SrcAlpha OneMinusSrcAlpha这句话是什么意思?
0、FSM(状态机)、HFSM(分层状态机)、BT(行为树)的区别
游戏人工智能AI中最常听见的就是这三个词拉:
1)FSM
这个不用说拉,百度一大堆解释,
简单将就是将游戏AI行为分为一个一个的状态,状态与状态之间的过渡通过事件的触发来形成。
比如士兵的行为有“巡逻”,“追击敌人”,“攻击敌人”,“逃跑”等行为,
响应的事件就有“发现敌人”,“追到敌人”,“敌人逃跑”,“敌人死亡”,“自己血量不足”等。
那么可以写成这样一个状态机:
1.士兵 “巡逻”,如果 “发现敌人”,那么,“追击敌人”
2.士兵 “追击敌人”, 如果 “追到敌人”, 那么,“攻击敌人”
3.士兵 “追击敌人”, 如果 “敌人死亡”, 那么,继续 “巡逻”
4.士兵 “攻击敌人”, 如果 “敌人死亡”, 那么,继续 “巡逻”
5.士兵 “攻击敌人”, 如果 “血量不足”, 那么,“逃跑”
其中,士兵就是这个FSM的执行者,红色的就是状态,蓝色的就是事件,
整个状态机的行为可以总结为:
当前状态=>是否满足条件1,如果是,则跳转到对应状态
否则=>是否满足条件2,如果是,则跳转到对应状态
由此可看出,状态机是一种“事件触发型”AI,就是只有事件的触发才会发生引起状态的变化。
2)HFSM
简单来说,就是FSM当状态太多的时候,不好维护,于是将状态分类,抽离出来,将同类型的
状态做为一个状态机,然后再做一个大的状态机,来维护这些子状态机。
举个决策小狗行为的例子:
我们对小狗定义了有很多行为,比如跑,吃饭,睡觉,咆哮,撒娇,摇尾巴等等,如果每个行为都是一个状态,
用常规状态机的话,我们就需要在这些状态间定义跳转,比如在“跑”的状态下,如果累了,那就跳转到“睡觉”状态,
再如,在“撒娇”的状态下,如果感到有威胁,那就跳转到“咆哮”的状态等等,我们会考量每一个状态间的关系,定
义所有的跳转链接,建立这样一个状态机。如果用层次化的状态机的话,我们就先会把这些行为“分类”,把几个小状
态归并到一个状态里,然后再定义高层状态和高层状态中内部小状态的跳转链接。
其实层次化状态机从某种程度上,就是限制了状态机的跳转,而且状态内的状态是不需要关心外部状态的跳转的,
这样也做到了无关状态间的隔离,比如对于小狗来说,我们可以把小狗的状态先定义为疲劳,开心,愤怒,然后这些
状态里再定义小状态,比如在开心的状态中,有撒桥,摇尾巴等小状态,这样我们在外部只需要关心三个状态的跳
转(疲劳,开心,愤怒),在每个状态的内部只需要关心自己的小状态的跳转就可以了。这样就大大的降低了状态机的复杂度,
另外,如果觉得两层的状态机还是状态太多的话,可以定义更多的状态层次以降低跳转链接数。
(摘自此文章)

3)Behavir Tree
谈到游戏AI,很明显智能体拥有的知识条目越多,便显得更智能,但维护
庞大数量的知识条目是个噩梦:使用有限状态机(FSM),分层有限状态机(HFSM),
决策树(Decision Tree)来实现游戏AI总有那么些不顺意。
试试Next-Gen AI的行为树(Behavior Tree)吧。
虽说Next-Gen AI,但距其原型提出已有约10年时间,而微软Halo系列估计
已用了超过8年了,Spore和一些著名游戏也早已使用行为树作为它们的AI结构。
如从未接触,那wikipedia(http://en.wikipedia.org/wiki/Behavior_Trees)
绝对是入门好资料。
先借用网上的一张图来诠释下行为树到底是怎么样的

———————————————————————
行为树(Behavior Tree)具有如下的特性:
它只有4大类型的Node:
* Composite Node 组合节点
* Decorator Node 修饰节点
* Condition Node 条件节点(叶节点)
* Action Node 动作节点(叶节点)
任何Node被执行后,必须向其Parent Node报告执行结果:成功 / 失败。
这简单的成功 / 失败汇报原则被很巧妙地用于控制整棵树的决策方向。
———————————————————————
先看Composite Node,其实它按复合性质还可以细分为3种:
* Selector Node
当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:
如遇到一个Child Node执行后返回True,那停止迭代,
本Node向自己的Parent Node也返回True;否则所有Child Node都返回False,
那本Node向自己的Parent Node返回False。
* Sequence Node
当执行本类型Node时,它将从begin到end迭代执行自己的Child Node:
如遇到一个Child Node执行后返回False,那停止迭代,
本Node向自己的Parent Node也返回False;否则所有Child Node都返回True,
那本Node向自己的Parent Node返回True。
* Parallel Node
并发执行它的所有Child Node。
而向Parent Node返回的值和Parallel Node所采取的具体策略相关:
Parallel Selector Node: 一False则返回False,全True才返回True。
Parallel Sequence Node: 一True则返回True,全False才返回False。
Parallel Hybird Node: 指定数量的Child Node返回True或False后才决定结果。
Parallel Node提供了并发,提高性能。
不需要像Selector/Sequence那样预判哪个Child Node应摆前,哪个应摆后,
常见情况是:
(1)用于并行多棵Action子树。
(2)在Parallel Node下挂一棵子树,并挂上多个Condition Node,
以提供实时性和性能。
Parallel Node增加性能和方便性的同时,也增加实现和维护复杂度。
PS:上面的Selector/Sequence准确来说是Liner Selector/Liner Sequence。
AI术语中称为strictly-order:按既定先后顺序迭代。
Selector和Sequence可以进一步提供非线性迭代的加权随机变种。
Weight Random Selector提供每次执行不同的First True Child Node的可能。
Weight Random Sequence则提供每次不同的迭代顺序。
AI术语中称为partial-order,能使AI避免总出现可预期的结果。
———————————————————————
再看Decorator Node,它的功能正如它的字面意思:它将它的Child Node执行
后返回的结果值做额外处理后,再返回给它的Parent Node。很有些AOP的味道。
比如Decorator Not/Decorator FailUtil/Decorator Counter/Decorator Time…
更geek的有Decorator Log/Decorator Ani/Decorator Nothing…
———————————————————————
然后是很直白的Condition Node,它仅当满足Condition时返回True。
———————————————————————
最后看Action Node,它完成具体的一次(或一个step)的行为,视需求返回值。
而当行为需要分step/Node间进行时,可引入Blackboard进行简单数据交互。
———————————————————————
整棵行为树中,只有Condition Node和Action Node才能成为Leaf Node,而也
只有Leaf Node才是需要特别定制的Node;Composite Node和Decorator Node均
用于控制行为树中的决策走向。(所以有些资料中也统称Condition Node和Action
Node为Behavior Node,而Composite Node和Decorator Node为Decider Node。)
更强大的是可以加入Stimulus和Impulse,通过Precondition来判断masks开关。
通过上述的各种Nodes几乎可以实现所有的决策控制:if, while, and, or,
not, counter, time, random, weight random, util…
———————————————————————
总的来说,行为树具有如下几种优点,确实是实现AI框架的利器,甚至是一种
通用的可维护的复杂流程管理利器:
> 静态性
越复杂的功能越需要简单的基础,否则最后连自己都玩不过来。
静态是使用行为树需要非常着重的一个要点:即使系统需要某些”动态”性。
其实诸如Stimulus这类动态安插的Node看似强大,
但却破坏了本来易于理解的静态性,弊大于利。
Halo3相对于Halo2对BT AI的一个改进就是去除Stimulus的动态性。
取而代之的做法是使用Behavior Masks,Encounter Attitude,Inhibitions。
原则就是保持全部Node静态,只是根据事件和环境来检查是否启用Node。
静态性直接带来的好处就是整棵树的规划无需再运行时动态调整,为很多优化
和预编辑都带来方便。
> 直观性
行为树可以方便地把复杂的AI知识条目组织得非常直观。
默认的Composite Node的从begin往end的Child Node迭代方式就像是处理一个
预设优先策略队列,也非常符合人类的正常思考模式:先最优再次优。
行为树编辑器对优秀的程序员来说也是唾手可得。
> 复用性
各种Node,包括Leaf Node,可复用性都极高。
实现NPC AI的个性区别甚至可以通过在一棵共用的行为树上不同的位置来
安插Impulse来达到目的。
当然,当NPC需要一个完全不同的大脑,比如70级大BOSS,
与其绞尽脑汁在一棵公用BT安插Impulse,不如重头设计一棵专属BT。
> 扩展性
虽然上述Node之间的组合和搭配使用几乎覆盖所有AI需求。
但也可以容易地为项目量身定做新的Composite Node或Decorator Node。
还可以积累一个项目相关的Node Lib,长远来说非常有价值。
--- 补充
每个节点都应该有以下三种状态:
Running,
Success,
Failed
Running状态用于表明该节点的结果不能立刻获知,比如游戏中的角色进行“向目标移动”
这个动作,很显然这个动作不能在这一帧中立刻完成,当行为树运行到此节点时,并不能
获知是success或者failed,于是返回running,表示该节点正在运行中,并记录此节点
的位置,下一帧运行到此节点的父节点时,则从此节点继续运行,跳过之前的节点。

有限状态机:可用于做任务动画的切换,也可用于做简单的AI。将行为分为一个个的状态,状态与状态之间的过渡通过事件的触发来形成。
分层有限状态机:简单说,就是状态太多时,不好维护,于是将状态分类,将同类的状态作为一个状态机,然后再做一个大的状态机,来维护这些子状态机。
行为树:行为树与FSM不同,它是一种“轮询式机制”,即每次更新都会遍历树,判定逻辑是否成立,是否该继续往下执行。常用于英雄或敌方等有多种复杂行为的单位。如下图:
1、什么是协同程序?
答:在主线程运行时同时开启另一段逻辑处理,来协助当前程序的执行。换句话说,开启协程就是开启一个可以与程序并行的逻辑。可以用来控制运动、序列以及对象的行为。
协程的三种启动/停止方式:
1)StartCoroutine(string method);
2)StartCoroutine(Coroutine routine);
3)StartCoroutine(IEnumrator routine);
启动依次对应停止方式,不然,可能不生效
1)StopCoroutine(string method);
2)StopCoroutine(Coroutine routine);
3)StopCoroutine(IEnumrator routine);
例如:IEnumerator Test(){....}
1)StartCoroutine(“Test”); => StopCoroutine(“Test”);
2)Coroutine routine= Test();
StartCoroutine(routine); => StopCoroutine(routine)
3)IEnumrator routine = StartCoroutine(Test());
=> StopCoroutine(routine );
注意:其他的情况
1)禁用启动协程的脚本,是无法停止协程的;
2)禁用启动协程的脚本挂载的GameObject ,是可以停止协程的
3)销毁启动协程的脚本,是可以停止协程的
4)销毁启动协程的脚本挂载的GameObject ,是可以停止协程的
5)协程依赖 MonoBehaviour
6)协程返回值一般只能是 IEnumrator
7)可能存在回调地狱 (注意 async 、await 异步)
2、Unity3D中的碰撞器和触发器的区别?
答:碰撞器是触发器的载体,而触发器只是碰撞器身上的一个属性。
当Is Trigger=false时,碰撞器根据物理引擎引发碰撞,产生碰撞的效果,可以调用OnCollisionEnter/Stay/Exit函数;
当Is Trigger=true时,碰撞器被物理引擎所忽略,没有碰撞效果,可以调用OnTriggerEnter/Stay/Exit函数。
如果既要检测到物体的接触又不想让碰撞检测影响物体移动或要检测一个物件是否经过空间中的某个区域这时就可以用到触发器。
3、物体发生碰撞的必要条件?
答:两个物体都必须带有碰撞器Collider,其中一个物体还必须带有Rigidbody刚体。
4、七:简述四元数Quaternion的作用,四元数对欧拉角的优点?
答:四元数用于表示旋转
相对欧拉角的优点:能进行增量旋转、避免万向锁、给定方位的表达方式有两种,互为负(欧拉角有无数种表达方式)
5、如何安全的在不同工程间安全地迁移asset数据?三种方法
答: 1.将Assets和Library一起迁移 2.导出包package 3.用unity自带的assets Server功能
6、OnEnable、Awake、Start运行时的发生顺序?哪些可能在同一个对象周期中反复的发生?
答:Awake–>OnEnable->Start,OnEnable在同一周期中可以反复地发生!
7、MeshRender中material和sharedmaterial的区别?
答:修改sharedMaterial将改变所有物体使用这个材质的外观,并且也改变储存在工程里的材质设置。 不推荐修改由sharedMaterial返回的材质。如果你想修改渲染器的材质,使用material替代。
8、TCP/IP协议栈各个层次及分别的功能?
答:网络接口层:这是协议栈的最低层,对应OSI的物理层和数据链路层,主要完成数据帧的实际发送和接收。
网络层:处理分组在网络中的活动,例如路由选择和转发等,这一层主要包括IP协议、ARP、ICMP协议等。
传输层:主要功能是提供应用程序之间的通信,这一层主要是TCP/UDP协议。
应用层:用来处理特定的应用,针对不同的应用提供了不同的协议,例如进行文件传输时用到的FTP协议,发送email用到的SMTP等。
9、Unity提供了几种光源,分别是什么?
答: 四种。 平行光:Directional Light 点光源:Point Light 聚光灯:Spot Light 区域光源:Area Light
10、简述一下对象池,你觉得在FPS里哪些东西适合使用对象池?
对象池就存放需要被反复调用资源的一个空间,比如游戏中要常被大量复制的对象,子弹,敌人,以及任何重复出现的对象。
11、CharacterController和Rigidbody的区别?
Rigidbody具有完全真实物理的特性,而CharacterController可以说是受限的的Rigidbody,具有一定的物理效果但不是完全真实的。
12、移动相机动作在哪个函数里,为什么在这个函数里?
LateUpdate,是在所有的Update结束后才调用,比较适合用于命令脚本的执行。官网上例子是摄像机的跟随,都是所有的Update操作完才进行摄像机的跟进,不然就有可能出现摄像机已经推进了,但是视角里还未有角色的空帧出现。
13、简述prefab的用处
在游戏运行时实例化,prefab相当于一个模板,对你已经有的素材、脚本、参数做一个默认的配置,以便于以后的修改,同事prefab打包的内容简化了导出的操作,便于团队的交流。
14、GPU的工作原理?
简而言之,GPU的图形(处理)流水线完成如下的工作:(并不一定是按照如下顺序)。
顶点处理:这阶段GPU读取描述3D图形外观的顶点数据并根据顶点数据确定3D图形的形状及位置关系,建立起3D图形的骨架。在支持DX8和DX9规格的GPU中,这些工作由硬件实现的Vertex Shader(定点着色器)完成。
光栅化计算:显示器实际显示的图像是由像素组成的,我们需要将上面生成的图形上的点和线通过一定的算法转换到相应的像素点。把一个矢量图形转换为一系列像素点的过程就称为光栅化。例如,一条数学表示的斜线段,最终被转化成阶梯状的连续像素点。
纹理帖图:顶点单元生成的多边形只构成了3D物体的轮廓,而纹理映射(texture mapping)工作完成对多变形表面的帖图,通俗的说,就是将多边形的表面贴上相应的图片,从而生成“真实”的图形。TMU(Texture mapping unit)即是用来完成此项工作。
像素处理:这阶段(在对每个像素进行光栅化处理期间)GPU完成对像素的计算和处理,从而确定每个像素的最终属性。在支持DX8和DX9规格的GPU中,这些工作由硬件实现的Pixel Shader(像素着色器)完成。
最终输出:由ROP(光栅化引擎)最终完成像素的输出,1帧渲染完毕后,被送到显存帧缓冲区。
总结:GPU的工作通俗的来说就是完成3D图形的生成,将图形映射到相应的像素点上,对每个像素进行计算确定最终颜色并完成输出。
15、什么是渲染管道?
答:是指在显示器上为了显示出图像而经过的一系列必要操作。 渲染管道中的很多步骤,都要将几何物体从一个坐标系中变换到另一个坐标系中去。
主要步骤有: 本地坐标->视图坐标->背面裁剪->光照->裁剪->投影->视图变换->光栅化。
16、如何优化内存?
答:有很多种方式,例如
1.压缩自带类库;
2.将暂时不用的以后还需要使用的物体隐藏起来而不是直接Destroy掉;
3.释放AssetBundle占用的资源;
4.降低模型的片面数,降低模型的骨骼数量,降低贴图的大小;
5.使用光照贴图,使用多层次细节(LOD),使用着色器(Shader),使用预设(Prefab)
6.代码中少产生临时变量
18、动态加载资源的方式?
1.Resources.Load(); 2.AssetBundle
Unity5.1版本后可以选择使用Git: https://github.com/applexiaohao/LOAssetFramework.git
19、 使用Unity3d实现2d游戏,有几种方式?
答: 1.使用本身的GUI、UGUI
2.把摄像机的Projection(投影)值调为Orthographic(正交投影),不考虑z轴;
3.使用2d插件,如:2DToolKit、NGUI
20、在物体发生碰撞的整个过程中,有几个阶段,分别列出对应的函数 三个阶段
答:OnCollisionEnter、 OnCollisionStay、 OnCollisionExit
21、Unity3d的物理引擎中,有几种施加力的方式,分别描述出来
答:rigidbody.AddForce、 rigidbody.AddForceAtPosition
22、什么叫做链条关节?
答:Hinge Joint,可以模拟两个物体间用一根链条连接在一起的情况,能保持两个物体在一个固定距离内部相互移动而不产生作用力,但是达到固定距离后就会产生拉力。
23、物体自身旋转使用的函数?
答: Transform.Rotate()
24、Unity3d提供了一个用于保存和读取数据的类(PlayerPrefs),请列出保存和读取整形数据的函数
答:PlayerPrefs.SetInt()、 PlayerPrefs.GetInt()

本文详细介绍了Unity3D中的关键概念和技术,包括状态机(FSM、HFSM、BT)、协同程序、碰撞器与触发器的区别、四元数的作用以及内存优化方法。此外,还探讨了Unity3D的渲染管道、光照计算、对象池、对象销毁、光照贴图(LOD)和渲染优化策略。通过对这些核心技术的理解,开发者可以更好地实现高效的游戏开发。
1万+

被折叠的 条评论
为什么被折叠?



