Unity框架学习--场景切换管理器

活动场景

用脚本实例化的游戏对象都会生成在活动场景中。

哪个场景是活动场景,则当前的天空盒就会使用该场景的天空盒。

只能有一个场景是活动场景。

在Hierarchy右击一个场景,点击"Set Active Scene"可以手动把这个场景设置为活动场景。也可以使用SceneManager.SetActiveScene方法把一个加载了的场景设置为活动场景。

异步加载

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

AsyncOperation 对象名=SceneManager.LoadSceneAsync(string 场景名)

开启异步加载场景,并把异步加载的信息存储在AsyncOperation型对象中。

AsyncOperation型对象.allowSceneActivation

返回bool型,表示是否允许在场景加载完毕后立即激活该场景。

值为true表示一旦该场景异步加载完毕,则会立即激活该场景。

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

AsyncOperation型对象.progress

返回float型,范围是0-1。表示异步加载的进度,开始是0,完成时是1

注意:当AsyncOperation型变量.allowSceneActivation的值为false,这个参数的值最多会卡在0.9,直到AsyncOperation型变量.allowSceneActivation的值变为true,这个参数的值才会变为1

AsyncOperation型对象.isDone

返回bool型。表示该异步加载是否完成。如果完成,则值为true,如果未完成,则值为false。

当AsyncOperation型对象.progress的值为1时,此时这个变量的值才为true,但这样就会激活新的新场景,一般很难观测到AsyncOperation型对象.isDone是true

AsyncOperation型对象.priority

返回int型,用于设置异步操作的优先级。

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

AsyncOperation.completed

这个是一个有一个AsyncOperation型参数的Action事件。该AsyncOperation型参数存储了本次异步加载的信息。

当异步加载完成,也就是AsyncOperation型对象.isDone的值为true时,会执行一次这个事件。

LoadSceneManager 代码

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Events;

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

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

        //检测要切换的新场景的下标是否越界     这个参数的意思是BuildSettings中的场景总数
        if (buildIndex > SceneManager.sceneCountInBuildSettings-1)
        {
            if (isCyclical)
                buildIndex = 0;
            else
            {
                Debug.LogWarning($"加载场景失败!要加载的场景的索引是{buildIndex},越界了");
                return;
            }
        }

        SceneManager.LoadScene(buildIndex);
    }

    /// <summary>
    /// 加载上一个场景,包括可选择的场景循环功能
    /// </summary>
    public void LoadPreviousScene(bool isCyslical=false)
    {
        int buildIndex = SceneManager.GetActiveScene().buildIndex - 1;

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

        SceneManager.LoadScene(buildIndex);
    }

    /// <summary>
    /// 异步加载场景  根据名字来切换场景
    /// </summary>
    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));
    }

    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;  //资源加载最多到0.9

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

        //当asyncOperation.allowSceneActivation 为false,则asyncOperation.Progress最多只能到达0.9
        //我们人为把它们凑成1,可以方便外部进度条的显示
        loading?.Invoke(1);

        asyncOperation.allowSceneActivation = setActiveAfterCompleted;

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

    /// <summary>
    /// 异步加载场景 根据索引来切换场景
    /// </summary>
    public void LoadSceneAsync(int sceneIndex,UnityAction<float>loading=null, 
        UnityAction completed = null,bool setActiveAfterCompleted=true, LoadSceneMode mode = LoadSceneMode.Single)
    {
        MonoManager.Instance.StartCoroutine(LoadSceneCoroutine(sceneIndex,loading, completed,setActiveAfterCompleted, mode));
    }

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

        asyncOperation.allowSceneActivation = false;  //资源加载最多到0.9

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

        //当asyncOperation.allowSceneActivation 为false,则asyncOperation.Progress最多只能到达0.9
        //我们人为把它们凑成1,可以方便外部进度条的显示
        loading?.Invoke(1);

        asyncOperation.allowSceneActivation = setActiveAfterCompleted;

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


}

