您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
286 行
9.5 KiB
286 行
9.5 KiB
using System.Collections;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.SceneManagement;
|
|
using System.Linq;
|
|
|
|
namespace GameplayIngredients.LevelStreaming
|
|
{
|
|
[ManagerDefaultPrefab("LevelStreamingManager")]
|
|
public class LevelStreamingManager : Manager
|
|
{
|
|
public enum StreamingAction
|
|
{
|
|
Load,
|
|
Unload,
|
|
Replace
|
|
}
|
|
|
|
[Header("UI Configuration")]
|
|
public GameObject LoadingRoot;
|
|
public GameObject LoadingIcon;
|
|
public GameObject ProgressBar;
|
|
public GameObject ProgressBarContainer;
|
|
public Text LoadingText;
|
|
public Text PercentageText;
|
|
|
|
[Header("Behavior")]
|
|
[Min(0.0f)]
|
|
public float DelayBeforeLoad = 0.0f;
|
|
[Min(0.0f)]
|
|
public float DelayAfterLoad = 0.0f;
|
|
|
|
[Header("Debug")]
|
|
public Text DebugText;
|
|
public bool EnableDebug = false;
|
|
|
|
private float[] percentages;
|
|
private AsyncOperation[] asyncOperations;
|
|
|
|
public void LoadScenes(StreamingAction action, string[] scenes, string sceneToActivate, bool showUI, Callable[] onLoadComplete, bool replace = false)
|
|
{
|
|
if (EnableDebug)
|
|
DebugText.gameObject.SetActive(true);
|
|
|
|
List<string> requiredScenes = new List<string>();
|
|
|
|
foreach (string scene in scenes)
|
|
{
|
|
if (
|
|
(SceneManager.GetSceneByName(scene).isLoaded && action == StreamingAction.Unload)
|
|
|| (!SceneManager.GetSceneByName(scene).isLoaded && action == StreamingAction.Load)
|
|
|| (action == StreamingAction.Replace)
|
|
)
|
|
{
|
|
requiredScenes.Add(scene);
|
|
}
|
|
}
|
|
|
|
int count = requiredScenes.Count;
|
|
|
|
if (showUI)
|
|
LoadingRoot.SetActive(true);
|
|
|
|
if (LoadingIcon != null)
|
|
LoadingIcon.SetActive(true);
|
|
|
|
if (count > 0)
|
|
StartCoroutine(LoadScenesCoroutine(action, requiredScenes, sceneToActivate, showUI, onLoadComplete));
|
|
else
|
|
{
|
|
Debug.LogWarning("Did not find any candidates to load or unload...");
|
|
|
|
if (onLoadComplete != null)
|
|
Callable.Call(onLoadComplete);
|
|
|
|
if (showUI)
|
|
LoadingRoot.SetActive(false);
|
|
|
|
if (LoadingIcon != null)
|
|
LoadingIcon.SetActive(false);
|
|
|
|
if (EnableDebug)
|
|
DebugText.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
IEnumerator LoadScenesCoroutine(StreamingAction action, List<string> scenes, string sceneToActivate, bool showUI, Callable[] onLoadComplete)
|
|
{
|
|
LogDebugInformation("START LOAD/UNLOAD FOR LEVELS...");
|
|
LoadingText.text = "Loading...";
|
|
SetProgressBar(0.0f, true);
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
if (DelayBeforeLoad >= 0.0f)
|
|
yield return new WaitForSeconds(DelayBeforeLoad);
|
|
|
|
int count = scenes.Count;
|
|
|
|
percentages = new float[count];
|
|
asyncOperations = new AsyncOperation[count];
|
|
|
|
switch (action)
|
|
{
|
|
case StreamingAction.Replace:
|
|
LogDebugInformation("[*] ASYNC REPLACE FOR: " + scenes);
|
|
StartCoroutine(LoadLevelCoroutine(scenes, sceneToActivate));
|
|
break;
|
|
case StreamingAction.Load:
|
|
LogDebugInformation("[*] ASYNC LOAD FOR: " + scenes);
|
|
StartCoroutine(LoadLevelCoroutine(scenes));
|
|
break;
|
|
case StreamingAction.Unload:
|
|
LogDebugInformation("[*] ASYNC UNLOAD FOR: " + scenes);
|
|
StartCoroutine(UnloadLevelCoroutine(scenes));
|
|
break;
|
|
default: throw new NotImplementedException("LoadScenesCoroutine does not handle mode " + action.ToString());
|
|
}
|
|
|
|
if(action == StreamingAction.Replace)
|
|
{
|
|
while (!asyncOperations[0].isDone)
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
// Wait for all scenes to be loaded
|
|
while (asyncOperations.Any(a => !a.isDone))
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
// Then change active scene
|
|
if (!string.IsNullOrEmpty(sceneToActivate) && action != StreamingAction.Replace)
|
|
{
|
|
var newActive = SceneManager.GetSceneByName(sceneToActivate);
|
|
SceneManager.SetActiveScene(newActive);
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
if(DelayAfterLoad >= 0.0f)
|
|
{
|
|
SetProgressBar(1.0f, true);
|
|
yield return new WaitForSeconds(DelayAfterLoad);
|
|
}
|
|
|
|
if (onLoadComplete != null)
|
|
Callable.Call(onLoadComplete);
|
|
|
|
if (showUI)
|
|
LoadingRoot.SetActive(false);
|
|
|
|
if (LoadingIcon != null)
|
|
LoadingIcon.SetActive(false);
|
|
|
|
if (EnableDebug)
|
|
DebugText.gameObject.SetActive(false);
|
|
}
|
|
|
|
void UpdatePercentage()
|
|
{
|
|
for (int i = 0; i < asyncOperations.Length; i++)
|
|
percentages[i] = asyncOperations[i].progress;
|
|
|
|
float percentage = percentages.Sum() / percentages.Length;
|
|
SetProgressBar(percentage);
|
|
}
|
|
|
|
private IEnumerator LoadLevelCoroutine(List<string> sceneNames, string singleScene = "")
|
|
{
|
|
// Manage Single Scene Loading
|
|
int offset = 0;
|
|
if (sceneNames.Contains(singleScene))
|
|
{
|
|
asyncOperations[0] = SceneManager.LoadSceneAsync(singleScene, LoadSceneMode.Single);
|
|
asyncOperations[0].allowSceneActivation = true;
|
|
sceneNames.Remove(singleScene);
|
|
|
|
while (!asyncOperations[0].isDone)
|
|
{
|
|
SetProgressBar(asyncOperations[0].progress / Math.Max(sceneNames.Count,1));
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
offset = 1;
|
|
}
|
|
|
|
for (int i = 0; i < sceneNames.Count; i++)
|
|
{
|
|
asyncOperations[i + offset] = SceneManager.LoadSceneAsync(sceneNames[i], LoadSceneMode.Additive);
|
|
asyncOperations[i + offset].allowSceneActivation = false;
|
|
}
|
|
|
|
while (asyncOperations.Any(a => a.progress < 0.9f))
|
|
{
|
|
UpdatePercentage();
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
// Activate scenes
|
|
foreach (var a in asyncOperations)
|
|
a.allowSceneActivation = true;
|
|
|
|
LoadingText.text = "Starting...";
|
|
LogDebugInformation("All scenes loaded");
|
|
|
|
while (asyncOperations.Any(a => !a.isDone))
|
|
{
|
|
UpdatePercentage();
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
LogDebugInformation("All scenes activated");
|
|
}
|
|
|
|
private IEnumerator UnloadLevelCoroutine(List<string> sceneNames)
|
|
{
|
|
for (int i = 0; i < sceneNames.Count; i++)
|
|
{
|
|
if (!SceneManager.GetSceneByName(sceneNames[i]).isLoaded)
|
|
{
|
|
LogDebugInformation("SKIP UNLOAD: " + sceneNames + " (NOT LOADED)");
|
|
continue;
|
|
}
|
|
asyncOperations[i] = SceneManager.UnloadSceneAsync(sceneNames[i]);
|
|
asyncOperations[i].allowSceneActivation = false;
|
|
}
|
|
|
|
// Remove nulls
|
|
asyncOperations = asyncOperations.Where(a => a != null).ToArray();
|
|
|
|
LoadingText.text = "Unloading...";
|
|
|
|
while (asyncOperations.Any(a => a.progress < 1.0f))
|
|
{
|
|
UpdatePercentage();
|
|
yield return new WaitForEndOfFrame();
|
|
}
|
|
|
|
LogDebugInformation("Unloaded all scenes");
|
|
}
|
|
|
|
private float m_CurrentPercentage = 0.0f;
|
|
private float m_TargetPercentage = 0.0f;
|
|
|
|
private void SetProgressBar(float percentage, bool direct = false)
|
|
{
|
|
m_TargetPercentage = percentage;
|
|
if (direct)
|
|
m_CurrentPercentage = m_TargetPercentage;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
// Smoothen bar
|
|
m_CurrentPercentage = Mathf.Lerp(m_CurrentPercentage, m_TargetPercentage, 10 * Time.deltaTime);
|
|
|
|
// Update UI
|
|
PercentageText.text = ((int)(m_CurrentPercentage * 100)) + "%";
|
|
Vector2 size = ProgressBar.GetComponent<RectTransform>().sizeDelta;
|
|
size.x = m_CurrentPercentage * ProgressBarContainer.GetComponent<RectTransform>().sizeDelta.x;
|
|
ProgressBar.GetComponent<RectTransform>().sizeDelta = size;
|
|
|
|
//Debug
|
|
if (EnableDebug)
|
|
{
|
|
var sb = new System.Text.StringBuilder();
|
|
int count = SceneManager.sceneCount;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var s = SceneManager.GetSceneAt(i);
|
|
sb.AppendLine(string.Format("{0} : {1}", s.name, s.isLoaded ? "loaded" : "unloaded"));
|
|
}
|
|
|
|
DebugText.text = sb.ToString();
|
|
}
|
|
|
|
}
|
|
|
|
private void LogDebugInformation(string text)
|
|
{
|
|
if(EnableDebug)
|
|
Debug.Log(text);
|
|
}
|
|
|
|
}
|
|
}
|