Unity 之 动态加载物体卡顿简析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Czhenya/article/details/95350273

Unity 之 动态加载物体卡顿简析

最近做Unity优化的时候发现游戏在第一次动态加载物体的时候会有卡顿,不管是加载一个大的预制体还是加载很对小的预制体,都有这个的情况出现,困扰良久。终于找到了问题的原因和几个注意事项,和大家分享一下,若有不足,敬请指正。



首先来看一段我们经常写的代码:加载一个游戏对象,将其实例化,并且添加脚本。
void StartLoad () {
  		GameObject go = Resources.Load("Image") as GameObject;
  		GameObject obj = GameObject.Instantiate(go);
  		obj.AddComponent<AddTest>();
  }
你觉得上面三行代码,哪一行最耗时呢?我一直都认为是实例化(Instantiate)这个步骤最耗时,可是当我将其耗时分离开打印出来的时候才发现,第一次加载时耗时最大的却是加载游戏对象(Resources),,,而且差距还很大几倍到十几倍不等。

Unity的加载截图:

pc


我的手机截图android


上面结果的实践部分代码

【代码中这个 Image 预制体有90个带有Image组件的子物体,我这边添加的是一个空脚本,文章下面后面会说代码的耗时问题】
using System.Diagnostics;
using UnityEngine;
using UnityEngine.UI;

public class LoadGameObjectTest : MonoBehaviour {

    public Text showText;
    int count = 1;

	void StartLoad () {

        Stopwatch sw_Res = new Stopwatch();
        sw_Res.Start();
        GameObject go = Resources.Load("Image") as GameObject;
        sw_Res.Stop();
        showText.text += "\n";
        showText.text += "\n <color=red>>>第" + count + "次 Resources 耗时:" + sw_Res.Elapsed.TotalMilliseconds + "毫秒</color>";
        UnityEngine.Debug.Log("<color=red>>>第" + count+"次 Resources 耗时:" + sw_Res.Elapsed.TotalMilliseconds + "毫秒</color>");

        Stopwatch sw_Ins = new Stopwatch();
        sw_Ins.Start();
        GameObject obj = GameObject.Instantiate(go);
        sw_Ins.Stop();
        showText.text += "\n <color=yellow>>>第" + count + "次 Instantiate 耗时:" + sw_Ins.Elapsed.TotalMilliseconds + "毫秒</color>";
        UnityEngine.Debug.Log("<color=yellow>>>第" + count + "次 Instantiate 耗时:" + sw_Ins.Elapsed.TotalMilliseconds + "毫秒</color>");

        Stopwatch sw_Add = new Stopwatch();
        sw_Add.Start();
        obj.AddComponent<AddTest>();
        sw_Add.Stop();
        showText.text += "\n <color=green>>>第" + count + "次 AddComponent 耗时:" + sw_Add.Elapsed.TotalMilliseconds + "毫秒</color>";
        UnityEngine.Debug.Log("<color=green>>>第" + count + "次 AddComponent 耗时:" + sw_Add.Elapsed.TotalMilliseconds + "毫秒</color>");

        count++;
    }
    void OnGUI()
    {
        if (GUI.Button(new Rect(100, 100, 100, 80), "加载按钮"))
        {
            StartLoad();
        }

    }
}


结论以及要注意的点

Resources.Load:是一个”同步”耗时操作,Unity 中的资源是共享的,相当于程序中的引用类型的变量,不管你去Load几次指向的资源都是同一个,也就是说Unity不会重复加载资源,这也是当加载同一游戏对象时,只是第一次加载,后面的加载都是’假’的,,,所以,当重复Load同样的资源只会指向同一段内存,也不会增加开销。


Instantiate :目前没有找到可以优化的点,不过它的速度远比我曾经对他的理解要快很多,现在这样是可以满足需求。


AddComponent :动态添加脚本和脚本直接挂载到预制体上被加载出来,其实是一样的。

脚本耗时主要是因为在OnEnable,Awake中代码执行的逻辑和初始化,或者是代码中Public的对象太多,而这些对象又全部都是在Inspector面板上拖拽赋值的,所以加载时才会卡。

解决办法:将不必要的初始化放到Start中去写,就可以了。已经亲测过来,从打印的时间来看差距还是比较大的。(当然这个差距还是针对第一次而言,后面的话没有很大区别)


综合上述基本可以解决一下加载卡顿的问题了。建议使用对象池,通过使用:显示、不使用:隐藏 的形式减少对同一物体的重复加载、实例化的问题。



都看到这里了,不想说说你的看法吗?欢迎留言评论哦!


来自的avi9111评论:再次感谢分享@avi9111 【博客地址:https://me.csdn.net/avi9111】

有一些偏方是,是先setActive(false),Instantiate后才SetActive(true),可以避免onEnable,onAwake造成的影响,不过这个问题在编辑器才是问题,手机上问题不大(unity强制压30帧,也就是功耗高的都压不见了),而且如果做端游,PC版也不需要考虑这个问题,唯一优化的就是做成异步,入口也是通过先SetActive(false),让UnityEngine可以歇一歇,然后OnAwake, Onenable里面的方法都使用异步执行,不过这样开发效率低,也不稳定(结论还是要统一在框架里处理,好调试,好扩展,好维护,项目做久了肯定框架要维护好,前提是要有经验的人)

猜你喜欢

转载自blog.csdn.net/Czhenya/article/details/95350273