Unity 异步加载场景

异步

C# 异步

因为同步进程会出现阻塞的情况,为了避免卡顿,以及在处理数据时仍然可以接收用户新的访问,异步的思想就出现了

异步可以理解为,在调用异步函数的时候,函数会直接返回,然后剩下的部分等同于在一个新线程中运行

异步操作的关键字是asnycawait,当一个方法具有 async 的签名时, 它会向编译器发出信号,说明此方法包含 await 语句;也包含异步操作。

windows官方定义:

异步操作后跟同步操作的这种组合是一个异步操作。 换言之,如果操作的任何部分是异步的,整个操作就是异步的。

Unity 异步

Unity还提供了一系列的异步操作,方便大家根据需要进行选择。这些异步操作包括Resources的加载、场景的加载、Asset Bundle的加载、NavMesh的生成等等。当然,这些异步操作的底层实现各不相同。有些是独立线程处理的,有些则是利用Unity内部的JobSystem,也有一些是二者结合使用的。

在Unity中使用协程搭配异步来写代码更佳,例如通过异步加载场景,在加载过程中通过每帧更新进度条给予玩家一个反馈,就可以在协程中调用异步加载场景的方法,然后暂停协程,等待当前一帧结束,然后更新进度条,反复之后,就完成进度条显示进度加载场景的效果。

这里有四点需要注意:

  1. 首先创建一个unity自定义AsyncOperation类的对象,来承接unity异步加载场景的返回值,这里的返回值就是刚才的那个AsyncOperation类,作用是管理异步加载的进度,以及操控加载完毕后场景是否显示
  2. 通过yield return new WaitForEndOfFrame()达到协程的一个暂停,不然很快进度条就跑过去了,可能这个时候场景数据还没有加载完
  3. 异步加载场景函数调用一次就好,调用多次的话,出现bug先不说,如果所要加载的场景特别大的话,估计CPU就报废了(开个玩笑),所以在调用完异步之后,要做一个标记,循环再进来之后不进入异步的语句
  4. 因为加载场景,有可能在进度条还没有走完之前,场景就加载好了,所以要保证场景加载完毕之后场景不显示,需要用到ao.allowSceneActivation = false;语句,当然,在进度条加载完成之后,调用ao.allowSceneActivation = true;语句显示所加载的场景。但这种想法终归是有点赌的成分在,在加载大场景的时候,很可能进度条到了100,但是场景才加载了一部分,所以加载大场景的时候,可以选择使用异步给到的progress来获取当前场景加载进度,这样比较好把握。但是问题又来了,Unity通常会加载到89%便不会更新progress,但是此时场景已经加载完毕,所以再加一个循环使进度条到达100

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class LoadScene : MonoBehaviour
{
    public string loadingSceneName;
    private Button btn;
    public Text loadingProcess;
    private void Awake()
    {
        btn = GetComponent<Button>();
        btn.onClick.AddListener(SceneShow);
    }
    void SceneShow()
    {
        StartCoroutine("Show"); // 协程手动开启,手动关闭
    }
    IEnumerator Show()
    {
        AsyncOperation async = SceneManager.LoadSceneAsync(loadingSceneName);
        async.allowSceneActivation = false;
        float displayProgress = 0;
        float toProgress = 100f;

        // 加载小场景可以使用这个循环即可
        //while (displayProgress < toProgress)
        //{
        //    displayProgress++;
        //    TextShow(displayProgress);
        //    yield return new WaitForEndOfFrame();
        //}

        // 加载大场景使用这两个循环
        while (displayProgress < 90f)
        {
            displayProgress = async.progress * 100;
            Debug.Log("第一个循环" + displayProgress);
            TextShow(displayProgress);
            yield return new WaitForEndOfFrame();
        }
        // Unity通常会加载到89%便会卡顿,此时场景已经加载完毕
        while (displayProgress < toProgress)
        {
            displayProgress++;
            Debug.Log("第二个循环" + displayProgress);
            TextShow(displayProgress);
            yield return new WaitForEndOfFrame();
        }
        //激活已经加载的场景
        async.allowSceneActivation = true;
        StopCoroutine("Show");
    }
    void TextShow(float displayProgress)
    {
        if (displayProgress >= 100f)
            displayProgress = 100f; // 确保进度条不会显示大于100的数
        loadingProcess.text = displayProgress.ToString("F2") + "%";
    }
}

  • 14
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Unity中,你可以使用异步加载场景的方法来避免在切换场景时的卡顿或停顿。下面是一个示例代码,展示了如何使用异步加载场景: ```csharp using UnityEngine; using UnityEngine.SceneManagement; using System.Collections; public class SceneLoader : MonoBehaviour { public string sceneName; // 要加载场景名字 public void LoadSceneAsync() { StartCoroutine(LoadSceneAsyncCoroutine()); } IEnumerator LoadSceneAsyncCoroutine() { // 异步加载场景 AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName); // 等待场景加载完成 while (!asyncLoad.isDone) { // 可以在这里显示加载进度或执行其他操作 float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f); // 异步加载的进度范围为0-0.9 Debug.Log("Loading progress: " + (progress * 100) + "%"); yield return null; } } } ``` 在上述代码中,我们首先定义了一个`LoadSceneAsync`方法来启动异步加载场景的过程。然后,在`LoadSceneAsyncCoroutine`协程中,我们使用`SceneManager.LoadSceneAsync`方法来异步加载指定的场景。 使用`AsyncOperation`对象可以获取加载进度,将其归一化为0-1的范围,并在需要时进行显示或其他操作。注意,在异步加载的过程中,进度会达到0.9,因此我们使用`Mathf.Clamp01`来将进度限制在0-0.9之间。 最后,使用`yield return null`来等待一帧的时间,然后再次循环检查加载进度。当加载进度达到1时,表示场景加载完成。 你可以在需要异步加载场景的地方调用`LoadSceneAsync`方法,这样就可以在切换场景时避免卡顿或停顿。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值