飞道的博客

Unity面试题整理(一)

650人阅读  评论(0)

内容网上搜集,旨在记录整理Unity的面试题,为面试做好准备。白底黑字看的太难受了,加点颜色

目录

AssetBundle基本理论

AssetBundle资源加载框架设计

Awake()和Start区别

Csharp属性访问器

Profile性能优化基础

SerializeField的用法

UGUI事件系统

UGUI渲染层级

UI框架设计

Unity5如何进行AssetBundle

Unity中Update和FixUpdate和LateUpdate

Unity事件管理器


 

AssetBundle基本理论

最简单的AssetBundle打包方式:

  • Unity需要加载模型经常需要AssetBundle

  • 在Unity中载入模型的最简单的方式就是:直接将模型文件放到工程目录下,然后拖进场景之中。
  • 但是我们需要在程序运行时将网络或者任意目录下的模型加载到场景之中,name我们只能自己编写解析模型的脚本
  • Unity没有提供加载模型的API,或者是没有开放给用户 。。。

Unity中模型文件大多是.prefab,加载prefab的方式只有两个:

  • Resource.Load,需要将prefab放到Resource目录下
  • AssetDatabase.LoadAssetAtPath ,文件必须放在Assets目录下,即网络和其他文件夹下prefab无法加载

这时,assetBundle发挥除了很大用处。通过WWW加载AssetBundle。接下来的问题就是如何打包AssertBundle,利用
public static AssetBundleManifest BuildAssetBundles
(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform);

在Editor文件夹下创建脚本,放入脚本,这时才会出现AssetBundle选项

AssetBundle功能开发好后,怎么用呢???


AssetBundle需要对资源进行分组:

 按逻辑实体进行分组: 

  • 一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
  • 一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
  • 所有的场景所共享的部分一个包(包括贴图和模型)

按资源类型分组:

  •   所有声音资源打成一个包
  •   所有shader打成一个包
  •   所有模型打成一个包
  •   所有材质打成一个包

按照使用分组:

  •   把需要同时加载的资源或者某一时间内使用的所有资源打成一个包。
  •   可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。
  •   也可以按照场景分,一个场景所需要的资源一个包。

解包:


  
  1. IEnumerator LoadBundle(string url)
  2. {
  3.   WWW www = new WWW(url);
  4.   yield return www;
  5.   
  6.   if(www.error != null)
  7.   {
  8.     Debug.LogError();
  9.     yield break;
  10.   }
  11. }

资料:
实力封装:Unity打包AssetBundle(番外篇)
http://实力封装:Unity打包AssetBundle(二)
实力封装:Unity打包AssetBundle(一)


AssetBundle资源加载框架设计

目的:

  • 便于增量更新功能的实现
  • 降低安装包大小,unity不支持过滤到Resources目录下的不用的文件
  • 用AB包加快资源文件读取速度

生成AssetBundle文件的基本流程:

  • 所有需要打包成为AB包的资源放到BundleResources目录下,按照一定规则存放
  • 便利BundleResources目录,。根据一定规则,给不同的文件或者目录孵育一个AssetLabels
  • 打包,输出目录为StreamingAssets
  • 打包,遍历后生成的manifest信息,获取每个AB包的包名,根据依赖的AB包的HASH值,输出到一个JSON文件

资料

unity 资源加载框架设计


Awake()和Start区别


Awake()Monobehaviour创建后立刻被调用,Start()MonoBehaviour创建后在该帧update前执行。


  
  1. void Awake()
  2. {
  3.   //初始化函数,主要用来创建变量
  4.   //不可执行协同程序
  5. }
  6. void Start()
  7. {
  8. }

Awake方法的调用顺序在object之间时随机的,当所有对象的Awake方法都调用完成后,才会执行第一个Start方法,Awake方法就像构造函数一样,Awake方法不论脚本是否启用,都会调用


Csharp属性访问器

类成员包括变量和方法,希望其他类访问成员变量,则定义为共有public,那么这个成员变量就可随意访问,但是不利于数据安全性。

