unity版本5.3以上
网上很多异步加载场景实际上没有做到异步的功能,大部分是显示一个进度条,然后同时在执行异步加载代码,这实际上并未异步加载,这只是后台加载,并且性能上比同步加载慢,原因如下:
SceneManager.LoadSceneAsync 这个方法会在后台启动一个线程去加载场景,如果同时显示加载的进度条,这个进度条为主线程,这里就有两个线程在去抢占资源,因此从时间来讲,肯定比直接加载场景要慢。
那么问题来了,如何做到无延迟加载呢,前提条件:假设设备的资源是足够去同时加载两个场景。只需要在运行的场景内,提前把下一个要用的场景加载好,切换场景时无需再加载场景资源,这样处理后切换基本上是无延迟切换。
示例代码如下:
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 此类提供异步缓存加载场景(目前仅支持缓存加载一个场景),注意:在unity编辑器里调试时,异步加载会阻塞主线程,打包后,异步加载不会阻塞主线程,
/// 具体参考: https://forum.unity3d.com/threads/scenemanager-loadsceneasync-not-working-as-expected.369714/
/// </summary>
public class CacheSceneManager : MonoBehaviour {
public static CacheSceneManager _instance;
/// <summary>
/// 预加载场景名称
/// </summary>
public string CacheSceneName;
private AsyncOperation async;
private bool cacheFinish = false;
private bool cacheStart = true;
private bool startLoadScene = false;
private long startLoadTime = 0;
private long cacheAfterSeconds = 2;
void Awake()
{
//设置后台加载线程的优
Application.backgroundLoadingPriority = ThreadPriority.BelowNormal;
cacheFinish = false;
_instance = this;
if (CacheSceneName!=null) {
CacheSceneManager._instance.cacheScene(CacheSceneName);
}
}
private void cacheScene(string name) {
CacheSceneName = name;
cacheFinish = false;
cacheStart = false;
startLoadScene = false;
startLoadTime = 0;
async = null;
}
void Update()
{
//在脚本加载完成后延迟2秒钟开始缓存,避免和主场景抢占资源,具体时间可根据主场景的大小以及实际情况来设置
if (!cacheStart) {
if (startLoadTime==0) {
startLoadTime = getCurrentTimeSeconds();
}
if ((getCurrentTimeSeconds() - startLoadTime) > cacheAfterSeconds) {
cacheStart = true;
Debug.Log(CacheSceneName + " start async cache---------------------->" + getCurrentTimeSeconds());
async = SceneManager.LoadSceneAsync(CacheSceneName);
async.allowSceneActivation = false;
}
}
if (async!=null) {
//如果加载完成则更新标记
if (async.progress == 0.9f && !cacheFinish)
{
cacheFinish = true;
Debug.Log(CacheSceneName + " end async cache--------------------------> use Time:" + (getCurrentTimeSeconds() - startLoadTime- cacheAfterSeconds));
}
//加载完成后,检测到切换场景时,加载缓存场景
if (async.progress == 0.9f && startLoadScene)
{
async.allowSceneActivation = true;
}
}
}
//需要加载缓存场景时调用 CacheSceneManager._instance.startLoad();
public void startLoad() {
startLoadScene = true;
}
public static long getCurrentTimeSeconds()
{
return ConvertDateTimeToInt(System.DateTime.Now) / 1000;
}
public static long ConvertDateTimeToInt(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
long t = (time.Ticks - startTime.Ticks) / 10000;
return t;
}
}
注意:在unity编辑器里调试时,异步加载会阻塞主线程,打包后,异步加载不会阻塞主线程,
具体参考: https://forum.unity3d.com/threads/scenemanager-loadsceneasync-not-working-as-expected.369714/