|
|
|
|
|
|
using System.Collections.Generic; |
|
|
|
using UnityEngine; |
|
|
|
using UnityEngine.SceneManagement; |
|
|
|
using UnityEngine.UI; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// This class manages the scene loading and unloading.
|
|
|
|
|
|
|
{ |
|
|
|
[Header("Initialization Scene")] |
|
|
|
[SerializeField] private GameSceneSO _initializationScene = default; |
|
|
|
[Header("Persistent Manager Scene")] |
|
|
|
[SerializeField] private GameSceneSO _persistentManagersScene = default; |
|
|
|
[Header("Load on start")] |
|
|
|
[SerializeField] private GameSceneSO[] _mainMenuScenes = default; |
|
|
|
[Header("Gameplay Scene")] |
|
|
|
[SerializeField] private GameSceneSO _gameplayScene = default; |
|
|
|
[Header("Loading Screen")] |
|
|
|
[SerializeField] private GameObject _loadingInterface = default; |
|
|
|
[SerializeField] private Image _loadingProgressBar = default; |
|
|
|
[Header("Load Events")] |
|
|
|
//The location load event we are listening to
|
|
|
|
[SerializeField] private LoadEventChannelSO _loadLocation = default; |
|
|
|
//The menu load event we are listening to
|
|
|
|
[SerializeField] private LoadEventChannelSO _loadMenu = default; |
|
|
|
[Header("Load Event")] |
|
|
|
//The load event we are listening to
|
|
|
|
[SerializeField] private LoadEventChannelSO _loadEventChannel = default; |
|
|
|
[Header("Broadcasting on")] |
|
|
|
[SerializeField] private BoolEventChannelSO _ToggleLoadingScreen = default; |
|
|
|
[SerializeField] private VoidEventChannelSO _OnSceneReady = default; |
|
|
|
private List<GameSceneSO> _persistentScenes = new List<GameSceneSO>(); //Scenes to keep loaded when a load event is raised
|
|
|
|
_loadEventChannel.OnLoadingRequested += LoadScenes; |
|
|
|
if (_loadLocation != null) |
|
|
|
{ |
|
|
|
_loadLocation.OnLoadingRequested += LoadLocation; |
|
|
|
} |
|
|
|
if (_loadMenu != null) |
|
|
|
{ |
|
|
|
_loadMenu.OnLoadingRequested += LoadMenu; |
|
|
|
} |
|
|
|
_loadEventChannel.OnLoadingRequested -= LoadScenes; |
|
|
|
} |
|
|
|
|
|
|
|
private void Start() |
|
|
|
{ |
|
|
|
if (SceneManager.GetActiveScene().path == _initializationScene.scenePath) |
|
|
|
if (_loadLocation != null) |
|
|
|
{ |
|
|
|
_loadLocation.OnLoadingRequested -= LoadLocation; |
|
|
|
} |
|
|
|
if (_loadMenu != null) |
|
|
|
LoadMainMenu(); |
|
|
|
_loadMenu.OnLoadingRequested -= LoadMenu; |
|
|
|
private void LoadMainMenu() |
|
|
|
/// <summary>
|
|
|
|
/// This function loads the location scenes passed as array parameter
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="locationsToLoad"></param>
|
|
|
|
/// <param name="showLoadingScreen"></param>
|
|
|
|
private void LoadLocation(GameSceneSO[] locationsToLoad, bool showLoadingScreen) |
|
|
|
LoadScenes(_mainMenuScenes, false); |
|
|
|
//When loading a location, we want to keep the persistent managers and gameplay scenes loaded
|
|
|
|
_persistentScenes.Add(_persistentManagersScene); |
|
|
|
_persistentScenes.Add(_gameplayScene); |
|
|
|
AddScenesToUnload(_persistentScenes); |
|
|
|
LoadScenes(locationsToLoad, showLoadingScreen); |
|
|
|
/// This function loads the scenes passed as array parameter
|
|
|
|
/// This function loads the menu scenes passed as array parameter
|
|
|
|
/// <param name="locationsToLoad"></param>
|
|
|
|
/// <param name="MenuToLoad"></param>
|
|
|
|
private void LoadMenu(GameSceneSO[] MenuToLoad, bool showLoadingScreen) |
|
|
|
{ |
|
|
|
//When loading a menu, we only want to keep the persistent managers scene loaded
|
|
|
|
_persistentScenes.Add(_persistentManagersScene); |
|
|
|
AddScenesToUnload(_persistentScenes); |
|
|
|
LoadScenes(MenuToLoad, showLoadingScreen); |
|
|
|
} |
|
|
|
|
|
|
|
//Take the first scene in the array as the scene we want to set active
|
|
|
|
AddScenesToUnload(); |
|
|
|
Debug.Log("active scene = " + _activeScene.scenePath); |
|
|
|
_loadingInterface.SetActive(true); |
|
|
|
_ToggleLoadingScreen.RaiseEvent(true); |
|
|
|
} |
|
|
|
|
|
|
|
if (_scenesToLoadAsyncOperations.Count == 0) |
|
|
|
|
|
|
string currentScenePath = locationsToLoad[i].scenePath; |
|
|
|
if (IsSceneLoaded(currentScenePath) == false) |
|
|
|
{ |
|
|
|
if (runningLoader == null) |
|
|
|
{ |
|
|
|
_scenesToLoadAsyncOperations.Add(SceneManager.LoadSceneAsync(currentScenePath, LoadSceneMode.Additive)); |
|
|
|
_scenesToLoadAsyncOperations[i].completed += SetActiveScene; |
|
|
|
// TODO: Run a coroutine for each scene loading that updates a combined value
|
|
|
|
// for the progress bar. This way, as each scene completes loading, we will
|
|
|
|
// know what scene it is. Then decide if it activates right away or not.
|
|
|
|
// runningLoader = StartCoroutine(TrackLoadingProgress(locationsToLoad[i]));
|
|
|
|
} |
|
|
|
} |
|
|
|
_scenesToLoadAsyncOperations.Add(SceneManager.LoadSceneAsync(currentScenePath, LoadSceneMode.Additive)); |
|
|
|
} |
|
|
|
if (_scenesToLoadAsyncOperations.Count > 0) |
|
|
|
//Checks if any of the persistent scenes is not loaded yet and load it if unloaded
|
|
|
|
//This is especially useful when we go from main menu to first location
|
|
|
|
for (int i = 0; i < _persistentScenes.Count; ++i) |
|
|
|
{ |
|
|
|
if (IsSceneLoaded(_persistentScenes[i].scenePath) == false) |
|
|
|
// TODO: locationsToLoad[0] is a place holder right now.
|
|
|
|
runningLoader = StartCoroutine(TrackLoadingProgress(locationsToLoad[0])); |
|
|
|
_scenesToLoadAsyncOperations.Add(SceneManager.LoadSceneAsync(_persistentScenes[i].scenePath, LoadSceneMode.Additive)); |
|
|
|
StartCoroutine(WaitForLoading(showLoadingScreen)); |
|
|
|
} |
|
|
|
|
|
|
|
private IEnumerator WaitForLoading(bool showLoadingScreen) |
|
|
|
{ |
|
|
|
bool _loadingDone = false; |
|
|
|
// Wait until all scenes are loaded
|
|
|
|
while (!_loadingDone) |
|
|
|
{ |
|
|
|
for (int i = 0; i < _scenesToLoadAsyncOperations.Count; ++i) |
|
|
|
{ |
|
|
|
if (!_scenesToLoadAsyncOperations[i].isDone) |
|
|
|
{ |
|
|
|
break; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
_loadingDone = true; |
|
|
|
_scenesToLoadAsyncOperations.Clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
yield return null; |
|
|
|
} |
|
|
|
//Set the active scene
|
|
|
|
SetActiveScene(); |
|
|
|
if (showLoadingScreen) |
|
|
|
{ |
|
|
|
//Raise event to disable loading screen
|
|
|
|
_ToggleLoadingScreen.RaiseEvent(true); |
|
|
|
} |
|
|
|
|
|
|
|
/// SetActiveScene(AsyncOperation asyncOp) is called by AsyncOperation.complete event.
|
|
|
|
/// This function is called when all the scenes have been loaded
|
|
|
|
/// <param name="asyncOp"></param>
|
|
|
|
private void SetActiveScene(AsyncOperation asyncOp) |
|
|
|
private void SetActiveScene() |
|
|
|
// TODO: As each event completes, decide if it needs to activate right away.
|
|
|
|
|
|
|
|
//Raise the event to inform that the scene is loaded and set active
|
|
|
|
_OnSceneReady.RaiseEvent(); |
|
|
|
private void AddScenesToUnload() |
|
|
|
private void AddScenesToUnload(List<GameSceneSO> persistentScenes) |
|
|
|
for (int i = 0; i < SceneManager.sceneCount; i++) |
|
|
|
for (int i = 0; i < SceneManager.sceneCount; ++i) |
|
|
|
var scene = SceneManager.GetSceneAt(i); |
|
|
|
var scenePath = scene.path; |
|
|
|
if (scenePath != _initializationScene.scenePath && scenePath != _activeScene.scenePath) |
|
|
|
Scene scene = SceneManager.GetSceneAt(i); |
|
|
|
string scenePath = scene.path; |
|
|
|
for (int j = 0; j < persistentScenes.Count; ++j) |
|
|
|
Debug.Log("Added scene to unload = " + scenePath); |
|
|
|
_scenesToUnload.Add(scene); |
|
|
|
if (scenePath != persistentScenes[j].scenePath) |
|
|
|
{ |
|
|
|
//Check if we reached the last persistent scenes check
|
|
|
|
if (j == persistentScenes.Count-1) |
|
|
|
{ |
|
|
|
//If the scene is not one of the persistent scenes, we add it to the scenes to unload
|
|
|
|
_scenesToUnload.Add(scene); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
//We move the next scene check as soon as we find that the scene is one of the persistent scenes
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
if (_scenesToUnload != null) |
|
|
|
{ |
|
|
|
for (int i = 0; i < _scenesToUnload.Count; i++) |
|
|
|
for (int i = 0; i < _scenesToUnload.Count; ++i) |
|
|
|
{ |
|
|
|
SceneManager.UnloadSceneAsync(_scenesToUnload[i]); |
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// This function updates the loading progress once per frame until loading is complete
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="sceneReference">This is a place holder for the moment</param>
|
|
|
|
/// <returns>IEnumerator</returns>
|
|
|
|
private IEnumerator TrackLoadingProgress(GameSceneSO sceneReference) |
|
|
|
{ |
|
|
|
float totalProgress = 0; |
|
|
|
// When the scene reaches 0.9f, it means that it is loaded
|
|
|
|
// The remaining 0.1f are for the integration
|
|
|
|
while (totalProgress <= 0.9f) |
|
|
|
{ |
|
|
|
|
|
|
|
totalProgress = 0; |
|
|
|
for (int i = 0; i < _scenesToLoadAsyncOperations.Count; ++i) |
|
|
|
{ |
|
|
|
Debug.Log("Scene " + i + " :" + _scenesToLoadAsyncOperations[i].isDone + " progress = " + _scenesToLoadAsyncOperations[i].progress); |
|
|
|
totalProgress += _scenesToLoadAsyncOperations[i].progress; |
|
|
|
} |
|
|
|
|
|
|
|
//The fillAmount is for all scenes, so we divide the progress by the number of scenes to load
|
|
|
|
_loadingProgressBar.fillAmount = totalProgress / _scenesToLoadAsyncOperations.Count; |
|
|
|
Debug.Log("progress bar " + _loadingProgressBar.fillAmount + " and value = " + totalProgress / _scenesToLoadAsyncOperations.Count); |
|
|
|
|
|
|
|
yield return null; |
|
|
|
} |
|
|
|
|
|
|
|
_scenesToLoadAsyncOperations.Clear(); |
|
|
|
|
|
|
|
runningLoader = null; |
|
|
|
|
|
|
|
//Hide progress bar when loading is done
|
|
|
|
_loadingInterface.SetActive(false); |
|
|
|
} |
|
|
|
|
|
|
|
private void ExitGame() |
|
|
|