多场景加载

       我们在使用一些插件的时候,往往都会同步加载出来另外一个场景,这个场景会和我们现有的一个场景共存,而这个场景里面一般只会有一些脚本代码,或是一些UI,那么这个到底有什么用处呢

        前段时间想要封装一个插件,但是卡在了多线程处理上面,原因当然就是unity根本就没办法使用线程,但是我很多东西都需要时间,而递归或是其他的一些我能想到的方法都是会阻塞main线程的,那么,可不可以在某个地方挂上一个脚本,通过系统自带的invoke也好自己写的也好(更好,因为自己写的熟悉度比较高,而且可以支持更多的东西),总之,就是有一个继承了MonoBehaviour的脚本来让我们进行时间上的一些操作呢。。。但是,想一下,我们就会知道,我们创建的场景并不会按照Unity里面自带的一样,有可能一个失误,场景里面没有Main相机,或是没有某些我们可以直接调用的物体,这个时候我们就出现了一些很尴尬的事情,当然你可以直接new一个GameObject,在相应的构造函数或是其他的地方,

        那么,第二个,假设我们需要制作一个游戏,游戏有很多场景,猪脚,UI等,那么我们的猪脚和UI不可能每个场景里面都Resources或是直接放置上去,而是应该放在一个整个游戏运行只会出现一次,而且也不会被卸载的位置,这个时候,我们也是必须使用多场景进行加载,或是说进行一个场景的单例。。。

       总结,多场景,其实就是在一定程度上模拟场景的单例和多线程的一个模拟方式,当然,还有更多用处,比如在临时加载,或是临时场景进行更新数据之类的,这里暂时只是随便说几个。。。

==================================================================================================

       多场景的加载其实很简单,只是我们必须在加载完成之后将加载的场景进行一个“设置为当前活动状态”(我们脚本默认生成物体是会生成在当前活动场景的),

UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);

UnityEngine.SceneManagement.SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);


Scene scene = default(Scene);
for (int i = 0; i < SceneManager.sceneCount; i++)
{
    if (SceneManager.GetSceneAt(i).name == sceneName)
    {
       scene = SceneManager.GetSceneAt(i);
    }
}
SceneManager.SetActiveScene(scene);

后面那一个枚举,意思就是我现在需要加载的场景是要和我现在这个场景并存的

第三行则是前面说的,把加载出来的场景进行设置为活动场景,但是注意,这个接受的是Scene类型,所以我们必须先找到这个场景,在设置其激活,

注意:如果你就这样写,代码肯定是会报错的,他会提示你场景并未被加载,无法设置激活状态,这是因为我们虽然进行了加载场景,但是其实场景还没有被加载完成,Unity会认为这个场景根本没有被加载,但是我们的面板上面却已经出现了这个场景,所以SceneManager.GetSceneAt(i)可以找到相应的场景。

       关于这种情况,我们可以可以使用一步加载场景,在进度到达100的时候在设置其激活状态

    private AsyncOperation async;
    private int ToJourney, YetJourney;
    IEnumerator Loading(string sceneName)
    {
        async = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
        async.allowSceneActivation = false;
        while (async.progress < 0.9f)
        {
            ToJourney = (int)(async.progress * 100);
            while (YetJourney < ToJourney)
            {
                YetJourney++;
                ChangeAsyncLoadSceneUI_Slider(YetJourney);
                yield return new WaitForEndOfFrame();
            }
            yield return new WaitForEndOfFrame();
        }
        while (true)
        {
            ToJourney = 100;
            while (YetJourney < ToJourney)
            {
                YetJourney++;
                ChangeAsyncLoadSceneUI_Slider(YetJourney);
                yield return new WaitForEndOfFrame();
            }
            async.allowSceneActivation = true;
            yield return async;
            
            Scene scene = default(Scene);
            for (int i = 0; i < SceneManager.sceneCount; i++)
            {
                if (SceneManager.GetSceneAt(i).name == sceneName)
                {
                    scene = SceneManager.GetSceneAt(i);
                }
            }
            // 在我们加载完成后,可以在这里选择时候卸载我们上一个场景,因为我是加载了三个场景,
            // 其中只有一个不需要卸载,所以才这样写
            SceneManager.UnloadScene(SceneManager.GetActiveScene());
            // 注意 这里会和Awake相差一帧左右,所以最好写个bool判断场景是否加载完成
            // M_Manager.AsyncLoadSceneSuccess = true;
            // 加载完成,设置其激活
            SceneManager.SetActiveScene(scene);
            break;
        }
    }
     private void ChangeAsyncLoadSceneUI_Slider(int value)
    {
        Slider_value.text = "进度->" + value + "%";
        AsyncSlider.value = value;
    }

这样,我们就在加载其他场景的时候就不会卸载我们需要的场景,注意,上面的UnloadScene是需要根据你们代码进行修改的,否则有很大可能把你们不想卸载的场景卸载

放张运行图 ->

        在这里说一哈,由于我是把猪脚,猪脚UI,异步加载场景UI都放在了UIScene场景里面,所以,在test2 场景加载的时候会出现加载的进度,而在UIScene加载的时候则没有(毕竟异步加载UI的那个场景都没有被加载 ~)

        而UIScene场景里面我放置了两个相机,平时时候加载场景的相机和加载场景UI(Slider)是隐藏的,而猪脚相应UI的mode则是 RenderMode.ScreenSpaceOverlay,而一旦加载开始,会出现两个相机并存的情况,但是渲染猪脚和主要UI的相机由于Depth比进度值小,所以主相机会被无视,而UI则会在这个时候被更新为RenderMode.ScreenSpaceCamera,看向猪脚相机,这样,相关的UI和相机猪脚等就不会影响到我场景加载UI

猜你喜欢

转载自blog.csdn.net/MikuLingSSS/article/details/85383607