【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 变量,可以用来做个进度条什么的。

三、结语

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

相关推荐
1-1=017 小时前
C# 委托与事件
开发语言·c#
tealcwu1 天前
【Unity基础】为什么游戏需要物理按键映射?从 Unity Input Manager 到跨引擎输入设计
java·游戏·unity
1-1=01 天前
C# 特性(Attribute)
c#·.net·.netcore
tealcwu2 天前
【Unity高级】Unity URP:构建同时支持 2D 与 3D 场景的项目完全指南
3d·unity·游戏引擎
淡海水2 天前
10-01-互操作-C#与C++边界的内存管理
unity·c#·游戏引擎·.netcore·gc
小小数媒成员2 天前
UGUI原理(一)
开发语言·游戏·unity·游戏引擎
WarPigs2 天前
C#把byte[]以十六进制打印,带分割符
c#
暴走约伯2 天前
【VFX工具链源码拆解 04】拯救丢失的绑定:Timeline 一键克隆与层级相对路径重映射算法
unity·c#·游戏引擎·硬件工程
1-1=02 天前
C# 反射
c#·.net·.netcore
步步为营DotNet2 天前
.NET 可观测性选型:Metrics、ActivitySource、EventSource 到底该用哪个
c#·.net·metrics·可观测性