测试脚本

cs 复制代码
[MenuItem("我的菜单/同步切换场景/重新切换到上一个场景")]
    static void Method3()
    {
        LoadSceneManager.Instance.LoadPreviousScene();
    }

    [MenuItem("我的菜单/异步切换场景/重新切换到场景1")]
    static void Method4()
    {
        LoadSceneManager.Instance.LoadSceneAsync("New Scene 1", (obj) =>
         {
             Debug.Log("加载进度是:" + obj * 100 + "%");
         }, (obj) =>
         {
             Debug.Log("加载完成了!");
         });
    }

Unity Scene类(场景类)

Scene类的对象用来存储场景的信息。

Scene型对象.buildIndex

返回int型,表示该场景在Build Settings窗口中的索引。

如果该场景是无效的场景,则这个变量的值为-1

如果该场景是通过AssetBundle加载的场景,则这个变量的值也为-1

Scene型对象.isDirty

返回bool型,表示该场景是否被修改了。

当我们在编辑器模式下修改了某一个场景,但是没有保存,则此时这个变量的值为true。一旦该场景保存了,则这个变量的值为false

Scene型对象.isLoaded

如果该场景已经加载了,则返回true。如果该场景还没有加载或没有加载完成,则返回false

Scene型对象.name

返回string型,表示该场景的名字,结尾不包含后缀.unity

也就是它在Project窗口中的名字。

注意:该场景必须已经加载了,这个变量才能正确返回它的场景名。如果该场景还没有加载或没有加载完成,则返回的值是"Null"

Scene型对象.path

返回string型,表示该场景的路径,结尾包含后缀.unity

例如:

Assets/AssetBundleAssets/Scenes/TestScenes/Test.unity

Scene型对象.rootCount

返回int型,表示该场景中所有根游戏对象身上的Transform组件的总数。

Scene型对象.GetRootGameObjects

返回GameObject[]型,表示该场景中所有根游戏对象。

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

Scene型对象.IsValid

如果一个场景是存在的,它就是有效场景,这个变量的值就为true

如果一个场景是不存在的,它就是无效场景,这个变量的值就为false

注意:从EditorSceneManager.OpenScene返回的场景的 IsValid 的值是 false

两个场景对象之间可以使用运算符!=

如果这两个场景不同,则返回true,否则返回false

两个场景对象之间可以使用运算符==

如果这两个场景相同,则返回true,否则返回false

Unity SceneManager类(场景管理器,用于加载场景、切换场景)

首先把要跳转的场景都拖进File------Build Settings中

必须先引入命名空间:using UnityEngine.SceneManagement;

SceneManager.sceneCount

当前已经加载的场景的数量。

SceneManager.sceneCountInBuildSettings

已经添加到Build Settings窗口中的场景的数量。

如果在编辑器模式下,则进入播放模式之前已经打开的场景也会包含在内,如果它没有手动拖到Build Settings窗口,则它在Build Settings窗口中也是有索引的,只是我们看不到,这个索引比可以看得到的最大1。

SceneManager.CreateScene(int 场景名)

创建一个空场景,这个空场景会叠加到当前场景。

如果创建的场景名重复,则会报错。

场景名可以在Hierarchy窗口看到。

如果要在编辑时创建场景,例如在创建编辑器脚本或工具时需要创建场景,则应使用EditorSceneManager.NewScene

SceneManager.CreateScene(string 场景名,CreateSceneParameters 创建场景的各种参数)

创建一个空场景,这个场景会叠加到当前场景。

如果创建的场景名重复,则会报错。

场景名可以在Hierarchy窗口看到。

如果要在编辑时创建场景,例如在创建编辑器脚本或工具时需要创建场景,则应使用EditorSceneManager.NewScene

SceneManager.GetActiveScene()

返回Scene型对象,表示当前场景的信息。

SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);

使用同步的方式,重新切换到当前场景。

SceneManager.GetActiveScene().buildIndex+1表示下一个场景在Build Settings窗口中的索引。

