全用 SceneManager
我以前纯用 SceneManager 的加载场景和卸载场景
很简单……为了赶工
对以下测试脚本,调用 LoadHome()
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using Universal;
public class AppController : Singleton<AppController>
{
private GameUI gameUI;
private void Start()
{
DontDestroyOnLoad(gameObject);
}
public void LoadHome()
{
StartCoroutine(WaitForLoadHome());
}
public IEnumerator WaitForLoadHome()
{
int oldSceneID = SceneManager.GetActiveScene().buildIndex;
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Scenes/LoadingScene", LoadSceneMode.Additive);
while (!asyncLoad.isDone)
{
yield return null;
}
asyncLoad = SceneManager.UnloadSceneAsync(oldSceneID);
while (!asyncLoad.isDone)
{
yield return null;
}
LoadingController.Instance.BeginLoading();
yield return LoadingController.Instance.SetProgress(100);
asyncLoad = SceneManager.LoadSceneAsync("Scenes/HomeScene", LoadSceneMode.Additive);
while (!asyncLoad.isDone)
{
yield return null;
}
asyncLoad = SceneManager.UnloadSceneAsync("Scenes/LoadingScene");
while (!asyncLoad.isDone)
{
yield return null;
}
HomeController.Instance.BeginHome();
}
public void LoadGame()
{
StartCoroutine(WaitForLoadGame());
}
private IEnumerator WaitForLoadGame()
{
int oldSceneID = SceneManager.GetActiveScene().buildIndex;
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Scenes/LoadingScene", LoadSceneMode.Additive);
while (!asyncLoad.isDone)
{
yield return null;
}
asyncLoad = SceneManager.UnloadSceneAsync(oldSceneID);
while (!asyncLoad.isDone)
{
yield return null;
}
LoadingController.Instance.BeginLoading();
yield return LoadingController.Instance.SetProgress(100);
asyncLoad = SceneManager.LoadSceneAsync("Scenes/GameScene", LoadSceneMode.Additive);
while (!asyncLoad.isDone)
{
yield return null;
}
asyncLoad = SceneManager.UnloadSceneAsync("Scenes/LoadingScene");
while (!asyncLoad.isDone)
{
yield return null;
}
GameController.Instance.BeginGame();
}
}
复制代码
谨慎使用 AsyncOperationHandle.WaitForCompletion()
然后换成 Addressables 之后就有问题了……具体的 Debug 代码像这样:
对以下测试脚本,调用 TestLoad()
public string loadingSceneAddress;
private AsyncOperationHandle loadHandle;
private IEnumerator TestLoad()
{
loadHandle = Addressables.LoadSceneAsync(loadingSceneAddress, LoadSceneMode.Additive);
loadHandle.Completed += OnSceneLoaded;
Debug.Log("============= 1 ================");
Debug.Log(loadHandle.Status);
Debug.Log(loadHandle.Result.Scene.isLoaded);
Debug.Log(SceneManager.sceneCount);
yield return loadHandle.WaitForCompletion();
Debug.Log("============= 2 ================");
Debug.Log(loadHandle.Status);
Debug.Log(loadHandle.Result.Scene.isLoaded);
Debug.Log(SceneManager.sceneCount);
yield return new WaitForEndOfFrame();
Debug.Log("============= 3 ================");
Debug.Log(loadHandle.Status);
Debug.Log(loadHandle.Result.Scene.isLoaded);
Debug.Log(SceneManager.sceneCount);
yield return new WaitForEndOfFrame();
Debug.Log("============= 5 ================");
Debug.Log(loadHandle.Status);
Debug.Log(loadHandle.Result.Scene.isLoaded);
Debug.Log(SceneManager.sceneCount);
}
private void OnSceneLoaded(AsyncOperationHandle obj )
{
Debug.Log("============= 4 ================");
Debug.Log(loadHandle.Status);
Debug.Log(loadHandle.Result.Scene.isLoaded);
Debug.Log(SceneManager.sceneCount);
}
复制代码
打印结果:
============= 1 ================
None
False
2
============= 2 ================
None
False
2
============= 3 ================
None
False
2
============= 4 ================
Succeeded
True
2
============= 5 ================
Succeeded
True
2
复制代码
可以看到他这个 WaitForCompletion() 是完全没有效果的
同时unity动态加载游戏对象,在 handle 的 WaitForCompletion() 前后,handle 的 Status 也是 None,我看了一下他这个 Status 的赋值,感觉是在引用计数为 0 的时候才赋的 None。那这就说明调用了 Addressables.LoadSceneAsync 之后 Status 是 None游戏动态,可能是因为还不知道是成功或者失败吧
但同时场上却有他这个 Addressables 想要 load 的场景,因为打印出来场景数量是 2unity动态加载游戏对象,但是这个场景却没有 loaded,就很奇怪,但是既然现在他 Completed 是有效的游戏开发素材,那也不管了
改为使用 Addressables
现在就可以实现场景 A 到场景 B 之间的切换有一个加载场景作为缓冲,并且能够显示加载进度条的功能了
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using Universal;
public class AppController : Singleton<AppController>
{
public string homeSceneAddress;
public string loadingSceneAddress;
public string gameSceneAddress;
private void Start()
{
DontDestroyOnLoad(gameObject);
}
public void LoadHome()
{
TryLoad(homeSceneAddress, () => HomeController.Instance.BeginHome());
}
public void LoadGame()
{
TryLoad(gameSceneAddress, () => GameController.Instance.BeginGame());
}
private void TryLoad(string nextSceneAddress, Action callback = null)
{
AsyncOperationHandle lastLoadHandle = Addressables.LoadSceneAsync(loadingSceneAddress, LoadSceneMode.Single);
lastLoadHandle.Completed += (AsyncOperationHandle op) =>
{
if(op.Status == AsyncOperationStatus.Succeeded)
{
LoadingController.Instance.BeginLoading();
StartCoroutine(WaitForLoading(lastLoadHandle, nextSceneAddress, callback));
}
};
}
private IEnumerator WaitForLoading(AsyncOperationHandle lastLoadHandle, string nextSceneAddress, Action callback = null )
{
AsyncOperationHandle currLoadHandle = Addressables.LoadSceneAsync(nextSceneAddress, LoadSceneMode.Additive);
// 新场景加载时刷新进度条
while (currLoadHandle.Status == AsyncOperationStatus.None)
{
LoadingController.Instance.SetPercent(currLoadHandle.PercentComplete);
yield return null;
}
// 如果新场景加载完毕
if(currLoadHandle.Status == AsyncOperationStatus.Succeeded)
{
// 进度条缓冲时间,免得 loading 界面一闪而过,给人晃眼的感觉
LoadingController.Instance.SetPercent(1f);
yield return new WaitForSeconds(0.5f);
// 卸载 loading 场景
Addressables.UnloadSceneAsync(lastLoadHandle)
.Completed += (AsyncOperationHandle op2) =>
{
if (op2.Status == AsyncOperationStatus.Succeeded)
{
callback?.Invoke();
}
};
}
yield return null;
}
}
复制代码