【unity进阶知识8】unity场景Scene的使用, 如何封装一个场景管理器

news2024/12/26 21:36:22

文章目录

  • 一、场景基本操作
    • 1、加载切换场景
    • 2、获取场景信息
    • 3、激活场景
    • 4、场景基本属性获取
    • 5、已加载场景个数
    • 6、获取场景中所有物体
    • 7、创建新场景
    • 8、卸载销毁场景
  • 二、使用协程方法来异步加载场景
    • 1、AsyncOperation相关的代码应写在一个协同程序中。
    • 2、allowSceneActivation加载完场景是否自动跳转
    • 3、progress异步加载的进度
    • 4、isDone异步加载是否完成
    • 5、priority设置异步操作的优先级
    • 6、completed异步加载完成会执行一次这个事件
    • 7、简单案例
  • 三、封装场景管理器
    • 1、同步加载当前场景、下一个场景、上一个场景
    • 2、异步切换场景
    • 3、异步加载场景获取加载进度条
    • 4、完整代码
  • 完结

在这里插入图片描述

一、场景基本操作

1、加载切换场景

载索引为1的场景

SceneManager.LoadScene(1);

加载名为MyScene的场景

SceneManager.LoadScene("MyScene");

加载场景,LoadSceneMode.Single表示:销毁当前场景,加载要需要的场景,默认

SceneManager.LoadScene("MyScene", LoadSceneMode.Single);

叠加式加载场景,AddSceneMode.Additive表示:当前场景不销毁,并加载需要的场景

SceneManager.LoadScene("MyScene", LoadSceneMode.Additive);

2、获取场景信息

根据场景的名称(在此例中为 “Scene2”)来获取对应的场景对象

Scene scene2 = SceneManager.GetSceneByName("Scene2")

根据指定的场景索引获取场景信息

int sceneIndex = 1; // 假设我们要获取索引为 1 的场景
Scene scene = SceneManager.GetSceneByBuildIndex(sceneIndex);

3、激活场景

设置scene2为当前活动场景

SceneManager.SetActiveScene(scene2);

获取当前激活场景

Scene scene = SceneManager.GetActiveScene();

4、场景基本属性获取

场景名称

Debug.Log(scene.name);

场景是否已经加载

Debug.Log(scene.isLoaded);

场景路径

Debug.Log(scene.path);

场景索引

Debug.Log(scene.buildIndex);

获取当前构建设置中场景的数量。具体来说,它返回在 Unity 的构建设置(Build Settings)窗口中列出的所有场景的总数。

int totalScenes = SceneManager.sceneCountInBuildSettings;

5、已加载场景个数

Debug.Log(SceneManager.sceneCount);

6、获取场景中所有物体

隐藏的根游戏对象也会包含在其中,DontDestroyOnLoad的游戏对象不包含在其中。

GameObject[] gos = scene.GetRootGameObjects();
Debug.Log(gos.Length);

7、创建新场景

Scene newScene = SceneManager.CreateScene("newScene");

8、卸载销毁场景

//本方法不会卸载内存中的场景资源,如果要释放资源,应在调用这个方法后,再调用Resources.UnloadUnusedAssets()

SceneManager.UnloadSceneAsync(newScene);

//用于释放未使用的资源,以帮助管理内存。它会清理那些不再被使用的资源

Resources.UnloadUnusedAssets()

二、使用协程方法来异步加载场景

1、AsyncOperation相关的代码应写在一个协同程序中。

# 开始加载场景
AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Scene1", LoadSceneMode.Single);

2、allowSceneActivation加载完场景是否自动跳转

值为false表示即使加载场景完毕也不会激活该场景,直到用代码再次把这个变量的值改为true,才会激活该场景。

//加载完场景不要自动跳转
asyncOperation.allowSceneActivation = false;

3、progress异步加载的进度

返回float型,范围是0-1。表示异步加载的进度,开始是0,完成时是1
注意:当AsyncOperation型变量.allowSceneActivation的值为false,这个参数的值最多会卡在0.9,直到AsyncOperation型变量.allowSceneActivation的值变为true,这个参数的值才会变为1

asyncOperation.progress

4、isDone异步加载是否完成

