【unity框架开发8】unity场景Scene的使用, 如何封装一个场景管理器

news2024/12/26 22:42:04

文章目录

  • 一、场景基本操作
    • 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/2210045.html

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

相关文章

AI深湖DeepLate人工智能的数据集格式开源项目

人工智能的数据集格式 文档 • 入门 • API 参考 • 例子 • 博客 • Slack 社区 • Twitter&#xff08;推特&#xff09; 用其他语言阅读这篇文章: English 深湖 Deep Lake Deep Lake 是一种数据集格式&#xff0c;提供简单的 API 以用于创建、存储和协作处理任何规模的…

Spring Security 与 OAuth 2.0 登录实现指南

文章目录 一、项目概述二、环境准备三、创建GitHub OAuth应用四、项目依赖配置五、配置OAuth 2.0六、创建控制器七、创建视图八、运行应用九、用户界面展示十、总结 在现代的Web应用中&#xff0c;安全性是一个不可忽视的因素。OAuth 2.0作为一种流行的授权框架&#xff0c;提供…

浅析主流监控告警系统基本架构和原理

浅析主流监控告警系统基本架构和原理 一&#xff0c;监控系统的作用和目前主流监控系统 1&#xff0c;作用&#xff1a;监控系统一般有以下这几个作用 实时采集监控数据&#xff1a;包括硬件、操作系统、中间件、应用程序等各个维度的数据。实时反馈监控状态&#xff1a;通过…

论文笔记:RelationPrompt :Zero-Shot Relation Triplet Extraction

论文来源: ACL Findings 2022 论文链接:https://arxiv.org/pdf/2203.09101.pdf 论文代码:http://github.com/declare-lab/RelationPrompt 本篇论文是由阿里达摩院自然语言智能实验室于2022年发表的关于零样本关系抽取的顶会论文,本篇博客将记录我在阅读过程中的一些笔记…

AI自动生成PPT解决方案,AI生成PPT-PrensentationGen-Java实现

AI自动生成PPT解决方案&#xff0c;AI生成PPT-PrensentationGen-Java实现。 利用大语言模型生成PPT文件的SpringBoot Web应用&#xff0c;主要功能是自动化创建演示文稿&#xff0c;适用于快速制作演示材料&#xff0c;特色在于其高效的模板处理和文本替换技术。 点击视频观看…

Python入门:如何在Python中优雅地书写多行字符串!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 多行字符串📒📝 什么是多行字符串?📝 三重引号📝 字符串连接📝 反斜杠⚓️ 相关链接 ⚓️📖 介绍 📖 在编程过程中,时常会遇到需要使用多行字符串的场景。例如,在编写长参数、描述文本或代码文档时,多行字符串…

java生成日历数据列表并按日历格式导出到excel

