Unity3D 优化相关

     抛砖引玉:

  http://www.luzexi.com/unity3d%E4%BC%98%E5%8C%96%E4%B9%8B%E8%B7%AF/

关于图片

一、Unity3D自身会把导入的图片进行压缩,这些压缩不仅体现在内存上,而且也体现在包大小。

  测试如下,相同的图片,压缩后的大小:

  

    

     打包的大小分别对应如下:可以看到差别很大。

   

  2014-12-30:

    这里貌似 有个 误解:

    我重新做了 这个 实验,1024 * 1024 RGBA 32 png  图片 与 1024 * 1024 RGB 8 jpg  图片 分别对应 不同的 压缩格式 并且 压缩的大小也不同。但是出来的包竟然神奇的是一样的。我无语了…………上图

    

 

    

二、如果一堆PreFab,被多个场景静态引用,和被多个场景动态引用,导出的大小差别不大。这里做个测试

  

   

   根据图片顺序分别给出对应的包:可以看到,虽然有差别,但是不是很大,估计是静态引用本身需要一些资源吧。

    

三、图片不引用则不会加到包里

  如果你加了一堆图片进到工程中,如果你对其不引用,那么你的的图片就不会加到工程中,必须要在这里吐槽一点,Unity3D就算一个空白工程也会有一个7M的APK,表示无语。

  没有任何图片资源的工程

  

  有图片资源的工程

  

 

关于脚本

 一、有时候你打开一个按钮,弹出一个界面预设,如果这个界面携带很多资源,那么在生成的时候就会有点慢,这样给用户的感觉就是按下按钮 过了一会才会弹出那个界面。

 

  这种情况需要异步加载,使用协程,最好不要自己使用协程加载界面,因为自己使用协程的话,那么只能在最后Destroy 自己,不然自己销毁后协程就消失了。

      这样一来有两个问题。

      一、在最后destroy 的之前,你 需要 额外做一段动画 来 保证与用户的交互。不然用户按下之后,你开着协程生成界面,自己又不消失,交互很不好。

      二、

  我们看这一段代码

 

 1     public GameObject go;
 2 
 3 
 4     float curTime;
 5 
 6     IEnumerator Test()
 7     {
 8         curTime = Time.realtimeSinceStartup;
 9 
10         GameObject newgo = Instantiate(go) as GameObject;
11 
12         float delta = Time.realtimeSinceStartup - curTime;
13         Debug.Log("Instantiate Use Time : " + delta);
14 
15         yield return new WaitForSeconds(0.3f);
16 
17         Destroy(transform.root.gameObject);
18     }
19 
20 
21     void OnDestroy()
22     {
23         Debug.Log("OnDestroy" + transform.name);
24     }
25 
26 
27     void OnGUI()
28     {
29         if (GUI.Button(new Rect(10, 10, 150, 100), "I am a button")) StartCoroutine(Test());
30     }

 

 

 

     相信我们都很清楚u3d 事件调用序列顺序,我们可以看到Instantiate 的时候 会把这个 生成物体 下的 Awake OnEnable 全部 执行一遍。

并且 原物体 的Destroy 是会在下一个轮回中进行的,是在 新生成物体 的Start之后。

 

这样一来,如果 原物体 是UIRoot的话,UIRoot 有一个

static public List<UIRoot> list = new List<UIRoot>(); 在新物体生成时候 list保存了 原物体新物体 的两个UIRoot的引用。

list 在 新物体 Start 的时候进行 会全部 进行 scale 调整。

这个scale 调整是会把 原物体 新物体 都调整一遍,如果你的 新物体 生成比较快 并且 调用了 yield return new waitforseconds 之后才 销毁 原物体 , 你就会发现 原物体 卡一下的情况(因为此时还没有真正Destroy)。

  2015-1-13 如果 每次 OnEnable 的时候  return, list 永远是空的。这个 时候 第二个UIROOT生成 如果此时第一个UIROOt 还没有销毁的话 还是会出现卡一下的情况,看来不是list的问题。

      当然也可以因为 界面生成 花费的时间长,这样一来可能新物体 uiroot start 的 时刻 已经 超过了 yield return new waitforseconds 的 时刻。 此时 原物体 已经 destroy 了。也就不会出现卡一下的 原因了。但是这个时间不好掌握,所以还是不推荐了。

      当然你也可以说干嘛不干脆一个 UIRoot 算了,原物体 与  新物体 都是这个一个 UIRoot 的子物体不就没事了。没错,这样一来是可以的,但是还没有解决第一个问题。

  

  看到上述 2个 原因,那么我们可以明白 原物体 不能在最后 destroy 自己。可是又要使用协程,那么 我们就使用一个专门的UIManager 类来进行协程管理生成UI, 这里 UIManager 负责所有的 UI 物体的 生成 与 销毁。 先 Destroy 原物体, 再 开协程 一个个生成 新UI。用户只会看到自己按下后界面消失,至于界面的产生慢0.几秒是感觉不到的,(你也可以做一个tween传入,让产生慢一点的界面快一会传入,产生快一点慢一点传入,让用户错觉是都是产生都是差不多的,只要速度接近就行了。)

  当然最好 都是 UIRoot 的 子物体,这样防止 每一个 新UI 因为都携带一个 UIRoot ,start 的 时候 都会 导致 scale 重新调整一遍。

  

 

     另外,我建议用缓冲机制 setActive 代替 instantiage/destroy .(第一次除外,必须要用instantiate),这样一来最好都是一个UIRoot 的子物体,不然父物体使用destroy ,而子物体使用setactive 就冲突了。如果 全局都是 一个UIRoot ,那么我们destroy 与  setactive 都是 那一个uiroot 的 子物体,不会引发冲突。

    另外模块对其的调用也可以统一,其他模块只需要调用 UIManager 的 Create(UIId id) 这个接口就可以了。内部到底是缓冲机制 还是 destroy 完全由自己维护。

 

  总结一下,就是两点,

  一、最好就是一个UIRoot ,所有新的UI都是其子物体。

      二、就是 大 界面的 生成,使用协程,但是 不要 自己 使用 协程,交给uimanager 管理,这样可以先销毁自己,再生成新的ui。

 

posted @ 2014-07-14 20:04  灵魂重新  阅读(601)  评论(0编辑  收藏  举报