返回bool型。表示该异步加载是否完成。如果完成,则值为true,如果未完成,则值为false。
当AsyncOperation型对象.progress的值为1时,此时这个变量的值才为true,但这样就会激活新的新场景,一般很难观测到AsyncOperation型对象.isDone是true

asyncOperation.isDone

5、priority设置异步操作的优先级

返回int型,用于设置异步操作的优先级。
当有多个异步操作排队时,将优先执行更高优先级的异步操作。但如果异步操作在后台线程上启动, 则更改优先级没有任何效果。

asyncOperation.priority

6、completed异步加载完成会执行一次这个事件

这个是一个有一个AsyncOperation型参数的Action事件。该AsyncOperation型参数存储了本次异步加载的信息。
当异步加载完成,也就是AsyncOperation型对象.isDone的值为true时,会执行一次这个事件。

asyncOperation.completed += Completed()

Action<AsyncOperation> Completed(){
    return null;
}

7、简单案例

using UnityEngine;
using UnityEngine.SceneManagement;

public class  AsyncTest:MonoBehaviour
{
	AsyncOperation asyncOperation;
	
	void Start()
	{
		StartCoroutine(loadScene());
	}

	//协程方法用来异步加载场景
	IEnumerator loadScene()
	{
		//异步加载索引为1的场景
		operation = SceneManager.LoadSceneAsync(1);
		//加载完场景不要自动跳转
		operation.allowSceneActivation = false;
		//等待资源加载完毕
		yield return operation;
	}

	float timer = 0;
	
	void Update()
	{
		//输出加载进度 0-0.9,可以按这个值制作加载进度条
		Debug.Log(operation.progress);
		timer += Time.deltaTime;
		//如果到达5秒,再跳转场景
		if(timer > 5){
			operation.allowSceneActivation = true;
		}
	}
}

三、封装场景管理器

1、同步加载当前场景、下一个场景、上一个场景

using UnityEngine;
using UnityEngine.SceneManagement;

/// <summary>
/// 场景切换管理器
/// </summary>
public class LoadSceneManager : SingletonPatternBase<LoadSceneManager>
{
    /// <summary>
    /// 重新切换到当前场景
    /// </summary>
    public void LoadActiveScene()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

    /// <summary>
    /// 切换到下一个场景
    /// </summary>
    /// <param name="isCyclical">是否循环切换</param>
    public void LoadNextScene(bool isCyclical = false)
    {
        int buildIndex = SceneManager.GetActiveScene().buildIndex + 1;

        if (buildIndex > SceneManager.sceneCountInBuildSettings - 1)
        {
            if (isCyclical)
            {
                buildIndex = 0;
            }
            else
            {
                Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex}, 越界了!");
                return;
            }
        }

        SceneManager.LoadScene(buildIndex);
    }

    /// <summary>
    /// 切换到上一个场景
    /// </summary>
    /// <param name="isCyclical">是否循环切换</param>
    public void LoadPreviousScene(bool isCyclical = false)
    {
        int buildIndex = SceneManager.GetActiveScene().buildIndex - 1;

        if (buildIndex < 0)
        {
            if (isCyclical)
            {
                buildIndex = SceneManager.sceneCountInBuildSettings - 1;
            }
            else
            {
                Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex}, 索引不能为负数!");
                return;
            }
        }

        SceneManager.LoadScene(buildIndex);
    }
}

测试调用

LoadSceneManager.Instance.LoadActiveScene();
LoadSceneManager.Instance.LoadNextScene();
LoadSceneManager.Instance.LoadPreviousScene();

2、异步切换场景

/// <summary>
/// 异步加载场景
/// </summary>
public void LoadSceneAsync(string sceneName, UnityAction completed = null, LoadSceneMode mode = LoadSceneMode.Single)
{
    MonoManager.Instance.StartCoroutine(LoadSceneCoroutine(sceneName, completed, mode));
}

private IEnumerator LoadSceneCoroutine(string sceneName, UnityAction completed = null, LoadSceneMode mode = LoadSceneMode.Single)
{
    // 开始加载场景
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName, mode);

    // 等待资源加载完毕
    while (!asyncOperation.isDone)
    {
        yield return null; // 等待下一帧
    }

    // 加载资源完毕后执行的逻辑
    completed?.Invoke();
}

