Unity--异步加载场景

Unity–异步加载场景

异步加载场景其实和异步加载资源是一样的,只是加载的内容比较特殊而已. 也可以将场景视为特殊资源.

1.SceneManager.LoadScene

加载场景的方式,在Unity 中加载场景是通过SceneManager.LoadScene("场景名称"); 来实现加载场景,这和UE4中的OpenLevel也是一样的. 其中SceneManager是untiy中自带的场景管理器,可以用于加载场景,卸载场景等.需要引入using UnityEngine.SceneManagement才能使用

2.同步加载场景

和资源一样,场景默认是同步加载的,也就是直接使用SceneManager.LoadScene("场景名称")来实现同步加载. 如果一个场景中的资源比较多,比如:游戏模型,粒子特效等,那么就会导致加载场景时候卡顿,很久才能加载场景.

需要注意的是,它会立即切换到新场景,这可能导致短暂的冻结或卡顿,特别是在加载较大或资源密集的场景时…为了解决这个问题,我们一般使用异步加载. 减轻主线程的压力.

3.异步加载场景

和异步加载资源一样,场景的异步加载也是有两个过程: 加载中与加载完成.

异步加载的重要性:异步加载(LoadSceneAsync)允许场景在后台加载,这样主线程可以继续处理其他任务,如更新UI、处理玩家输入等。这对于提高用户体验至关重要,特别是在资源密集型游戏中。

仔细分析就是因为资源过大,内容过多导致加载中的时间过长,我们一般的设计方式就是进度条,加载完毕一段内容,进度条走了20%或者其他.直到加载完毕才走到100%,当然这个进度条有可能是假的.

在Unity中异步加载场景的写法如下:使用异步加载关键 + 加载完毕的回调函数

/// <summary>
/// 普通异步加载场景 + 调用回调函数
/// </summary>
/// <param name="scenenName">场景名称</param>
void LoadSceneAsychonized(string sceneName)
{
    // 加载场景
    AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
    operation.completed += LoadSceneCompleted;
}

其中SceneManager.LoadSceneAsync(sceneName);sceneName就是我们要加载的场景名称. 返回值是一个异步加载操作的对象AsyncOperation .和上面将的一样,加载场景有两个状态:加载中与加载完毕.

AsyncOperation对象:其中AsyncOperation operation就是记录了场景是否加载完毕isDown,没有加载完毕就是在加载中. 当场景处于加载中,我们就能获取场景的加载进度progress, 优先级priority以及当场景准备好了就激活场景allowSceneActivation. 还有加载完毕的回调函数completed.
AsyncOperation对象:这是异步加载的核心。它提供了加载进度(progress)、是否完成(isDone)等重要信息。通过这些属性,可以创建进度条或执行其他加载相关的逻辑。

属性/方法含义
isDown是否加载完成
progress场景的加载进度0-1的值,Unity很多时候是0.9,这个值准确
priority优先级
allowSceneActivation收否在场景准备好了就激活场景
completed加载完毕的回到函数

以下是AsyncOperationC#中的代码

namespace UnityEngine
{
    //
    // 摘要:
    //     Asynchronous operation coroutine.
    [NativeHeader("Runtime/Export/Scripting/AsyncOperation.bindings.h")]
    [NativeHeader("Runtime/Misc/AsyncOperation.h")]
    [RequiredByNativeCode]
    public class AsyncOperation : YieldInstruction
    {
        public AsyncOperation();

        ~AsyncOperation();

        // 摘要:Has the operation finished? (Read Only)
        public bool isDone { get; }

        // 摘要: What's the operation's progress. (Read Only)
        public float progress { get; }

        // 摘要: Priority lets you tweak in which order async operation calls will be performed.
        public int priority { get; set; }

        // 摘要:Allow Scenes to be activated as soon as it is ready.
        public bool allowSceneActivation { get; set; }

        public event Action<AsyncOperation> completed;
    }
}

注意,场景加载完毕后我们需要用一个函数来做一些其他内容, 比如:设置场景初始化[这里需要说明的是加载场景不等于初始化场景],还可以设置游戏状态,UI的显示隐藏等.

 private void LoadSceneCompleted(AsyncOperation operation)
    {
        // 场景加载完成后执行的代码
        Debug.Log("Scene loaded successfully");
     	// ... ...

        // 在这里可以进行场景初始化,例如查找和初始化游戏对象,设置游戏状态等
    }

