147 lines
4.6 KiB
C#
147 lines
4.6 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
|
|
namespace A2W
|
|
{
|
|
public class SceneLoader : Singleton<SceneLoader>
|
|
{
|
|
ITransition currentTransition; // 当前的过场实例
|
|
Canvas canvas;
|
|
|
|
public bool isPreLoading { get; set; } = false; // 预加载中
|
|
|
|
public Action OnFinished; // 转场结束
|
|
|
|
bool isLoading = false;// 现在是否可以转场
|
|
WaitForSeconds leastTime;
|
|
|
|
|
|
public void Init()
|
|
{
|
|
GameObject go = new GameObject();
|
|
go.name = "LoadingCanvas";
|
|
go.transform.SetParent(transform, false);
|
|
|
|
canvas = go.AddComponent<Canvas>();
|
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
canvas.sortingOrder = 1000;
|
|
|
|
CanvasScaler canvasScaler = go.AddComponent<CanvasScaler>();
|
|
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
|
canvasScaler.referenceResolution = new Vector2(Screen.width, Screen.height);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 使用转场加载场景
|
|
/// </summary>
|
|
/// <param name="SceneName">场景名称</param>
|
|
/// <param name="transition">转场方式</param>
|
|
/// <param name="hasPreload">是否有预加载</param>
|
|
/// <param name="leastTime">至少等待一定时间</param>
|
|
public void LoadScene(string SceneName, ITransition transition = null, bool hasPreload = false, float leastSecond = 0.2f)
|
|
{
|
|
// 如果现在不能转换场景直接返回
|
|
if (isLoading) return;
|
|
|
|
if (canvas is null)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
isPreLoading = hasPreload;
|
|
leastTime = new WaitForSeconds(leastSecond);
|
|
|
|
currentTransition = transition;
|
|
|
|
// 如果有设置过场就设置过场
|
|
if (transition is not null)
|
|
{
|
|
currentTransition.Init(canvas.transform);
|
|
}
|
|
|
|
// 开始转换场景
|
|
StartCoroutine(LoadLevel(SceneName));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换场景并且使用过场动画
|
|
/// </summary>
|
|
/// <param name="levelName">场景名称</param>
|
|
/// <returns></returns>
|
|
private IEnumerator LoadLevel(string levelName)
|
|
{
|
|
// 异步加载场景
|
|
AsyncOperation loading = SceneManager.LoadSceneAsync(levelName);
|
|
|
|
// 不允许场景加载完后直接转换
|
|
loading.allowSceneActivation = false;
|
|
|
|
// 现在不再能转换场景
|
|
isLoading = true;
|
|
|
|
|
|
if (currentTransition is not null)
|
|
{
|
|
// 开始过场
|
|
currentTransition.Begin();
|
|
|
|
// 等待一帧
|
|
// 理由再下面有解释,但其实这里本来不需要,因为检查动画前还夹着一个检查加载的过程。基本不会在一帧内就加载完
|
|
// 但是保险起见还是在播放动画后延迟一帧
|
|
yield return null;
|
|
|
|
// 至少等待一定时间
|
|
yield return leastTime;
|
|
|
|
|
|
// 等待动画播放完成
|
|
while (!currentTransition.IsDone())
|
|
yield return null;
|
|
}
|
|
|
|
// 等待场景加载几乎完成
|
|
while (loading.progress < 0.899)
|
|
yield return null;
|
|
|
|
// 允许场景加载完成
|
|
loading.allowSceneActivation = true;
|
|
|
|
// 等待场景加载彻底完成
|
|
while (loading.progress != 1)
|
|
yield return null;
|
|
|
|
//等待预加载完毕
|
|
while (isPreLoading)
|
|
yield return null;
|
|
|
|
if (currentTransition is not null)
|
|
{
|
|
// 结束过场
|
|
currentTransition.Finish();
|
|
|
|
// 等待一帧
|
|
// 因为我发现如果在开始动画后不等待一帧的话,第二个动画其实还没开始播放,
|
|
// 后面检测动画完成检测的就是第一个动画,就起不到检测第二个动画的作用。
|
|
yield return null;
|
|
|
|
// 至少等待一定时间
|
|
yield return leastTime;
|
|
|
|
// 等待动画播放完成
|
|
while (!currentTransition.IsDone())
|
|
yield return null;
|
|
}
|
|
|
|
// 可以继续转换场景
|
|
isLoading = false;
|
|
OnFinished?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|