SceneManager.GetActiveScene().name

string型。表示当前场景的名字。可以配合SceneManager.LoadScene使用,重新加载当前场景

SceneManager.GetSceneAt(int 索引)

在当前已加载的场景的列表中,返回指定索引的场景的信息。

索引必须大于等于0,最小为0。如果为负数,或者索引越界,则会报错。

SceneManager.GetSceneByBuildIndex(int 场景在Build Settings窗口中的索引)

根据传入的索引,返回Build Settings中的场景的信息。

该场景必须在Build Settings窗口中,且当前已经加载,这样才会返回它的信息。否则会返回一个无效的Scene型对象。

索引必须大于等于0,最小为0。如果为负数,或者索引越界,则会报错。

SceneManager.GetSceneByName(string 场景名)

在当前已经加载的场景中,查找指定场景名的场景。

如果找到了,则返回一个Scene对象,表示这个场景的信息。如果找不到,则返回一个无效的Scene对象。

场景名可以是Build Settings窗口中所示名称的最后一部分,在这种情况下,将返回第一个匹配的场景信息。

场景名也可以是Build Settings窗口中显示的路径,在这种情况下,将返回精确匹配到的场景信息。

场景名不区分大小写。

场景名一定不得包含.unity扩展名。

SceneManager.GetSceneByPath(string 场景的路径)

在当前已经加载的场景中,查找具有指定资源路径的场景。

如果找到了,则返回一个Scene对象,表示这个场景的信息。如果找不到,则返回一个无效的Scene对象。

场景的路径应是项目文件夹的相对路径,例如:"Assets/MyScenes/MyScene.unity"

SceneManager.LoadScene(int 场景在Build Settings窗口中的索引,LoadSceneMode 加载场景的模式);

同步加载指定索引的场景。

第一个参数可以使用string型,这样就会根据场景名或者场景路径来加载指定的场景。此时这个名字的场景要么提前放到Build Settings窗口中,要么之前已经用了AssetBundle加载,这样一来这个方法才会有效。如果都没有,则会报错。注意:场景名不包含.unity的后缀。还有,场景名不要重名,如果重名,则会加载匹配到的第一个场景。可以使用场景路径,例如:Assets/AssetBundleAssets/Scenes/TestScenes/Scene1.unity

如果第二个参数使用LoadSceneMode.Single,则加载完毕后,会自动切换到该场景。原来场景会被卸载。默认就是使用这个。

如果第二个参数使用LoadSceneMode.Additive,则加载完毕后,该场景会叠加到原来的场景中。原来的场景不会被卸载,且活动场景依然是原来的场景。

使用此方法加载场景,不会立即加载,而是会在下一帧才开始加载。而且由于此方法是同步的,所以可能会出现卡顿现象,建议使用异步加载的LoadSceneAsync方法。

SceneManager.LoadSceneAsync(int 场景在Build Settings窗口中的索引,LoadSceneMode 加载场景的模式);

异步加载指定索引的场景。

第一个参数可以使用string型,这样就会根据场景名或场景路径来加载指定的场景。此时这个名字的场景要么提前放到Build Settings窗口中,要么之前已经用了AssetBundle加载,这样一来这个方法才会有效。如果都没有,则会报错。注意:场景名不包含.unity的后缀。还有,场景名不要重名,如果重名,则会加载匹配到的第一个场景。可以使用场景路径,例如:Assets/AssetBundleAssets/Scenes/TestScenes/Scene1.unity

如果第二个参数使用LoadSceneMode.Single,则加载完毕后,可以切换到该场景,那么原来场景会被卸载。默认就是使用这个。

如果第二个参数使用LoadSceneMode.Additive,则加载完毕后,该场景可以叠加到原来的场景中。原来的场景不会被卸载,且活动场景依然是原来的场景。

使用此方法加载场景不会卡住游戏,往往配合场景中的进度条来使用,可以一边加载场景,一边控制进度条的推进。