4.使用协程的方式异步加载场景

利用AsyncOperation operation的isDone数显来判断是否加载完毕, 如果没有加载完毕,就不可以做一些其他事情,并使用yield return来等待一段时间,然后继续判断是否加载完毕,代码如下:

/// <summary>
    /// 自定义协程加载场景
    /// </summary>
    /// <param name="operation"></param>
    /// <returns></returns>
    IEnumerator LoadWaitScene(AsyncOperation operation)
    {
        // 获得加载进度
        while(! operation.isDone)
        {
            Debug.Log("加载中...\t进度: " + operation.progress);
            if (operation.progress >= 0.9f)
            {
                // 激活场景 Allow Scenes to be activated as soon as it is ready.
                operation.allowSceneActivation = true;
            }
            
            // 自己做个假的进度条
            yield return null;
        }

    }

我们也可以直接在协程里使用yield return operaiton来判断是否记加载完毕, 需要注意的是,一旦获得了加载操作的对象那么yeild return xxx后的代码就无法执行.因为场景加载好了,切换到了新的场景,旧的场景中的内容会被销毁,也包括我们挂载的脚本

IEnumerator LoadScene(string sceneName)
    {
        DontDestroyOnLoad(this.gameObject);
        AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
        Debug.Log("加载中...");
        yield return operation;
        // 后面的内容无法打印,因为场景被加载完毕,当前场景上游戏物体,脚本被移除
        Debug.Log("场景加载完毕后打印数据");
        // 要想场景加载完毕后也可以继续执行yield return 后的代码,需要使用 DontDestroyOnLoad 来保存数据
        // 注意: DontDestroyOnLoad 这个代码要放在异步加载场景之前的任意位置,可以是在协程前,可以是在开启异步加载场景协程前.
       
        Debug.Log("加载场景时不销毁对象");

        // 场景加载结束,但不急着显示场景
        // 场景加载结束, 进度条更新一段
        // 接着加载场景中的其他信息
        // 加载怪物-怪物加载完毕进度条更新一段
        // 动态加载 场景模型
        // 这时候就认为加载完毕,进度条设置100%, 隐藏进度条
        
    }

5.DontDestroyOnLoad

如何保持旧场景指定游戏对象/脚本/组件不被销毁? 这时候需要使用DontDestroyOnLoad这个方法来让我们指定的兑现不销毁.下面的代码表示加载场景后销毁气其他资源 ,不销毁当前脚本挂载的游戏物体,自然,当前脚本就不会被销毁了. DontDestroyOnLoad()这是一个重要的方法,用于在场景切换时保留特定的游戏对象。这在某些情况下非常有用,比如保留音效管理器或全局配置对象

 DontDestroyOnLoad(this.gameObject);

6.自己写一个场景管理器

为了避免每一次加载场景的时候都要自己手动写鞋厂或者回调函数,我们可以将这样的方案构成一个类, 值需要传入一个场景名称和一个加载完毕的函数名称就行. 该类最好可以在任意地方使用,因此,我们可以将场景管理类写成一个单例. 这和Unity自带的ScenManager是一个意思,只是自己有了自己自定义的部分. 代码如下:

public class MySceneManager
{
    private static MySceneManager instance = new MySceneManager();
    private MySceneManager() { }

    public static MySceneManager Instance => instance;

    /// <summary>
    /// 外部调用异步加载场景的方法
    /// </summary>
    /// <param name="sceneName"> 场景名 </param>
    public void LoadScene(string sceneName, UnityAction action)
    {
        AsyncOperation ao = SceneManager.LoadSceneAsync(sceneName);
        ao.completed += (a) =>
        {
            action(); // 调用外部的函数
        };
    }
}

测试脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestMySceneManager : MonoBehaviour
{    
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.A))
        {
            MySceneManager.Instance.LoadScene("测试场景", loadCompleteAction);
        }
    }

    private void loadCompleteAction()
    {
        Debug.Log("场景加载完毕");
    }
}

7.测试和优化:

在实现异步加载时,测试不同的场景大小和资源负载非常重要。这有助于发现潜在的性能瓶颈并优化加载过程。

