
🐾 个人主页 🐾
阿松爱睡觉,横竖醒不来 🏅你可以不屠龙,但不能不磨剑🗡
目录
一、前言
在游戏开发的过程中,各个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 变量,可以用来做个进度条什么的。
三、结语
这篇的内容就到此结束了,如果遇到什么问题,欢迎在评论区留言或者私信,下期见,拜拜!