这个方法的返回值类型的是AsyncOperation类型,可以根据这个类型的对象来判断异步加载是否完成。具体可以参考AsyncOperation类。

SceneManager.MergeScenes(Scene 场景1,Scene 场景2)

将场景1的所有游戏对象全部转移到场景2,且场景1会被卸载掉。

一般在加载场景时,使用了LoadSceneMode.Additive来加载,才可能会使用这个方法。

场景1和场景2都必须是已加载的场景。

如果原来的场景1是活动场景,这样它被卸载掉之后,Hierarchy窗口中最上面的第一个场景就会变成活动场景。

如果原来的场景1不是活动场景,这样它被卸载掉之后,活动场景不变。

SceneManager.MoveGameObjectToScene(GameObject 要移动的游戏对象,Scene 移动到场景)

将一个游戏对象从它所在的场景移动到目标场景中。

一般在加载场景时,使用了LoadSceneMode.Additive来加载,才可能会使用这个方法。

要移动到的场景必须是已加载的场景。

如果要移动的游戏对象为null,则本方法无效。

如果移动到的场景没有加载完成,或者是无效的场景,则会报错。

SceneManager.SetActiveScene(Scene 场景名)

将指定的场景设置为活动场景。

SceneManager.UnloadSceneAsync(int 场景在Build Settings窗口中的索引)

SceneManager.UnloadSceneAsync(string 场景名或场景路径)

SceneManager.UnloadSceneAsync(Scene 场景对象)

SceneManager.UnloadSceneAsync(int 场景在Build Settings窗口中的索引,UnloadSceneOptions 卸载场景的选项)

SceneManager.UnloadSceneAsync(string 场景名或场景路径,UnloadSceneOptions 卸载场景的选项)

SceneManager.UnloadSceneAsync(Scene 场景对象,UnloadSceneOptions 卸载场景的选项)

销毁指定的场景和这个场景中的所有游戏对象。

本方法只对加载时用了LoadSceneMode.Additive所加载的场景有效。如果当前游戏中只有一个场景,则本方法无效,控制台会报黄色的警告。

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

返回值的类型是AsyncOperation类型,可以根据这个对象来确定异步操作是否完成。

SceneManager.activeSceneChanged

UnityAction<Scene,Scene>型的事件。

当活动场景发生变化时,会执行一次这个事件。

第一个参数表示原来的活动场景,第二个参数表示后来的活动场景。

SceneManager.sceneLoaded

UnityAction<Scene,LoadSceneMode>型的事件。

每当有新的场景被加载时,会执行一次这个事件。

第一个参数表示加载的新的场景,第二个参数表示这个场景加载的模式。

SceneManager.sceneUnloaded

UnityAction<Scene>型的事件。

每当有场景被卸载时,会执行一次这个事件。

参数表示卸载的场景对象。

相关推荐
qq 180809515 小时前
从零构建一个多目标多传感器融合跟踪器
unity
平行云6 小时前
实时云渲染支持在网页上运行UE5开发的3A大作Lyra项目
unity·云原生·ue5·webgl·虚拟现实·实时云渲染·像素流送
鹏飞于天6 小时前
Shader compiler initialization error: Failed to read D3DCompiler DLL file
unity
wonder135798 小时前
UGUI重建流程和优化
unity·游戏开发·ugui
那个村的李富贵12 小时前
Unity打包Webgl后 本地运行测试
unity·webgl
nnsix13 小时前
Unity OpenXR开发HTC Vive Cosmos
unity·游戏引擎
nnsix13 小时前
Unity OpenXR,扳机键交互UI时,必须按下扳机才触发
unity·游戏引擎
nnsix14 小时前
Unity XR 编辑器VR设备模拟功能
unity·编辑器·xr
老朱佩琪!14 小时前
Unity访问者模式
unity·游戏引擎·访问者模式
不定时总结的那啥14 小时前
Unity实现点击Console消息自动选中预制体的方法
unity·游戏引擎