/// <summary>
/// 异步加载场景(通过索引)
/// </summary>
public void LoadSceneAsync(int sceneIndex, UnityAction completed = null, LoadSceneMode mode = LoadSceneMode.Single)
{
    MonoManager.Instance.StartCoroutine(LoadSceneCoroutine(sceneIndex, completed, mode));
}

private IEnumerator LoadSceneCoroutine(int sceneIndex, UnityAction completed = null, LoadSceneMode mode = LoadSceneMode.Single)
{
    // 开始加载场景
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneIndex, mode);

    // 等待资源加载完毕
    while (!asyncOperation.isDone)
    {
        yield return null; // 等待下一帧
    }

    // 加载资源完毕后执行的逻辑
    completed?.Invoke();
}

测试调用

LoadSceneManager.Instance.LoadSceneAsync(1);
LoadSceneManager.Instance.LoadSceneAsync("Scene1");

3、异步加载场景获取加载进度条

public void LoadSceneAsync(string sceneName, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
{
    MonoManager.Instance.StartCoroutine(LoadSceneCoroutine(sceneName, loading, completed, setActiveAfterCompleted, mode));
}

private IEnumerator LoadSceneCoroutine(string sceneName, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
{
    // 开始加载资源
    AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName, mode);
    asyncOperation.allowSceneActivation = false;

    // 等待资源加载完毕
    while (asyncOperation.progress < 0.9f)
    {
        loading?.Invoke(asyncOperation.progress);
        yield return null;
    }

    // 人为将进度设置为1,以便外部进度条的显示
    loading?.Invoke(1);

    // 根据设置决定何时激活场景
    asyncOperation.allowSceneActivation = setActiveAfterCompleted;

    // 加载资源完毕后执行的逻辑
    completed?.Invoke(asyncOperation);
}

测试调用

public class SceneTest : MonoBehaviour
{
    private void Start()
    {
        LoadSceneManager.Instance.LoadSceneAsync(1, Loading, Completed);
    }

    void Loading(float progress)
    {
        Debug.Log($"加载进度是{progress*100}%");
    }

    void Completed(AsyncOperation asyncOperation)
    {
        Debug.Log("场景加载完成");
    }
}

结果
在这里插入图片描述

4、完整代码

using System;
using System.Collections;
using System.Collections.Generic;
using PlasticGui.WorkspaceWindow;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

namespace XYFrame
{
    /// <summary>
    /// 切换场景的管理器。用于加载场景和切换场景。
    /// </summary>
    public class LoadSceneManager : Singleton<LoadSceneManager>
    {
        #region 同步加载场景
        /// <summary>
        /// <para>同步加载场景(通过索引)</para>
        /// </summary>
        /// <param name="sceneBuildIndex">场景的索引</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadScene(int sceneBuildIndex, LoadSceneMode mode = LoadSceneMode.Single)
        {
            SceneManager.LoadScene(sceneBuildIndex, mode);
        }

        /// <summary>
        /// <para>同步加载场景(通过名字)</para>
        /// </summary>
        /// <param name="sceneName">场景的名字</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadScene(string sceneName, LoadSceneMode mode)
        {
            SceneManager.LoadScene(sceneName, mode);
        }

        /// <summary>
        /// <para>同步重新加载当前的活动场景</para>
        /// </summary>
        public void LoadActiveScene()
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        }

        /// <summary>
        /// <para>同步加载下一个场景</para>
        /// </summary>
        /// <param name="isCyclical">是否循环加载场景。</param>
        public void LoadNextScene(bool isCyclical = false)
        {
            int buildIndex = SceneManager.GetActiveScene().buildIndex + 1;

            if (buildIndex > SceneManager.sceneCountInBuildSettings - 1)
            {
                if (isCyclical)
                {
                    buildIndex = 0;
                }
                else
                {
                    Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex},超过了当前Build Settings窗口中的最大索引。");
                    return;
                }
            }
            SceneManager.LoadScene(buildIndex);
        }

        /// <summary>
        /// <para>同步加载上一个场景</para>
        /// </summary>
        /// <param name="isCyclical">是否循环加载场景。</param>
        public void LoadPreviousScene(bool isCyclical = false)
        {
            int buildIndex = SceneManager.GetActiveScene().buildIndex - 1;

            if (buildIndex < 0)
            {
                if (isCyclical)
                {
                    buildIndex = SceneManager.sceneCountInBuildSettings - 1;
                }
                else
                {
                    Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex},没有索引为负数的场景。");
                    return;
                }
            }
            SceneManager.LoadScene(buildIndex);
        }
        #endregion

        #region 异步加载场景
        /// <summary>
        /// <para>异步加载场景(通过索引)</para>
        /// </summary>
        /// <param name="sceneBuildIndex">要加载的场景索引。</param>
        /// <param name="loading">加载中的回调。只要在加载中,就会不断地执行这个回调。一般用于进度条的显示。</param>
        /// <param name="completed">加载完毕后的回调。</param>
        /// <param name="setActiveAfterCompleted">加载场景完毕后,是否切换到该场景。</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadSceneAsync(int sceneBuildIndex, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //如果要加载的场景的索引不合法,则返回。
            if (!IsSceneBuildIndexValid(sceneBuildIndex)) return;

            //开启协程进行异步加载。
            MonoManager.Instance.StartCoroutine(LoadSceneAsyncCoroutine(sceneBuildIndex, loading, completed, setActiveAfterCompleted, mode));
        }
        IEnumerator LoadSceneAsyncCoroutine(int sceneBuildIndex, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //异步操作对象,记录了异步操作的数据。
            AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneBuildIndex, mode);

            //设置为false,则即使场景加载完毕,也不会切换过去。当场景加载完毕,再次把这个值复制为true,才会切换过去。
            asyncOperation.allowSceneActivation = false;

            //加载场景的过程中,提供给外部执行的回调。一般用于进度条的显示。
            while (asyncOperation.progress < 0.9f)
            {
                loading?.Invoke(asyncOperation.progress);
                yield return CoroutineTool.WaitForFrame();
            }

            //当asyncOperation.allowSceneActivation为false,则asyncOperation.progress最多只能到达0.9,我们人为让它凑成整数1,方便外部进度条的显示。
            loading?.Invoke(1f);

            //加载场景完毕之后,如果把这个变量设置为true,则会切换到该场景。如果为false,则不会切换到该场景。
            asyncOperation.allowSceneActivation = setActiveAfterCompleted;

            //加载场景完毕之后执行的回调。
            completed?.Invoke(asyncOperation);
        }

        /// <summary>
        /// <para>异步加载场景(通过名称)</para>
        /// </summary>
        /// <param name="sceneName">要加载的场景名</param>
        /// <param name="loading">加载中的回调。只要在加载中,就会不断地执行这个回调。一般用于进度条的显示。</param>
        /// <param name="completed">加载完毕后的回调。</param>
        /// <param name="setActiveAfterCompleted">加载场景完毕后,是否切换到该场景。</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadSceneAsync(string sceneName, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //开启协程进行异步加载。
            MonoManager.Instance.StartCoroutine(LoadSceneAsyncCoroutine(sceneName, loading, completed, setActiveAfterCompleted, mode));
        }
        IEnumerator LoadSceneAsyncCoroutine(string sceneName, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //异步操作对象,记录了异步操作的数据。
            AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName, mode);

            //设置为false,则即使场景加载完毕,也不会切换过去。当场景加载完毕,再次把这个值复制为true,才会切换过去。
            asyncOperation.allowSceneActivation = false;

            //加载场景的过程中,提供给外部执行的回调。一般用于进度条的显示。
            while (asyncOperation.progress < 0.9f)
            {
                loading?.Invoke(asyncOperation.progress);
                yield return CoroutineTool.WaitForFrame();
            }

            //当asyncOperation.allowSceneActivation为false,则asyncOperation.progress最多只能到达0.9,我们人为让它凑成整数1,方便外部进度条的显示。
            loading?.Invoke(1f);

            //加载场景完毕之后,如果把这个变量设置为true,则会切换到该场景。如果为false,则不会切换到该场景。
            asyncOperation.allowSceneActivation = setActiveAfterCompleted;

            //加载场景完毕之后执行的回调。
            completed?.Invoke(asyncOperation);
        }

        /// <summary>
        /// <para>异步加载当前活动场景。</para>
        /// </summary>
        /// <param name="loading">加载中的回调。只要在加载中,就会不断地执行这个回调。一般用于进度条的显示。</param>
        /// <param name="completed">加载完毕后的回调。</param>
        /// <param name="setActiveAfterCompleted">加载场景完毕后,是否切换到该场景。</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadActiveSceneAsync(UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            LoadSceneAsync(SceneManager.GetActiveScene().buildIndex, loading, completed, setActiveAfterCompleted, mode);
        }

        /// <summary>
        /// 异步加载下一个场景。
        /// </summary>
        /// <param name="isCyclical">是否循环加载场景。</param>
        /// <param name="loading">加载中的回调。只要在加载中,就会不断地执行这个回调。一般用于进度条的显示。</param>
        /// <param name="completed">加载完毕后的回调。</param>
        /// <param name="setActiveAfterCompleted">加载场景完毕后,是否切换到该场景。</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadNextSceneAsync(bool isCyclical = false, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //下一个场景的索引。
            int buildIndex = SceneManager.GetActiveScene().buildIndex + 1;

            //当要加载的场景的索引超过了Build Settings窗口中的最大索引,则根据参数来判断是否循环加载场景。
            if (buildIndex > SceneManager.sceneCountInBuildSettings - 1)
            {
                if (isCyclical)
                {
                    buildIndex = 0;
                }
                else
                {
                    Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex},超过了当前Build Settings窗口中的最大索引。");
                    return;
                }
            }
            //异步加载该场景。
            LoadSceneAsync(buildIndex, loading, completed, setActiveAfterCompleted, mode);
        }

        /// <summary>
        /// 异步加载上一个场景。
        /// </summary>
        /// <param name="isCyclical">是否循环加载场景。</param>
        /// <param name="loading">加载中的回调。只要在加载中,就会不断地执行这个回调。一般用于进度条的显示。</param>
        /// <param name="completed">加载完毕后的回调。</param>
        /// <param name="setActiveAfterCompleted">加载场景完毕后,是否切换到该场景。</param>
        /// <param name="mode">加载场景的模式。默认是LoadSceneMode.Single,表示会卸载原来的场景,再切换到新场景。LoadSceneMode.Additive表示会将新场景叠加在原来的场景中。</param>
        public void LoadPreviousSceneAsync(bool isCyclical = false, UnityAction<float> loading = null, UnityAction<AsyncOperation> completed = null, bool setActiveAfterCompleted = true, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //上一个场景的索引。
            int buildIndex = SceneManager.GetActiveScene().buildIndex - 1;

            //当要加载的场景的索引为负数,则根据参数来判断是否循环加载场景。
            if (buildIndex < 0)
            {
                if (isCyclical)
                {
                    buildIndex = SceneManager.sceneCountInBuildSettings - 1;
                }
                else
                {
                    Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex},没有索引为负数的场景。");
                    return;
                }
            }
            //异步加载该场景。
            LoadSceneAsync(buildIndex, loading, completed, setActiveAfterCompleted, mode);
        }
        #endregion

        #region 异步销毁场景和这个场景中的所有游戏对象
        /// <summary>
        /// <para>按索引销毁指定的场景和这个场景中的所有游戏对象。</para>
        /// <para>本方法只对加载时用了LoadSceneMode.Additive来加载的场景有效。如果当前游戏中只有一个场景,则本方法无效,且会在控制台报黄色的警告。</para>
        /// <para>本方法不会释放内存中的场景资源,如果要释放该场景资源,应在调用这个方法后,再调用Resources.UnloadUnusedAssets方法。</para>
        /// </summary>
        /// <param name="sceneBuildIndex">要销毁的场景索引。</param>
        /// <param name="callback">销毁完毕后执行的回调。</param>
        /// <param name="options">销毁场景的选项。是一个UnloadSceneOptions型枚举。</param>
        public void DestroySceneAsync(int sceneBuildIndex, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            MonoManager.Instance.StartCoroutine(DestroySceneCoroutine(sceneBuildIndex, callback, options));
        }
        IEnumerator DestroySceneCoroutine(int sceneBuildIndex, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            //异步操作对象,记录了异步操作的数据。
            AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneBuildIndex, options);

            if (asyncOperation == null)
            {
                Debug.LogWarning("要销毁的场景不合法,销毁无效!");
                yield break;
            }

            //如果没有卸载完成,则停在这里面等待。
            while (asyncOperation.progress < 0.9f)
                yield return CoroutineTool.WaitForFrame();

            //卸载场景完毕之后执行的回调。
            callback?.Invoke();
        }


        /// <summary>
        /// <para>按名称销毁指定的场景和这个场景中的所有游戏对象。</para>
        /// <para>本方法只对加载时用了LoadSceneMode.Additive来加载的场景有效。如果当前游戏中只有一个场景,则本方法无效,且会在控制台报黄色的警告。</para>
        /// <para>本方法不会释放内存中的场景资源,如果要释放该场景资源,应在调用这个方法后,再调用Resources.UnloadUnusedAssets方法。</para>
        /// </summary>
        /// <param name="sceneName">要销毁的场景名或场景路径。</param>
        /// <param name="callback">销毁完毕后执行的回调。</param>
        /// <param name="options">销毁场景的选项。是一个UnloadSceneOptions型枚举。</param>
        public void DestroySceneAsync(string sceneName, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            MonoManager.Instance.StartCoroutine(DestroySceneCoroutine(sceneName, callback, options));
        }
        IEnumerator DestroySceneCoroutine(string sceneName, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            //异步操作对象,记录了异步操作的数据。
            AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneName, options);

            if (asyncOperation == null)
            {
                Debug.LogWarning("要销毁的场景不合法,销毁无效!");
                yield break;
            }

            //如果没有卸载完成,则停在这里面等待。
            while (asyncOperation.progress < 0.9f)
                yield return CoroutineTool.WaitForFrame();

            //卸载场景完毕之后执行的回调。
            callback?.Invoke();
        }

        /// <summary>
        /// <para>按场景对象销毁指定的场景和这个场景中的所有游戏对象。</para>
        /// <para>本方法只对加载时用了LoadSceneMode.Additive来加载的场景有效。如果当前游戏中只有一个场景,则本方法无效,且会在控制台报黄色的警告。</para>
        /// <para>本方法不会释放内存中的场景资源,如果要释放该场景资源,应在调用这个方法后,再调用Resources.UnloadUnusedAssets方法。</para>
        /// </summary>
        /// <param name="scene">要销毁的场景对象。</param>
        /// <param name="callback">销毁完毕后执行的回调。</param>
        /// <param name="options">销毁场景的选项。是一个UnloadSceneOptions型枚举。</param>
        public void DestroySceneAsync(Scene scene, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            MonoManager.Instance.StartCoroutine(DestroySceneCoroutine(scene, callback, options));
        }
        IEnumerator DestroySceneCoroutine(Scene scene, UnityAction callback = null, UnloadSceneOptions options = UnloadSceneOptions.None)
        {
            //异步操作对象,记录了异步操作的数据。
            AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(scene, options);

            if (asyncOperation == null)
            {
                Debug.LogWarning("要销毁的场景不合法,销毁无效!");
                yield break;
            }

            //如果没有卸载完成,则停在这里面等待。
            while (asyncOperation.progress < 0.9f)
                yield return CoroutineTool.WaitForFrame();

            //卸载场景完毕之后执行的回调。
            callback?.Invoke();
        }
        #endregion

        #region 返回场景所有游戏对象
        /// <summary>
        /// <para>获取当前激活场景里的所有游戏对象</para>
        /// <para>隐藏的根游戏对象也会包含在其中。DontDestroyOnLoad的游戏对象不包含在其中。</para>
        /// </summary>
        public GameObject[] GetActiveSceneRootGameObjects()
        {
            return SceneManager.GetActiveScene().GetRootGameObjects();
        }

        /// <summary>
        /// <para>获取所有加载的场景里的所有游戏对象</para>
        /// <para>隐藏的根游戏对象也会包含在其中。DontDestroyOnLoad的游戏对象不包含在其中。</para>
        /// </summary>
        public GameObject[] GetLoadedScenesRootGameObjects()
        {
            List<GameObject> list = new List<GameObject>();

            //把当前所有加载的场景的根游戏对象都逐一存储到列表中。
            for (int i = 0; i < SceneManager.sceneCount; i++)
                list.AddRange(SceneManager.GetSceneAt(i).GetRootGameObjects());

            return list.ToArray();
        }
        #endregion

        /// <summary>
        /// 判断指定的场景索引是否合法。
        /// </summary>
        /// <param name="buildIndex">指定的场景索引</param>
        bool IsSceneBuildIndexValid(int buildIndex)
        {
            if (buildIndex < 0)
            {
                Debug.LogWarning($"要加载的场景的索引不合法!该索引是{buildIndex},不能为负数。");
                return false;
            }

            if (buildIndex > SceneManager.sceneCountInBuildSettings - 1)
            {
                Debug.LogWarning($"要加载的场景的索引不合法!该索引越界,越界的索引是{buildIndex},但是场景最大的索引是{SceneManager.sceneCountInBuildSettings - 1}。");
                return false;
            }

            return true;
        }
    }
}

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TypeScript:装饰器