日历格式输出 日历数据列表导出封装日历格式实体类效果 日历数据列表 /**** 封装日历数据* param year 年份* param month 月份*/public List<InspectionDailyStaffPlanCalendarData> selectCalendarDataList(int year,int month,List<InspectionDailyStaffPlan> …

centos7 Oracle 11g rac 静默安装(NFS配置共享存储)

1.环境信息准备 注意&#xff1a; 在配置网络时&#xff0c;Oracle RAC的每个节点必须具有至少两个以上的网卡&#xff0c;一张网卡对外提供网络服务&#xff0c;另一张网卡用于各个节点间的通信和心跳检测等。在配置RAC集群的网卡时&#xff0c;如果节点1的公共接口是eth0&…

随机变量及其分布

定义 1.随机变量是一个从样本空间&#xff08;所有可能结果的集合&#xff09;到实数集的函数。样本空间中的每个结果都对应于随机变量的一个值。随机变量的值可以是离散的&#xff0c;也可以是连续的。随机变量通常用大写字母表示&#xff0c;如 X、Y 或 Z。 2.随机变量和事…

难点:Linux 死机定位(进程虚拟地址空间耗尽)

死机定位(进程虚拟地址空间耗尽) 一、死机现象 内存富裕,但内存申请失败。 死机时打印: 怀疑是: 1、内存碎片原因导致。 2、进程虚拟地址空间耗尽导致。 3、进程资源限制导致。 二、内存碎片分析 1、理论知识:如何分析内存碎片化情况 使用 /proc/buddyinfo: /proc/…

Java-sec-code学习2

Java-Sec-Code学习1-文件上传漏洞 case1 url: http://127.0.0.1:8080/file/any 这是一个典型的上传页面&#xff0c;我们尝试上传一个文件试试看。 直接上传一个jsp文件&#xff0c;发现可以直接上传&#xff0c;非常顺利。这意味这后端和前端都没有对文件类型进行任何限制。…

[旧日谈]关于Qt的刷新事件频率,以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。

[旧日谈]关于Qt的刷新事件频率&#xff0c;以及我们在Qt的框架上做实时的绘制操作时我们该关心什么。 最近在开发的时候&#xff0c;发现一个依赖事件来刷新渲染的控件会导致程序很容易异常和崩溃。 当程序在运行的时候&#xff0c;其实软件本身的负载并不高&#xff0c;所以…

【LeetCode每日一题】——724.寻找数组的中心下标

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目注意】六【题目示例】七【题目提示】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 前缀和 二【题目难度】 简单 三【题目编号】 724.寻找数组的中心下标 四【…

python基础路径的迁移

本人未安装anaconda或pycharm等&#xff0c;仅安装了某个python环境&#xff0c;因此以下方法仅针对基础python环境的迁移&#xff0c;不确保其他软件或插件正常运行 第一步将原python路径的整个文件夹剪切到新的路径下 第二步修改系统环境变量&#xff0c;将原来的python路径…

胤娲科技:AI绘梦师——一键复刻梵高《星空》

想象一下&#xff0c;你手中握有一张梵高的《星空》原图&#xff0c;只需轻轻一点&#xff0c;AI便能化身绘画大师&#xff0c;一步步在画布上重现那璀璨星河。 这不是科幻电影中的桥段&#xff0c;而是华盛顿大学科研团队带来的“Inverse Painting”项目&#xff0c;正悄然改变…

【软件工程】McCabe复杂度计算

文章目录 一、定义与公式二、计算步骤三、示例四、注意事项 McCabe复杂度&#xff0c;又称为环路复杂度&#xff08;Cyclomatic Complexity&#xff09;&#xff0c;是一种用来度量软件程序复杂度的经典方法。它通过计算程序中独立路径的数量&#xff0c;帮助开发人员理解代码的…

CMIP6数据处理 ▎单点降尺度、统计方法的区域降尺度、基于WRF模式的动力降尺度

CMIP6数据被广泛应用于全球和地区的气候变化研究、极端天气和气候事件研究、气候变化影响和风险评估、气候变化的不确定性研究、气候反馈和敏感性研究以及气候政策和决策支持等多个领域。这些数据为我们理解和预测气候变化&#xff0c;评估气候变化的影响和风险&#xff0c;以及…

【从感知机到神经网络】

感知机 什么是感知机 公式、框图表示 直观举例 根据身高体重判断胖瘦的感知机。 1、根据已知样本训练出一条直线&#xff0c;用于对非训练样本进行分类&#xff0c;这条直线就是感知机模型。 三维情况下感知机模型是一个平面 感知机的缺陷 缺陷原因 不能处理异或问题&…

【hot100-java】路径总和 III

二叉树篇。 灵神题解 ps: 完结 历时许久的hot100终于结束了&#xff0c;先是python&#xff0c;后是java。 学到了不少语法&#xff0c;也挺爽的&#xff0c;希望接下来几遍会更加熟悉哈哈哈。

解读《ARM Cortex-M3 与Cortex-M4 权威指南》——第1章 ARM Cortex-M处理器简介

1. 三级流水线设计 解释:三级流水线设计意味着处理器在执行指令时可以同时处理多个步骤。这些步骤通常包括取指(Fetch)、译码(Decode)和执行(Execute)。好处:这种设计提高了指令的执行效率,使得处理器能够在每个时钟周期内完成更多的工作,从而提升整体性能。2. 哈佛总…