c#通过属性特性读取和写入字段【成员变量】,而非直接读取和写入,借此提供对类中字段的保护,属性作为c#面相对象技术中封装性的体现。

属性和字段的区别:

  • 属性作为逻辑字段,是字段的扩展,不占用实际的内存
  • 属性可以被其他类访问,而非public字段不能直接访问
  • 属性可以对接受的数据在范围上做限定,但是字段不能

使用属性的情况:

  • 要求字段只读或只写
  • 需要限制字段取值范围
  • 在改变一个字段的值时希望改变对象的其他状态


使用字段的情况:

  • 允许自由读写
  • 取值范围只受到数据类型约束而无其他任何限制
  • 值变动不引发类中其他成员的变化

设计字段是为了便于内部方法使用,而尽量与外界隔绝;设计属性考虑的是方便外界的使用,但是不让外界知道的数据一律不给。


Profile性能优化基础

Profile介绍:
CPU:

      A. WaitForTargetFPS
            Vsync(垂直同步)功能所,即显示当前帧的CPU等待时间 
      B. Overhead: 
            Profiler总体时间-所有单项的记录时间总和。用于记录尚不明确的时间消耗,以帮助进一步完善Profiler的统计。 
      C. Physics.Simulate: 
            当前帧物理模拟的CPU占用时间。 
      D. Camera.Render: 
            相机渲染准备工作的CPU占用量 
      E. RenderTexture.SetActive: 
            设置RenderTexture操作. 
            底层实现:

  •    比对当前帧与前一帧的ColorSurfaceDepthSurface
  •    如果这两个Buffer一致则不生成新的RT,否则则生成新的RT,并设置与之相对应的Viewport和空间转换矩阵. 

      F. Monobeaviour.OnMouse_ : 
            用于检测鼠标的输入消息接收和反馈,主要包括:SendMouseEvents和DoSendMouseEvents。(只要Edtor开起来,这个就会存在) 
      G. HandleUtility.SetViewInfo: 
            仅用于Editor中,作用是将GUI和Editor中的显示看起来与发布版本的显示一致。 
      H. GUI.Repaint: 
            GUI的重绘(说明在有使用原生的OnGUI) 
      I. Event.Internal_MakeMasterEventCurrent: 
            负责GUI的消息传送 
      J. Cleanup Unused Cached Data: 
            清空无用的缓存数据,主要包括RenderBuffer的垃圾回收和TextRendering的垃圾回收。 

  • RenderTexture.GarbageCollectTemporary:存在于RenderBuffer的垃圾回收中,清除临时的FreeTexture
  • TextRendering.Cleanup:TextMesh的垃圾回收操作

      K. Application.Integrate Assets in Background: 
            遍历预加载的线程队列并完成加载,同时,完成纹理的加载、SubstanceUpdate等. 
      L. Application.LoadLevelAsync Integrate: 
            加载场景的CPU占用,通常如果此项时间长的话70%的可能是Texture过长导致. 
      M. UnloadScene: 
            卸载场景中的GameObjectsComponentGameManager,一般用在切换场景时. 
      N. CollectGameObjectObjects: 
            执行上面M项的同时,会将场景中的GameObjectComponent聚集到一个Array中.然后执行下面的Destroy. 
      O. Destroy: 
            删除GameObject和Component的CPU占用. 
      P. AssetBundle.LoadAsync Integrate: 
            多线程加载AwakeQueue中的内容,即多线程执行资源的AwakeFromLoad函数. 
      Q. Loading.AwakeFromLoad: 
            在资源被加载后调用,对每种资源进行与其对应用处理.
      
GPU:

   A. Device.Present: 
      device.PresentFrame的耗时显示,该选项出现在发布版本中. 
   B. Graphics.PresentAndSync: 
      GPU上的显示和垂直同步耗时.该选项出现在发布版本中. 
   C. Mesh.DrawVBO: 
      GPU中关于MeshVertex Buffer Object的渲染耗时. 
   D. Shader.Parse: 
      资源加入后引擎对Shader的解析过程. 
   E. Shader.CreateGPUProgram: 
      根据当前设备支持的图形库来建立GPU工程.        