一、简介 随着TypeScript和ES6里引入了类&#xff0c;在一些场景下我们需要额外的特性来支持标注或修改类及其成员。 装饰器&#xff08;Decorators&#xff09;为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。 Javascript里的装饰器目前处在 建议征集的第二阶…

LeetCode 54 Spiral Matrix 解题思路和python代码

题目&#xff1a; Given an m x n matrix, return all elements of the matrix in spiral order. Example 1: Input: matrix [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 2: Input: matrix [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,1…

进程间通信——《匿名管道》

文章目录 前言&#xff1a;进程间通信介绍进程间通信目的进程之间如何通信&#xff1f;进程间通信分类 管道什么是管道&#xff1f;匿名管道&#x1f9e8;尝试使用&#xff1a;&#x1f357;处理细节问题&#xff1a; &#x1f680;管道的4种情况和5种特征&#xff1a;4种情况&…

C++引用(变量引用、数组引用与数组指针、引用本质-指针常量、常量引用)

C语言 ——对数组名进行解引用,取地址,还有sizeof和strlen进行操作解析_对数组名解引用得到什么-CSDN博客 C++引用(变量引用、数组引用与数组指针、引用本质-指针常量、常量引用)_c++11 数组引用-CSDN博客

【智能算法应用】指数分布优化算法求解二维路径规划问题

