您好,欢迎来到Unity之家!   unity.jb51.net 
  • 首 页
  • 你问我答
  • 当前位置:首页 > 学习培训 > Unity编程 >
    Unity3D编程规范
    时间:2015-04-21 08:57 来源:互联网 作者:脚印 浏览:收藏 挑错 推荐 打印


    C#脚本规范:

    一:变量小写字母开头:int passWord = 123456;

    二:函数大写字母开头:void GetPassWord();

    三:函数参数以"_" + 小写字母开头: void SetPassWord(int _passWord);

    四:变量、属性、枚举、声明写最前面。


    Unity3D的性能优化:


    一.缓存组件查找

    另一个优化是组件缓存。这种优化需要一些代码并且不是总有必要。

    但是如果你的代码真的很大,并且你需要尽可能的性能提升,它会是很好的优化。

    当你通过GetComponent获取一个组件或一个变量时,Unity必须从游戏物体里找到正确的组件。

    这时你便能通过一个缓存组件引用到一个私有变量。

    将:


    void Update ()
    {
        transform.Translate(0,0, 5);
    }


    转换为:


    private Transform myTransform ;
    
    void Awake ()
    {
        myTransform =transform;
    }
    void Update ()
    {
        myTransform.Translate(0,0, 5);
    }


    后面的代码运行较快,因为Unity不用在每一帧寻找变换组件。

    同样,支持脚本组件。你可以使用GetComponent获取组件或其他快捷属性。



    二.如果没有必要不要调用函数


    1.最简单,最好的优化是执行最少的工作。如,当一个敌人在远处时,让他处于睡眠状态,大多时候是可行的。直到玩家靠近,可以这样处理:


    void Update ()
    {
    // Early out if the player is too far away.
    if (Vector3.Distance(transform.position, target.position)> 100)
    return;
    perform real work work...
    }


    这并不是很好的方法,虽然Unity不得不在每一帧访问update函数。更好的方法是禁用这个行为直到玩家靠近。有3中方法做这个:使用 OnBecameVisible和OnBecameInvisible。这些调用与渲染系统相联系。一旦摄像机看到物体,OnBecameVisible 将被调用,不看他时,OnBecameInvisible被调用。这有时很有用。但是对于AI来讲通常是没有用的,因为你背转敌人,敌人就变成不可用了。


    void OnBecameVisible () {
    enabled = true;
    }
    void OnBecameInvisible ()
    {
    enabled = false;
    }

     

    2.使用触发器。一个简单的球形触发器能引发惊人效果。你可以调用OnTriggerEnter/Exit,当进入你想要的作用范围。


    void OnTriggerEnter (c : Collider)
    {
    if (c.CompareTag("Player"))
    enabled = true;
    }
    void OnTriggerExit (c : Collider)
    {
    if (c.CompareTag("Player"))
    enabled = false;
    }


    3.使用协同程序。Update的问题是他在每帧都发生。很可能只需要5秒钟检查一次玩家的距离。这可以节约大量的处理周期。




    三、遇到麻烦时要调用“垃圾回收器”(Garbage Collector,无用单元收集程序,以下简称GC)


    由于具有C/C++游戏编程背景,我们并不习惯无用单元收集程序的特定行为。确保自动清理你不用的内存,这种做法在刚开始时很好,但很快你就公发现自己的分析器经常显示CPU负荷过大,原因是垃圾回收器正在收集垃圾内存。这对移动设备来说尤其是个大问题。要跟进内存分配,并尽量避免它们成为优先数,以下是我们应该采取的主要操作:

    1.移除代码中的任何字符串连接,因为这会给GC留下大量垃圾。

    2.用简单的“for”循环代替“foreach”循环。由于某些原因,每个“foreach”循环的每次迭代会生成24字节的垃圾内存。一个简单的循环迭代10次就可以留下240字节的垃圾内存。

    3.更改我们检查游戏对象标签的方法。用“if(go.CompareTag (“Enemy”)”来代替“if (go.tag == “Enemy”)”。在一个内部循环调用对象分配的标签属性以及拷贝额外内存,这是一个非常糟糕的做法。

    4.对象库很棒,我们为所有动态游戏对象制作和使用库,这样在游戏运行时间内不会动态分配任何东西,不需要的时候所有东西反向循环到库中。

    5.不使用LINQ命令,因为它们一般会分配中间缓器,而这很容易生成垃圾内存。


    四、减少DrawCall


         Unity(或者说基本所有图形引擎)生成一帧画面的处理过程大致可以这样简化描述:引擎首先经过简单的可见性测试,确定摄像机可以看到的物体,然后把这些物体的顶点(包括本地位置、法线、UV等),索引(顶点如何组成三角形),变换(就是物体的位置、旋转、缩放、以及摄像机位置等),相关光源,纹理,渲染方式(由材质/Shader决定)等数据准备好,然后通知图形API——或者就简单地看作是通知GPU——开始绘制,GPU基于这些数据,经过一系列运算,在屏幕上画出成千上万的三角形,最终构成一幅图像。

    在Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call。这一过程是逐个物体进行的,对于每个物体,不只GPU的渲染,引擎重新设置材质/Shader也是一项非常耗时的操作。因此每帧的Draw Call次数是一项非常重要的性能指标,对于iOS来说应尽量控制在20次以内,这个值可以在编辑器的Statistic窗口看到。

    Unity内置了Draw CallBatching技术,从名字就可以看出,它的主要目标就是在一次Draw Call中批量处理多个物体。只要物体的变换和材质相同,GPU就可以按完全相同的方式进行处理,即可以把它们放在一个Draw Call中。Draw Call Batching技术的核心就是在可见性测试之后,检查所有要绘制的物体的材质,把相同材质的分为一组(一个Batch),然后把它们组合成一个物体(统一变换),这样就可以在一个Draw Call中处理多个物体了(实际上是组合后的一个物体)。

    但Draw Call Batching存在一个缺陷,就是它需要把一个Batch中的所有物体组合到一起,相当于创建了一个与这些物体加起来一样大的物体,与此同时就需要分配相应大小的内存。这不仅会消耗更多内存,还需要消耗CPU时间。特别是对于移动的物体,每一帧都得重新进行组合,这就需要进行一些权衡,否则得不偿失。但对于静止不动的物体来说,只需要进行一次组合,之后就可以一直使用,效率要高得多。

    Unity提供了Dynamic Batching和StaticBatching两种方式。Dynamic Batching是完全自动进行的,不需要也无法进行任何干预,对于顶点数在300以内的可移动物体,只要使用相同的材质,就会组成Batch。Static Batching则需要把静止的物体标记为Static,然后无论大小,都会组成Batch。如前文所说,Static Batching显然比Dynamic Batching要高效得多,于是,Static Batching功能是收费的……

    要有效利用Draw Call Batching,首先是尽量减少场景中使用的材质数量,即尽量共享材质,对于仅纹理不同的材质可以把纹理组合到一张更大的纹理中(称为Texture Atlasing)。然后是把不会移动的物体标记为Static。此外还可以通过CombineChildren脚本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手动把物体组合在一起,但这个脚本会影响可见性测试,因为组合在一起的物体始终会被看作一个物体,从而会增加GPU要处理的几何体数量,因此要小心使用。

    对于复杂的静态场景,还可以考虑自行设计遮挡剔除算法,减少可见的物体数量同时也可以减少Draw Call。

    总之,理解Draw Call和Draw Call Batching原理,根据场景特点设计相应的方案来尽量减少Draw Call次数才是王道,其它方面亦然。


    其他:

    1.      尽量减少在Awake和Start里有复杂的运算,尽量减少开方运算。

    2.      避免使用GameObject.Find 迫不得已用GameObject.FindGameObjectWithTag代替



    (责任编辑:脚印)
    免责声明:Unity之家部分内容来源于互联网,如有侵权,请联系我们,本站将立即进行处理。
    标签:Unity之家