unity scene 无缝切换(缓存)
来源:互联网 发布:网络流行歌曲大全 编辑:程序博客网 时间:2024/06/08 17:29
场景切换的时候经常会造成卡顿,导致用户体验并不好。
如何能做到不卡呢,有一种方式是做成prefab,然后通过启用禁用来模拟切场景,但是现在遇到的情况是希望烘焙出的lightmap也能够进行切换。而在unity5中动态的去切lightmap有点麻烦,没有去深入研究,于是采用了下面缓存场景的做法。
假设场景切换顺序:Main->A->B->C->Main
从Main场景切到A,A加载完后希望在A运行的同时能够缓存B场景。这样待会从B切到C时B因为已经缓存过了,加载耗时会比较短,B加载同时又缓存C场景,缓存C的过程不会造成B的卡顿,之后会有解释。
异步切换场景的核心代码如下
LoadAsyncApi(ref _curResult,_curSceneName);yield return StartCoroutine(LoadInProgress(_curResult));yield return StartCoroutine(LoadAfterProgress(_curResult, _curSceneName)); private void LoadAsyncApi(ref AsyncOperation result,string sceneName) { result = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); } //0-0.9 private IEnumerator LoadInProgress(AsyncOperation result) { result.allowSceneActivation = false; while (result.progress < 0.9f) { yield return null; } } //0.9-1(start awake ,not include coroutine) private IEnumerator LoadAfterProgress(AsyncOperation result,string sceneName ) { result.allowSceneActivation = true; while (!SceneManager.GetSceneByName(sceneName).isLoaded) { yield return null; } }
调用LoadSceneAsyc异步加载,然后将之后的加载分为两步。
allowSceneActivation很多帖子写的都很懵逼,今天我来讲清楚。。。
1. 0-0.9(阶段1)
allowSceneActivation设为false的时候,阻止Scene的完全激活,这时进度会一直卡在0.9。这个阶段会做一些磁盘相关的IO操作,比如载入资源等,这些操作不会阻塞当前主线程。当你的场景中引用了比较多的material啊,texture啊,那很多时间会花费在这里。
2. 0.9-1(阶段2)
将allowSceneActivation设为true,这个过程做的事情包括所有的awake,start函数的执行以及setactive的时间,应该也包括所有组件如collider,animator内部初始化相关的操作。通过实验发现,直接在场景中加入成千上万个立方体,最后场景加载的时间基本都花在这个阶段。你手动启用这些物体也是会造成卡顿的。这一步会造成主进程阻塞,会使得unity难以避免的卡顿,这一步暂无办法去优化。了解了这两步之后,实现这个需求就很清楚了。
Main切A加载B:
执行A的阶段1,阶段2,unload掉Main,再执行B的阶段1,让B卡在progress为0.9的位置。真正加载B的时候再执行B的阶段2。如果说场景中没有大量物体,而引用的资源又大又多,是可以做到秒切场景的。
提供了两个函数,EnterScene需要提供切换到的场景和需要缓存的场景。当不需要走这套机制,直接从场景中跳出到别的场景时,直接将precachescene设为null或者直接调用EnterOutScene退出即可。
完整代码:
DialogSceneMgr
using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Runtime.CompilerServices;using UnityEngine.SceneManagement;public class DialogSceneMgr : Singleton<DialogSceneMgr>{ private string _curSceneName; private string _precacheSceneName; private bool _fromOuterScene = false; private AsyncOperation _curResult; private AsyncOperation _precacheResult; void OnGUI() { if (GUILayout.Button("BaseLight2 cache BaseLight", GUILayout.Width(200))) { EnterScene("BaseLight2", "BaseLight"); //DialogSceneMgr.Instance.InitScenes(new List<string>() { "BaseLight", "BaseLight2" }); } if (GUILayout.Button("BaseLight cache Context", GUILayout.Width(200))) { EnterScene("BaseLight","Context"); } if (GUILayout.Button("SwitchOut", GUILayout.Width(200))) { EnterOuterScene("Context"); }// if (GUILayout.Button("BaseLight2", GUILayout.Width(200)))// {// EnterScene("BaseLight2", null);// }// if (GUILayout.Button("BaseLight", GUILayout.Width(200)))// {// EnterScene("BaseLight", null);// } if (_curResult!=null) GUILayout.TextArea("CurProgress:" + _curResult.progress); if (_precacheResult != null) GUILayout.TextArea("PrecacheProgress:" + _precacheResult.progress); } public void EnterScene(string sceneName,string precacheSceneName ) { _curSceneName = sceneName; //没有precache的scene说明是第一次进入 _fromOuterScene = string.IsNullOrEmpty(_precacheSceneName); //缓存的场景和即将进入的场景不一致直接Load场景 if (_curSceneName != _precacheSceneName && !_fromOuterScene) { Clear(); SceneManager.LoadScene(_curSceneName); return; } _precacheSceneName = precacheSceneName; StartCoroutine(LoadSceneCor()); } private void Clear() { _precacheSceneName = null; } public void EnterOuterScene(string sceneName) { EnterScene(sceneName, null); } private IEnumerator LoadSceneCor() { //from prev to cur if (_fromOuterScene) { LoadAsyncApi(ref _curResult,_curSceneName); yield return StartCoroutine(LoadInProgress(_curResult)); yield return StartCoroutine(LoadAfterProgress(_curResult, _curSceneName)); } else { _curResult = _precacheResult; yield return StartCoroutine(LoadAfterProgress(_curResult, _curSceneName)); } UnLoadPrevScene(); SetActiveScene(_curSceneName); //precache next Debug.Log("precache next"); //没有缓存场景了,不需要缓存 if (string.IsNullOrEmpty(_precacheSceneName)) { yield break; } LoadAsyncApi(ref _precacheResult,_precacheSceneName); yield return StartCoroutine(LoadInProgress(_precacheResult)); } private void UnLoadPrevScene() { Scene prevScene = SceneManager.GetActiveScene(); SceneManager.UnloadScene(prevScene.name); } private void SetActiveScene(string sceneName) { SceneManager.SetActiveScene(SceneManager.GetSceneByName(sceneName)); } //0-0.9 private IEnumerator LoadInProgress(AsyncOperation result) { result.allowSceneActivation = false; while (result.progress < 0.9f) { yield return null; } } private void LoadAsyncApi(ref AsyncOperation result,string sceneName) { result = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); } //0.9-1(start awake ,not include coroutine) private IEnumerator LoadAfterProgress(AsyncOperation result,string sceneName ) { result.allowSceneActivation = true; while (!SceneManager.GetSceneByName(sceneName).isLoaded) { yield return null; } }}
附singleton
using System;using UnityEngine;using System.Collections;public class Singleton<T> : MonoBehaviour where T : Singleton<T>{ private static T mInstance; private static bool isQuiting; public static T Instance { get { if (mInstance == null && !isQuiting) { mInstance = new GameObject("(Singleton) " + typeof (T).Name).AddComponent<T>(); } return mInstance; } } private void Awake() { T instance = this as T; if (mInstance != null && mInstance != instance) { T cacheInstance = mInstance;//因为下一步destroy的时候更改了static的mInstance DestroyImmediate(this.gameObject); mInstance = cacheInstance; return; } // 切换场景不要销毁GameObject DontDestroyOnLoad(gameObject); mInstance = instance; OnInit(); } private void OnDestroy() { OnRelease(); mInstance = null; } private void OnApplicationQuit() { isQuiting = true; } /// <summary> /// 初始化 /// </summary> protected virtual void OnInit() { } /// <summary> /// 释放 /// </summary> protected virtual void OnRelease() { }}
- unity scene 无缝切换(缓存)
- Unity--无缝场景切换
- scene切换
- Unity无缝地图研究
- Unity无缝地图研究
- unity 无缝大地图
- JavaScript打造无缝切换
- js实现无缝切换
- 无缝切换SVN服务器
- android wifi 无缝切换
- 无缝切换功能
- 无缝轮播切换
- 内外网无缝切换
- [1]时钟无缝切换
- 无缝切换轮播图
- Unity Scene 数据迁移研究
- Unity Scene场景自定义坐标轴
- android 视频 无缝切换 无缝播放 surfaceview
- IOS 图形验证码的封装
- OracleBulkCopy 批量插入oracle数据库的方法
- varchar(10)和char(10)的区别?存入abc字符串
- 机器学习资料
- 2014年黑马第九期JAVAEE+hadoop大数据 全套下载
- unity scene 无缝切换(缓存)
- Sphinx参考手册(八)
- angularjs项目目录
- python学习作业D1
- 怎么解决访问所有HTTPS网站显示连接不安全
- .htaccess技巧: URL重写(Rewrite)
- 大屏时代的生态变迁_看平板手机的拇指热键与界面布局
- android中?attr/**与@drawable/**或@color/**等的区别
- 在不同编译器下数据类型占用字节大小