摘要 本项目采用指数分布优化算法来求解二维路径规划问题。通过构建合理的代价函数并结合智能算法进行优化&#xff0c;我们可以在复杂环境中找到最优路径。实验结果表明&#xff0c;该算法在多维空间中表现出高效性和稳定性。 理论 路径规划问题的核心在于从起点到终点选择…

中国喀斯特地貌分布shp格式数据

​ 中国几乎各省区都有不同面积的石灰岩的分布&#xff0c;出露地表的总面积约有130万平方公里&#xff0c;约占全国总面积的13.5%。被埋藏于地下的则更为广泛&#xff0c;有的地区累计厚度可达几千米。以至上万米。由此可见&#xff0c;喀斯特地形的研究对中国来说&#xff0c…

Nuxt.js 应用中的 link:prefetch 钩子详解

title: Nuxt.js 应用中的 link:prefetch 钩子详解 date: 2024/10/7 updated: 2024/10/7 author: cmdragon excerpt: link:prefetch 是一个强大的钩子,允许开发者在链接预取时执行附加逻辑。合理利用这个钩子,可以帮助优化页面的加载速度和用户体验,提升 Web 应用的整体性…

气膜馆的多元化盈利模式与市场前景—轻空间

随着市场经济的不断繁荣&#xff0c;气膜馆作为一种创新型场馆&#xff0c;凭借其独特的结构设计和灵活的运营模式&#xff0c;逐渐成为创业者关注的焦点。那么&#xff0c;气膜馆如何通过多元化经营实现盈利&#xff1f;本文将为您详细解析气膜馆的经营模式与发展机会。 气膜馆…

