【Unity开发】监听Scene场景事件

🐾 个人主页 🐾

阿松爱睡觉,横竖醒不来 🏅你可以不屠龙,但不能不磨剑🗡


目录

一、前言

在游戏开发的过程中,各个Scene场景之间的切换加载是必要的。但有些时候我们也需要知道场景什么时候切换加载完毕,以便于在场景加载完毕的时候执行特定的函数。

所以下面就聊一聊,场景切换完成时机的获取方法,就是监听一下场景什么时候加载完毕。

二、监听方法

(一)SceneManager.sceneLoaded事件

第一个也是比较简单便捷的方法,通过订阅 SceneManager.sceneLoaded 事件来监听场景加载完成的情况。

用法比较简单,看下示例:

csharp 复制代码
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneLoadListener : MonoBehaviour
{
    private void OnEnable()
    {
        // 订阅场景加载完成的事件
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    private void OnDisable()
    {
        // 取消订阅场景加载完成的事件
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }

	//scene 加载的场景、mode 加载场景的模式
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 处理场景加载完成后的逻辑
        Debug.Log("场景加载完毕:" + scene.name);
    }
}

脚本编写完毕之后,将该监听的脚本挂载到任何活跃的GameObject上即可,它会监听场景加载事件。当场景加载完成时,OnSceneLoaded 方法自动被调用。

这里有一点需要注意,就是脚本挂载的地方,需要保持挂载了该脚本的物体持续活跃,为什么这么讲?

假设挂载了该脚本的物体在某个场景中,而且这个场景还刚好是被切换下的旧的场景,一旦含有该物体的场景被切换,那么场景里面的物体也同样被销毁,那么该脚本就会在场景加载完成前取消订阅,那么也就不会监听到场景加载完毕事件。

对于这种情况,有两种方法可以避免。第一个就是使用 DontDestroyOnLoad() 固定持久化,这个方法不明白的可以看我的另一篇文章,有专门的讲解;第二个就是把加载场景的方式换成 LoadSceneMode.Additive 这样就不会关闭之前正在加载的场景。

(二)SceneManager.LoadSceneAsync回调

第二个是使用 SceneManager.LoadSceneAsync 来异步加载场景,然后可以通过其返回的AsyncOperation 对象来监听加载完成。

还是先看下示例:

csharp 复制代码
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneLoadAsync : MonoBehaviour
{
	//加载场景的方法
    public void LoadSceneAsync(string sceneName)
    {
        SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single).completed += operation =>
        {
            // 在这里处理场景加载完成后的逻辑
            Debug.Log("场景加载完毕:" + sceneName);
        };
		
		//上面是比较简洁的写法,没用使用AsyncOperation类型的变量来存储返回的AsyncOperation对象
		AsyncOperation asyncOperation= SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
		asyncOperation.completed += operation =>
        {
            // 在这里处理场景加载完成后的逻辑
            Debug.Log("场景加载完毕:" + sceneName);
        };
    }
}

看完可能会注意到回调函数中带有一个名为 operation 的参数,这个参数代表当前完成的异步操作,所以它的类型是 AsyncOperation 类型。

那么可以从这个参数获取到什么数据呢?这个参数类型 (AsyncOperation) 中有四个变量:

  • allowSceneActivation :允许在场景准备就绪后立即激活场景。(bool类型)
  • isDone :操作是否已完成?(只读)(bool类型)
  • priority :允许调整执行异步操作调用的顺序。(int类型)
  • progress :获取操作进度。(只读)(float类型)

比较常用的就只有 isDone 和 progress ,下面第三中方法中就用到了 isDone 变量,一起来看下。

(三)协程方式

这种方法其实跟上面的(二)是类似的,都是使用的 SceneManager.LoadSceneAsync 返回的 AsyncOperation 对象,只不过不同的是这里没有用 AsyncOperation 对象中的 completed 事件,而是检测的对象中的 isDone 变量。

看下示例:

csharp 复制代码
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class SceneLoadCoroutine : MonoBehaviour
{
	//加载场景函数
    public void LoadScene(string sceneName)
    {
    	//启动协程
        StartCoroutine(LoadSceneAsync(sceneName));
    }

	//协程加载
    IEnumerator LoadSceneAsync(string sceneName)
    {
        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
        // 等待场景加载完成
        while (!asyncLoad.isDone)
        {
            yield return null;
        }
        // 在这里处理场景加载完成后的逻辑
        Debug.Log("场景加载完毕:" + sceneName);
    }
}

LoadScene方法启动了一个协程,该协程等待 AsyncOperation 的 isDone 为 true ,指示场景加载完成。

这种方法有个好处,就是可以获取场景加载的进度,就是前面说的 progress 变量,可以用来做个进度条什么的。

三、结语

这篇的内容就到此结束了,如果遇到什么问题,欢迎在评论区留言或者私信,下期见,拜拜!

相关推荐
xiaogai_gai9 小时前
BOM 物料清单同步实战:金蝶云星空 → 四化智造 MES 修改场景深度拆解
unity·游戏引擎
天天代码码天天10 小时前
屏幕翻拍满是彩色条纹?用 C# + Vulkan 做了一个去摩尔纹工具,支持单图与文件夹批量
c#·去摩尔纹
2501_9307077810 小时前
使用C#代码在 Word 文档中添加、插入或删除页面
开发语言·c#·word
淡海水12 小时前
03-03-架构篇-SGen GC架构解析
unity·架构·c#·gc·sgen
曹牧1 天前
C#:输入的字符串格式不正确
c#
萌萌的提莫队长1 天前
Unity相机捕捉,图像识别,抠像+合成
opencv·unity
根号五1 天前
JetBrains Rider 使用教程(1)新建解决方案
c#·jetbrains rider
海天鹰1 天前
C#:接收从打开方式打开的参数
c#
宝桥南山1 天前
.NET 11 - 尝试一下Minimal API中的异步验证新特性
microsoft·微软·c#·asp.net·.net·.netcore