Memory Profiler:

   A. Used Total: 
      当前帧的Unity内存、Mono内存、GfxDriver内存、Profiler内存的总和. 
   B. Reserved Total: 
      系统在当前帧的申请内存. 
   C. Total System Memory Usage
      当前帧的虚拟内存使用量.(通常是我们当前使用内存的1.5~3倍) 
   D. GameObjects in Scene: 
      当前帧场景中的GameObject数量. 
   E. Total Objects in Scene: 
      当前帧场景中的Object数量(除GameObject外,还有Component等). 
   F. Total Object Count: 
      Object数据 + Asset数量.

Detail Memory Profiler:

  A. Assets
      Texture2d:记录当前帧内存中所使用的纹理资源情况,包括各种GameObject的纹理、天空盒纹理以及场景中所用的Lightmap资源. 
   B. Scene Memory: 
      记录当前场景中各个方面的内存占用情况,包括GameObject、所用资源、各种组件以及GameManager等(天般情况通过AssetBundle加载的不会显示在这里). 
   C. Other: 
      ManagedHeap.UseSize:代码在运行时造成的堆内存分配,表示上次GC到目前为止所分配的堆内存量. 
      SerializedFile(3): 
      WebStream:这个是由WWW来进行加载的内存占用. 
      System.ExecutableAndDlls:不同平台和不同硬件得到的值会不一样。     

优化的关键点:

   A. CPU-GC Allow: 
      关注原则:1.检测任何一次性内存分配大于2KB的选项 2.检测每帧都具有20B以上内存分配的选项. 
   B. Time ms: 
      记录游戏运行时每帧CPU占用(特别注意占用5ms以上的). 
   C. Memory Profiler-Other: 

  • ManagedHeap.UsedSize: 移动游戏建议不要超过20MB. 
  • SerializedFile: 通过异步加载(LoadFromCache、WWW等)的时候留下的序列化文件,可监视是否被卸载. 
  • WebStream: 通过异步WWW下载的资源文件在内存中的解压版本,比SerializedFile大几倍或几十倍,重点监视.**** 

   D. Memory Profiler-Assets: 

  • Texture2D: 重点检查是否有重复资源和超大Memory是否需要压缩等. 
  • AnimationClip: 重点检查是否有重复资源. 
  • Mesh: 重点检查是否有重复资源.

SerializeField的用法

如果a是公有的序列化变量。

  • 如果你想要在面板中看到变量a,那么用:                   
public int a;
  • 如果你不想在面板中看到变量a,那么用:

  
  1. [ HideInInspector]
  2.                     public int a;

这样a可以在程序中被代码赋值,但不会在面板中看到,也不能手动设置赋值。

 

  • 如果a是私有的序列化变量,你想在面板中读取并赋值,那么用:

  
  1. [ SerializeField]
  2.               private int a;
  • 如果a是私有的序列化变量,你想在面板中读取,但是不赋值,那么用:       

  
  1.     [ HideInInspector][SerializedField]
  2.             private int a;
  3.             public int b
  4.             {
  5.                 get{ return a;}
  6.             }
  7.             
  •  如果a是私有序列化变量,你不想在面板中做任何操作(不想看到,也不想写),但是想要在程序中给它赋值,那么用。

  
  1. [ HideInInspector][SerializedField]
  2.             private int a;
  3.             public int b
  4.             {
  5.                 get{ return a;}
  6.                 set{a = value;}
  7.             }

UGUI事件系统


Unity UGUI的可触发事件系统:

  • PointerEnter:  

  • PointerExit:

  • PointerDown:

  • PointUp:

  • PointClick:

  • Drag:

  • Drop:

  • Scroll:

  • UpdateSelected:

  • Select:

  • Deselect:

  • Move:

继承基础接口实现:

创建ClickObject脚本,继承MonoBehaviourPointerClickHander


  
  1. public ClickObject : MonoBehaviour,IPointerClickHandelr{
  2. void Start(){
  3. }
  4. void Update(){
  5. }
  6. public void OnPointerClick(PointerEventData eventData){
  7.   Debug.Log( "click");
  8. }
  9. }

实现public void OnPointerClick(PointerEventData eventData)

创建名为 Panel_IPointer的空白对象,并且把ClickObject脚本挂在对象上

启动。点击Panel_IPointer对象,Console输出   

Unity3D编辑器操作设置实现:

Button提供OnClick操作,实现事件

步骤一:创建c#脚本,添加OnTestClick()
步骤二:创建Empty对象,接受和响应点击事件,创建名为Panel的UI对象,于触发点击事件。
步骤三:Panel对象添加EventTrigger组件," Add New" -> 选择" PointerClick"。
Empty对象拖拽到触发者位置。然后点击"No Function"选择我们写在Test脚本中的OnTestClick事件。
 


UGUI渲染层级

Unity中的渲染顺序自上而下大致分为三层。 分别是Camera - > Sorting Layer - > Sorting order
最高层为Camera层,可以在Cameradepth那里设置,设置之后,图形的渲染顺序就是先绘制depth低的相机下的物体,
再绘制depth高的相机下的物体,也就是说,depth高的相机会覆盖depth低的相机(具体的覆盖关系有don't clear, solid color等等几种)
UGUI渲染模式:Canvas -- Render Mode:ScreenSpace-Overlay

此模式下不依赖摄像机Camera的渲染

Hierachy下存在各层级遮挡,

  • 不同CameraDepth。(大在前,小在后)
  • CameraSortingLayer。(下在前,上在后)
  • SortingLayer下的Order in Layer。(大在前,小在后)
  • Order in Layer下的Z轴。(小在前,大在后)

改变控件之间的层级关系
同一canvas下:

  •      改变控件transformSiblingIndex,
  •      transform.GetSiblingIndex();
  •      transform.SetSiblingIndex(int index); //index值越大,越后渲染,层级越大,越显示在前面

不同Canvas下:
    设置Canvas下的Sort Order //Sort Order值越大,越后渲染,层级越大,越显示在前面
渲染顺序与hierarchy面板里物体的摆放顺序也有关
面板里越靠上的物体越先被渲染,越后被渲染的显示在越前面。

注意:

如果是多个Canvas的渲染先后顺序 看这里
调Canvas下面有一个Sort Order值,默认为0,越大越在后面。
 
创建任意UGUI元素时自动生成一个Canvas物体,Canvas下的所有物体从上往下渲染,即排在下面的会遮盖排上面的。同理,子元素会覆盖父元素。

在游戏运行中如何修改UGUI的显示层级?
在代码中调整该元素的层级位:使用RectTransform类的函数。

  •    SetAsFirstSibling:移动到所有兄弟节点的第一个位置(Hierarchy同级最上面,先渲染,显示在最下面)
  •    SetAsLastSibling:移动到所有兄弟节点的最后一个位置(Hierarchy同级最下面,后渲染,显示在最上面)
  •    GetSiblingIndex:获得该元素在当前兄弟节点层级的位置
  •    SetSiblingIndex:设置该元素在当前兄弟节点层级的位置


Canvas的渲染模式【Render Mode】:ScreenSpace Overlay,ScreenSpace Camera,World Space
ScreenSpace-Overlay:

  • OverLay模式,永远覆盖在其他物体之上。出现在最上面。不受摄像机的Depth值影响
  • 有多个摄像机时,由摄像机的Depth值决定
  • 只有一个摄像机时,由距离和方向决定World模式和Camera模式、它们的渲染结果 可前、可后、可穿插。ScreenSpace-Camera:

1.遵循刷油漆规则
2.依次由Render CameraDepth值、Sorting  Layer先后顺序、Order in Layer值决定 
Render Camera不同时,由Render CameraDepth决定
Render Camera相同时,由Sorting Layer先后顺序决定
Render Camera相同时,Sorting Layer相同,由Order in Layer值决定。


UI框架设计


UI框架的设计:

UI框架用于管理场景中的所有面板,控制面板之间的切换,加快开发进度,提高代码质量。【主要在于管理面板】

实现思路:

  • 进入状态:界面第一次动态加载被使用【】
  • 暂停状态:切换到其他界面的时候
  • 继续状态:重新回到界面的时候
  • 退出状态:界面不显示的时候

实现步骤:

  • 使用JSON保存面板路径,枚举保存面板类型
  • 根据界面的四种状态,创建UI基类BasePanel,场景界面继承该类。将四种状态写作虚方法,分别为OnEnter(),OnPause(),OnResume(),OnExit()
  • 通过管理类UIManager,解析JSON,管理UI界面的加载和切换。方便调用,做成单例模式,分别从两个字典保存从JSON读取面板信息和已动态加载实例化的面板,通过栈实现面板之间的切换。


缺点明显,使用栈用来存储场景中依次打开的界面,只能够依次从栈顶界面开始关闭。

OnEnter()->OnPause()->OnResume()->OnExit()

UI框架类图: 
UIPanelType :存储面板路径和类型
UIManager : 

  •   panelPathDict:Dictionary<UIPanelType,String>
  •   panelDict:Dictionary<UIPanelType,BasePanel>
  •   panelStack:Stack<BasePanel>

BasePanel:


Unity5如何进行AssetBundle


开始创建一个AssetBundle,从项目文件夹中选择一个想要的自愿的对象,

Inspector检查器的底部是AssetBundle菜单,

  • 从第一个下拉框中选择或者设置AssetBundles的名称,
  • 第二个下案例框是附加选项。


如果资源是第一次打包,请不要设置第二个附加选项,否则打包报错。

默认情况下,AssetBundle名称设置为None,这意味着资源不能进行AssetBundle打包。
如果还没有定义包,单机new.输入包名。这样可以创建一个或者多个AssetBundle


Unity中Update和FixUpdate和LateUpdate

FixedUpdate () 和 Update () :

Monobehaviour激活后,在每一帧被调用,实现更新。

Update()每一帧的时间不固定,即第一帧与第二帧的时间t1和第三帧与第四帧的时间t2不一定相同。FixedUpdate()每帧与每帧之间相差的时间是固定的.

FixUpdate是按照帧进行更新的。

通常


  
  1. FixedUpdate()
  2. {
  3.   i++;
  4.   time += Time.deltaTime;
  5.   Debug.Log(“这是第”);
  6. }

Unity事件管理器


c#语言本身具有一个事件管理器event delegate,为何需要自己建立事件管理器??虽然不是必须,
但是c#的delegate本质是回调函数。因为回调函数是双向引用关系,而事件管理器就是为了让游戏内部逻辑
的类和类之间的关系结构变成单向引用关系,是类和类之间的降低耦合度,大都是通过事件类型【字符串】进行内部沟通。


EventManager事件管理器:


主要函数:添加监听,移除监听,调度事件
主要变量:事件list,事件结构,回调委托

 


  
  1. MyEvent:事件类型:
  2. public class MyEvent{
  3. private EventType type;
  4. private string content;
  5. }
  6. public enum EventType{
  7. EVENT_0 = "UI"
  8. //。。。。
  9. }
  10. public class EventManager : MonoBehaviour{
  11. private Dictionary< string,UnityEvent> eventDictionary; //字典  
  12. }

资料:

基于Unity3d SendMessage实现事件管理器

Unity 3D 教你打造自己的EventSystem(事件总线)

EventsSystems(Unity3D)事件系统

Unity3D游戏开发框架-消息机制

Unity3D游戏框架设计3——事件机制、模块

改了几次发现找不到原文地址,特此说明本文为转载。


转载:https://blog.csdn.net/a1191835397/article/details/96474984
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场