8.资源打包和加载策略:

除了异步加载,合理的资源打包和加载策略也对性能有显著影响。考虑使用AssetBundlesAddressables来优化资源的加载和管理。

9.用户体验:

在加载过程中,提供清晰的反馈(如进度条、加载动画)对于提升用户体验至关重要。这可以让玩家知道游戏正在加载,而不是卡顿或无响应。

最后,确保在实现异步加载时,对Unity的版本和平台特性有一定的了解,因为它们可能会影响异步加载的行为和性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/776163.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SKM Power*Tools 10.0

SKM Power*Tools 10.0是功能强大的电气电力系统分析设计解决方案&#xff01;综合软件提供强大的功能和领先的技术&#xff0c;在检查、计算、负载分配、流量、瞬态稳定性等多个方面提供领先的支持&#xff0c;可对不同的安全设备、系统进行评估分析和比较&#xff0c;使用 Pow…

《安全行业大模型技术应用态势发展报告(2024)》

人工智能技术快速迭代发展&#xff0c;大模型应用场景不断拓展&#xff0c;随着安全行业对人工智能技术的应用程度日益加深&#xff0c;大模型在网络安全领域的应用潜力和挑战逐渐显现。安全行业大模型技术的应用实践不断涌现&#xff0c;其在威胁检测、风险评估和安全运营等方…

解决Vue3中路由页面跳转出现白屏,刷新页面之后展示正常的问题

遇到这个问题&#xff0c;首先需要检查根组件标签最外层是否包含了个最大的div盒子来包裹内容。如下图所示&#xff1a; 我的项目就是因为没有将两块内容放到一个大盒子里面&#xff0c;所以才会出现白屏的问题。然后我去查了相关的资料&#xff0c;了解到这个问题是Vue组件渲染…

improved-diffusion-main代码理解

目录 一、 TimestepEmbedSequential二、PyTorch之Checkpoint机制三、AttentionBlock四、use_scale_shift_norm 和nanoDiffusion-main相比&#xff0c;improved-diffusion-main代码是相似的&#xff0c;但有几个不是很好理解的地方记录一下。 一、 TimestepEmbedSequential 代码…

中国动物志(140卷)

中国动物志&#xff0c;共140卷&#xff0c;包括昆虫纲、鸟纲、兽纲、无脊椎动物、硬骨鱼纲等多类&#xff0c;是反映我国动物分类区系研究工作成果的系列专著&#xff0c;是研究物种多样性、探讨物种演化和系统发育的重要参考&#xff0c;是动物资源开发利用、有害物种控制、濒…

charles使用教程

安装与配置 下载链接&#xff1a;https://www.charlesproxy.com/download/ 进行移动端抓包&#xff1a; 电脑端配置&#xff1a; 关闭防火墙 Proxy–>勾选 macOS Proxy Proxy–>Proxy Setting–>填入代理端口8888–>勾选Enable transparent http proxying 安装c…

【pycharm】 Virtualenv创建venv报错

一、背景 在启动django项目时&#xff0c;需要创建venv环境&#xff0c;有时候能顺利创建成功&#xff0c;当python版本换成3.8时&#xff0c;会报错 ImportError: DLL load failed while importing _ssl: 找不到指定的模块。 二、原因和解决措施 之所以执行这个报错&#…

.NET下的开源OCR项目:解锁图片文字识别的新篇章

在数字化时代&#xff0c;从图片中高效准确地提取文字信息已成为众多应用场景的迫切需求。OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术正是满足这一需求的关键技术。对于.NET开发者而言&#xff0c;幸运的是&#xff0c;存在多个开…

SpringBoot的在线教育平台-计算机毕业设计源码68562

摘要 在数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;在线教育已成为教育领域的重要趋势。为了满足广大学习者对于灵活、高效学习方式的需求&#xff0c;基于Spring Boot的在线教育平台应运而生。Spring Boot以其快速开发、简便部署以及良好的可扩展性&#xff0c…

聚鼎科技:装饰画现在做晚不晚

