概述
Unity 之 动态加载物体卡顿简析
最近做Unity优化的时候发现游戏在第一次动态加载物体的时候会有卡顿,不管是加载一个大的预制体还是加载很对小的预制体,都有这个的情况出现,困扰良久。终于找到了问题的原因和几个注意事项,和大家分享一下,若有不足,敬请指正。
首先来看一段我们经常写的代码:加载一个游戏对象,将其实例化,并且添加脚本。
void StartLoad () {
GameObject go = Resources.Load("Image") as GameObject;
GameObject obj = GameObject.Instantiate(go);
obj.AddComponent<AddTest>();
}
你觉得上面三行代码,哪一行最耗时呢?我一直都认为是实例化(Instantiate)这个步骤最耗时,可是当我将其耗时分离开打印出来的时候才发现,第一次加载时耗时最大的却是加载游戏对象(Resources),,,而且差距还很大几倍到十几倍不等。
Unity的加载截图:
我的手机截图
上面结果的实践部分代码
【代码中这个 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
有一些偏方是,是先setActive(false),Instantiate后才SetActive(true),可以避免onEnable,onAwake造成的影响,不过这个问题在编辑器才是问题,手机上问题不大(unity强制压30帧,也就是功耗高的都压不见了),而且如果做端游,PC版也不需要考虑这个问题,唯一优化的就是做成异步,入口也是通过先SetActive(false),让UnityEngine可以歇一歇,然后OnAwake, Onenable里面的方法都使用异步执行,不过这样开发效率低,也不稳定(结论还是要统一在框架里处理,好调试,好扩展,好维护,项目做久了肯定框架要维护好,前提是要有经验的人)
最后
以上就是幽默烧鹅为你收集整理的Unity 之 动态加载物体卡顿简析的全部内容,希望文章能够帮你解决Unity 之 动态加载物体卡顿简析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复