Hive3.x版本调优总结

文章目录 第 1 章 Explain 查看执行计划&#xff08;重点&#xff09;1.1 创建测试用表1&#xff09;建大表、小表和 JOIN 后表的语句2&#xff09;分别向大表和小表中导入数据 1.2 基本语法1.3 案例实操 第 2 章 Hive 建表优化2.1 分区表2.1.1 分区表基本操作2.1.2 二级分区2.…

Spring Boot医院管理系统:数据驱动的医疗

3系统分析 3.1可行性分析 通过对本医院管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本医院管理系统采用JAVA作为开发语言&#xff0c;Spring Boot框…

代码随想录算法训练营Day27 | 回溯算法理论基础、77.组合、216.组合总和Ⅲ、17.电话号码的字母组合

目录 回溯算法理论基础 77.组合 216.组合总和Ⅲ 17.电话号码的字母组合 回溯算法理论基础 视频讲解&#xff1a;带你学透回溯算法&#xff08;理论篇&#xff09;| 回溯法精讲&#xff01; 代码随想录&#xff1a;回溯算法理论基础 回溯函数与递归函数指的是同一个函数…

VSCode | 设置Jupyter Notebook显示行号

vscode中的jupyter notebook每个cell都是默认不显示行号的&#xff0c;如果出现了报错&#xff0c;比如在52行出现报错&#xff0c;如果代码多的话不显示行号就有点麻烦&#xff0c;本文介绍如何设置显示行号。 1、VScode点击文件-首选项-设置 2、搜索“python”&#xff0c;点…