在每一处光影交错的角落&#xff0c;墙上那一副副静默无言的装饰画&#xff0c;似乎总在诉说着不同的故事。如今&#xff0c;投身于装饰画的创作与收藏&#xff0c;仿佛是一场关于美和时间的赛跑&#xff0c;那么问题来了——现在开始&#xff0c;晚吗? 伴随着生活品质的提升和…

高薪程序员必修课-JVM的内存区域以及对象创建过程

JVM内存区域 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;内存区域&#xff08;Memory Areas&#xff09;是对内存空间的逻辑划分&#xff0c;用于存储不同类型的数据和执行不同的操作。理解JVM的内存区域有助于优化程序性能、调优内存使用和排查内存相关的问题。下…

14-6 小型语言模型在商业应用中的使用指南

人工智能 (AI) 在商业领域的发展使众多工具和技术成为人们关注的焦点&#xff0c;其中之一就是语言模型。这些大小和复杂程度各异的模型为增强业务运营、客户互动和内容生成开辟了新途径。本指南重点介绍小型语言模型、它们的优势、实际用例以及企业如何有效利用它们。 基础知识…

RT-Thread和freeRTOS启动流程

一. freeRTOS启动流程 二. RT-Thread启动流程 因为RT-Thread中我们定义了补丁函数也叫做钩子函数--$Sub$$main()--作为一个新功能函数&#xff0c;可以将原有函数劫持下来&#xff0c;并在之后的程序运行中加上$Super $ $前缀来重新调用原始函数。 所以启动流程是$Sub$$main(…

谷粒商城笔记-04-项目微服务架构图简介

文章目录 一&#xff0c;网络二&#xff0c;网关1&#xff0c;网关选型2&#xff0c;认证鉴权3&#xff0c;动态路由4&#xff0c;限流5&#xff0c;负载均衡6&#xff0c;熔断降级 三&#xff0c;微服务四&#xff0c;存储层五&#xff0c;服务治理六&#xff0c;日志系统七&a…

【网络安全】Host碰撞漏洞原理+工具+脚本

文章目录 漏洞原理虚拟主机配置Host头部字段Host碰撞漏洞漏洞场景工具漏洞原理 Host 碰撞漏洞,也称为主机名冲突漏洞,是一种网络攻击手段。常见危害有:绕过访问控制,通过公网访问一些未经授权的资源等。 虚拟主机配置 在Web服务器(如Nginx或Apache)上,多个网站可以共…

软件测试面试题总结(超全的)

前面看到了一些面试题&#xff0c;总感觉会用得到&#xff0c;但是看一遍又记不住&#xff0c;所以我把面试题都整合在一起&#xff0c;都是来自各路大佬的分享&#xff0c;为了方便以后自己需要的时候刷一刷&#xff0c;不用再到处找题&#xff0c;今天把自己整理的这些面试题…

力扣热100 滑动窗口

这里写目录标题 3. 无重复字符的最长子串438. 找到字符串中所有字母异位词 3. 无重复字符的最长子串 左右指针left和right里面的字符串一直是没有重复的 class Solution:def lengthOfLongestSubstring(self, s: str) -> int:# 左右指针leftright0ans0#初始化结果tablecolle…

ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含

目录 1、web82 2、web83 3、web84 4、web85 5、web86 1、web82 新增过滤点 . &#xff0c;查看提示&#xff1a;利用 session 对话进行文件包含&#xff0c;通过条件竞争实现。 条件竞争这个知识点在文件上传、不死马利用与查杀这些里面也会涉及&#xff0c;如果大家不熟悉…

JavaScript高级程序设计(第四版)--学习记录之对象、类和面向对象编程(中)

创建对象方式 工厂模式&#xff1a;用于抽象创建特定对象的过程。可以解决创建多个类似对象的问题&#xff0c;但没有解决对象标识问题。&#xff08;即新创建的对象是什么类型&#xff09; function createPerson(name, age, job) { let o new Object(); o.name name; o.age…

广和通 OpenCPU 二次开发(二) ——通过linux编译

广和通 OpenCPU 二次开发&#xff08;二&#xff09; ——通过linux编译 一、编译命令总结 1.编译环境配置 . tools/core_launch.sh cout cmake ../.. -G Ninja 2.编译 ninja 二、命令解释 1. 执行 tools/core_launch.sh 这是一个脚本文件 core_launch.sh&#xff0c;通…