Unity Loading界面 协程中异步加载场景出现卡顿问题求助

在start函数中执行IEnumerator协程函数.

在协程函数中异步加载场景 AsyncOperation op=SceneManager.LoadSceneAsync(),并设置op.allowSceneActivation = false使场景加载完毕后不立即显示,此时op.progress最多加载到90%,等op.allowSceneActivation = true后op.progress再加载后10%.

问题是:op=SceneManager.LoadSceneAsync()这句会导致Loaing界面的卡顿(打印消息和特效粒子都卡住很久才显示).

求助:我希望能避免这个卡顿(毕竟异步和协程就是为了减少卡顿的,但它还是卡),所以我怀疑可能是我没用好协程和异步,导致异步没有生效.有没有知道原理的大神,求大神解说以下,或者推荐一下比较有用的文章.(还是说异步只能把卡顿转移到某一个画面,要想完全不显示卡顿,只能用静态界面.)

资料:

1.我查看了一些文章,有些说异步LoadSceneAsync()并非真正的后台载入,它在每一帧载入一些游戏资源,并给出一个progress值,所以在载入的时候还是会造成游戏卡顿.基于此原理,我觉得我的异步可能并没有生效,因为它在一开始就卡顿很久.(而后面进度条显示由于写了延时器所以都比较流畅.)

2.资源会在start函数开始时加载,如果没有分包,它的加载流量是虎头蛇尾的形式,它会在第一帧就能加载多少就加载多少,多到导致卡顿.(这就是我这个问题的真正原因).

3.关于协程IEnumerator,并不是异步,即使使用了协程,其实还是单线程(因为Unity基本上都是单线程,若出现多线程会导致Unity很多原生功能出现线程不安全的问题),只不过把中间帧抽出来做另一个任务,所以实质是还是同步.

4.我还发现在异步加载时,Unity编辑器暂停也不管用,后台会继续执行异步内容(Loaing界面是暂停的),异步加载完后还会自动转场景.(异步一旦开始是不是就无法停止了)

5.降低异步加载优先级,使Application.backgroundLoadingPriority = ThreadPriority.Low,尽量不影响帧率.异步加载包括:资源.LoadAsync/AssetBundle.LoadAssetAsync/AssetBundle.LoadAllAssetAsync, 场景sceneManager.LoadSceneAsync.

6.Unity官方专家给的解释:

在 Unity 中实例化操作(Instantiate),以及资源的初始化(如 Texture.AwakeFromLoad/Shader.Parse)等都不是异步的,会导致主线程的卡顿。Application.LoadLevelAsync 同样会在 Load 操作完成后自动进行资源的初始化和物件的实例化。在这个过程里就无法保持当前的帧率了。

因此,能否提供一下具体的 profiler 截图,看加载中卡在了什么地方,如果第二帧就加载完,很可能是在第一帧里就已经完成了 load 操作,而第二帧里是在做实例化等卡住主线程的操作。

 

 

我现在没办法解决这个问题,所以一开始就把进度先从0随机显示某一个位置,并结合几秒延迟创建异步加载场景,播放一会儿粒子效果,假装是加载过程中随机的卡顿,而不是创建异步的卡顿.(但我明白这治标不治本)

顺便说一下我是怎么测出"op=SceneManager.LoadSceneAsync()"这句会导致卡顿的,因为我把它放到哪里哪里就卡.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Loading : MonoBehaviour
{
    public Slider m_Slider;
    public Text m_Text;
    private ParticleSystem particle;
    private AsyncOperation op =null;
    private int startShowProgess=5;
    void Awake()
    {
        particle=GameObject.Find("Particle").GetComponent<ParticleSystem>();
        particle.Play();
    }
    void Start()
    {
        SetLoadingPercentage(startShowProgess);
        StartCoroutine(loadScene());                    //该协程会导致加载卡顿
    }
    string GetLoadName()
    {
        string loadName="";
        GameObject LevelRecordCreater=GameObject.Find("LevelRecordCreater");
        if (LevelRecordCreater)
        {

            int nowlevel=LevelRecordCreater.GetComponent<levelUpdata>().level;
            if (nowlevel == 1)
            {
                loadName = "level1";
            }
            if (nowlevel == 2)
            {
                loadName = "level2";
            }
            if (nowlevel == 3)
            {
                loadName = "level3";
            }
        }
        return loadName;
    }
    IEnumerator loadScene()
    {
        yield return new WaitForEndOfFrame();               //加上这么一句就可以先显示加载画面然后再进行加载
        int displayProgress = startShowProgess;
        int toProgress = (int)(Random.value*88);            //假随机卡在某个数
        //假进度前88%
        while (displayProgress < toProgress)
        {
            SetLoadingPercentage(++displayProgress);
            yield return new WaitForEndOfFrame();
        }
        yield return new WaitForSeconds(3);                 //把卡顿推后,假装是进度中的,防止一开始玩家就跑了<过半理论>
        op = SceneManager.LoadSceneAsync(GetLoadName());    //这个创建还是会导致卡顿
        op.allowSceneActivation = false;
        //真进度后88%~90%
        while (op.progress < 0.9f)                          //op.allowSceneActivation = true至前,op.progress最大值为0.9
        {
            toProgress = (int)op.progress * 100;
            while (displayProgress < toProgress)
            {
                SetLoadingPercentage(++displayProgress);
                yield return new WaitForEndOfFrame();
            }
        }
        //假进度后90%~100%
        toProgress = 100;
        while (displayProgress < toProgress)
        {
            SetLoadingPercentage(++displayProgress);
            yield return new WaitForEndOfFrame();
        }
        op.allowSceneActivation = true;
    }
    void SetLoadingPercentage(int sliderProgress)
    {
        m_Slider.value = sliderProgress * 0.01f;
        m_Text.text = "加载资源 "+sliderProgress.ToString() + "%";
    }
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值