Type-C那么多引脚是做什么用的?

一提到Type-C大家想到的肯定就是下面这个扁头接口。 如果大家仔细透过缝看里面的话&#xff0c;可以看到上下两排都有密密麻麻的引脚&#xff08;手机比较差拍不出来就不上图了&#xff09;。 虽然我们用Type-C口的时候我们不需要识别正反面&#xff08;这也是我喜欢Type-C的…

基于Java语言的充电桩平台+云快充协议+充电桩管理后台+充电桩小程序

软件架构 1、提供云快充底层桩直连协议&#xff0c;版本为云快充1.5&#xff0c;对于没有对接过充电桩系统的开发者尤为合适&#xff1b; 2、包含&#xff1a;启动充电、结束充电、充电中实时数据获取、报文解析、Netty通讯框架、包解析工具、调试器模拟器软件等&#xff1b;…

电脑提示d3dcompiler_47.dll缺失怎么修复,仔细介绍dll的解决方法

1. d3dcompiler_47.dll 概述 1.1 定义与作用 d3dcompiler_47.dll 是 Microsoft DirectX 的一个关键组件&#xff0c;作为一个动态链接库&#xff08;DLL&#xff09;文件&#xff0c;它在 Windows 操作系统中扮演着至关重要的角色。DirectX 是一套由微软开发的用于处理多媒体…

