Unity 工具类 之 简单的异步场景加载(包含加载进度和同步加载方法)类 LoadSceneManager 实现
Unity 工具类 之 简单的异步场景加载(包含加载进度和同步加载方法)类 LoadSceneManager 实现
目录
一、简单介绍
Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。
简单的异步场景加载(包含加载进度和同步加载方法)类,单独做了一个单例类,提供加载场景方法和加载进度,供外界调用即可。
二、实现原理
1、单例类,保证整个场景中只有一个类管理场景加载;
2、LoadSceneManager.Instance.LoadSceneAsync 即可异步加载场景;
3、LoadSceneManager.Instance.LoadScene 即可同步加载场景;
4、LoadSceneManager.Instance.ProgressLoadSceneAsync 即可获取异步加载进度;
三、注意事项
1、枚举管理场景名称;
2、获取进度,根据实际情况进行转化,进度值范围为 0 ~ 100 之间;
四、效果预览
五、实现步骤
1、打开Unity,新建一个工程,新建一个 Start 场景,场景中布局一些场景加载进度的 UI,如下图
2、新建一个 Game 场景,布局添加一个 UI ,提示场景即可,如下图
3、新建脚本,单例类,场景加载管理类,和一个测试场景加载的类,如下图
4、把 测试类脚本挂载到 Start 场景中,并对应赋值,如下图
5、把场景添加到 Build Settings 中,如下图
6、运行场景,效果如下
六、关键代码
1、TestScript
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TestScript : MonoBehaviour
{
public Slider progressSlider;
public Text progressText;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) {
Debug.Log("GetKeyDown(KeyCode.Space)");
LoadSceneAsync();
}
}
void LoadSceneAsync() {
progressSlider.value = 0;
progressText.text = "进度";
LoadSceneManager.Instance.LoadSceneAsync(ScenesName.Game, ShowProgress, ()=> { Debug.Log("开始异步加载场景..."); }, () => { Debug.Log("开始异步加载完成,跳转场景"); } );
}
void ShowProgress(float progress) {
Debug.Log("progress:" + progress);
progressSlider.value = progress / 100;
progressText.text = "进度: " + progress +" %";
}
}
2、LoadSceneManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// 场景枚举
/// </summary>
public enum ScenesName {
Start,
Game,
}
public class LoadSceneManager : MonoSingleton<LoadSceneManager>
{
//异步加载对象
private AsyncOperation prog;
// 异步加载进度参数
int toProgress = 0;
int showProgress = 0;
// 异步加载事件
System.Action<float> loadingAction = null;
System.Action loadBeforeAction = null;
System.Action loadedEndAction = null;
/// <summary>
/// 同步加载场景
/// </summary>
/// <param name="scenesName">场景名称</param>
public void LoadScene(ScenesName scenesName) {
SceneManager.LoadScene(scenesName.ToString());
}
/// <summary>
/// 异步加载
/// </summary>
/// <param name="scenesName">场景名称</param>
/// <param name="loadingAction">加载中的事件</param>
/// <param name="loadBeforeAction">异步加载前的事件</param>
/// <param name="loadedEndAction">异步加载完成后的事件</param>
public void LoadSceneAsync(ScenesName scenesName, System.Action<float> loadingAction = null, System.Action loadBeforeAction = null, System.Action loadedEndAction = null) {
// 事件赋值
this.loadBeforeAction = loadBeforeAction;
this.loadingAction = loadingAction;
this.loadedEndAction = loadedEndAction;
StartCoroutine(LoadingScene(scenesName));
}
/// <summary>
/// 异步加载进度
/// </summary>
/// <returns></returns>
public float ProgressLoadSceneAsync() {
return showProgress;
}
/// <summary>
/// 协程加载场景
/// </summary>
/// <param name="scenesName">场景名称</param>
/// <param name="loadingAction">加载中的事件</param>
/// <param name="loadBeforeAction">异步加载前的事件</param>
/// <param name="loadedEndAction">异步加载完成后的事件</param>
/// <returns></returns>
private IEnumerator LoadingScene(ScenesName scenesName)
{
// 异步加载前的事件
if (this.loadBeforeAction != null) {
this.loadBeforeAction.Invoke();
}
prog = SceneManager.LoadSceneAsync(scenesName.ToString()); //异步加载场景
prog.allowSceneActivation = false; //如果加载完成,也不进入场景
toProgress = 0;
showProgress = 0;
//测试了一下,进度最大就是0.9
while (prog.progress < 0.9f)
{
toProgress = (int)(prog.progress * 100);
while (showProgress < toProgress)
{
showProgress++;
// 异步加载中的事件
if (this.loadingAction != null)
{
this.loadingAction.Invoke(showProgress);
}
}
yield return new WaitForEndOfFrame(); //等待一帧
}
//计算0.9---1 其实0.9就是加载好了,我估计真正进入到场景是1
toProgress = 100;
while (showProgress < toProgress)
{
showProgress++;
// 异步加载中的事件
if (this.loadingAction != null)
{
this.loadingAction.Invoke(showProgress);
}
yield return new WaitForEndOfFrame(); //等待一帧
}
// 异步加载完成后的事件
if (this.loadedEndAction != null)
{
this.loadedEndAction.Invoke();
}
yield return new WaitForEndOfFrame(); //等待一帧
prog.allowSceneActivation = true; //如果加载完成,进入场景
}
}
3、MonoSingleton
using UnityEngine;
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance = null;
private static readonly object locker = new object();
private static bool bAppQuitting;
public static T Instance
{
get
{
if (bAppQuitting)
{
instance = null;
return instance;
}
lock (locker)
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if (FindObjectsOfType<T>().Length > 1)
{
Debug.LogError("不应该存在多个单例!");
return instance;
}
if (instance == null)
{
var singleton = new GameObject();
instance = singleton.AddComponent<T>();
singleton.name = "(singleton)" + typeof(T);
singleton.hideFlags = HideFlags.None;
DontDestroyOnLoad(singleton);
}
else
DontDestroyOnLoad(instance.gameObject);
}
instance.hideFlags = HideFlags.None;
return instance;
}
}
}
private void Awake()
{
bAppQuitting = false;
}
private void OnDestroy()
{
bAppQuitting = true;
}
}