Flutter渲染过程

The rendering process is what transforms your widget tree into the actual pixels that are displayed on the screen. It’s like the magic behind the scenes that brings your app’s UI to life! 呈现过程将小部件树转换为显示在屏幕上的实际像素。它就像幕后的魔法&…

代码随想录算法训练营第二十六天|669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 给定一个二叉搜索树&#xff0c;同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[L, R]中 (R>L) 。你可能需要改变树的根节点&#xff0c;所以结果应当返回修剪好的二叉搜索树的新的根节点。 思路&#xff1a; 首先…

JavaScript 获取浏览器本地数据的4种方式

JavaScript 获取浏览器本地数据的方式 我们在做Web开发中&#xff0c;客户端存储机制对于在浏览器中持久化数据至关重要。这些机制允许开发者存储用户偏好设置、应用状态以及其他关键信息&#xff0c;从而增强用户体验。本文将介绍几种常用的JavaScript获取浏览器本地数据的方…

【无人机设计与控制】基于蜣螂优化算法的无人机三维路径规划Matlab程序

摘要 使用蜣螂优化算法&#xff08;Dung Beetle Optimization, DBO&#xff09;&#xff0c;本文提出了一种无人机三维路径规划方法。该算法借鉴蜣螂导航行为&#xff0c;结合无人机避障需求&#xff0c;在复杂三维环境中生成最优路径。实验结果表明&#xff0c;基于DBO的路径…

Redis主从复制(replica)、哨兵

一、Redis主从复制介绍: 主从复制&#xff0c;master主机以写为主&#xff0c;slave从机以读为主&#xff0c;当主机数据变化的时候自动将新的数据异步同步到其他从机数据库&#xff1b;能够实现读写分离&#xff0c; 容灾恢复、 数据备份以及水平扩容支撑高并发 二、实现方法…