using Eflatun.SceneReference; using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; namespace MyCollections.SceneManagement { public class SceneLoader : MonoBehaviour { public SceneGroup[] sceneGroups; private static SceneLoader instance; [SerializeField] private GameObject loadingScreen; [SerializeField] private SceneReference loading; //Singleton public static SceneLoader Instance => instance; private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } private void Start() { } private SceneGroup FindSceneGroupByName(string name) => Array.Find(sceneGroups, group => group.groupName == name); public void LoadScenes(string groupName, LoadType type) { SceneGroup sceneGroup = FindSceneGroupByName(groupName); switch (type) { case LoadType.Loading: StartCoroutine(LoadWithLoadingScreenAsync(sceneGroup)); break; case LoadType.Trigger: LoadScenes(groupName); break; } } public void LoadSceneTrigger(SceneReference sceneReference) { int count = SceneManager.sceneCount; for (int i = 0; i < count; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.name == sceneReference.Name) return; } Debug.LogWarning("LoadingScene: " + sceneReference.Name); SceneManager.LoadSceneAsync(sceneReference.Name, LoadSceneMode.Additive); } public void UnloadSceneTrigger(SceneReference unloadScene, SceneReference newActiveScene) { int count = SceneManager.sceneCount; bool isSceneLoaded = false; for (int i = 0; i < count; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.name == unloadScene.Name) { isSceneLoaded = true; break; } } if (!isSceneLoaded) { Debug.LogWarning("Scene to unload not loaded: " + unloadScene.Name); return; } SceneManager.UnloadSceneAsync(unloadScene.Name); SetActiveScene(newActiveScene); } private void SetActiveScene(SceneReference sceneReference) { int count = SceneManager.sceneCount; for (int i = 0; i < count; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.name == sceneReference.Name) { SceneManager.SetActiveScene(scene); return; } } } public void LoadScenes(string groupName) { SceneGroup group = FindSceneGroupByName(groupName); Debug.Log($"Group Found: {group.groupName}"); if (group == null) return; List<string> scenesToLoad = new List<string>(); int count = SceneManager.sceneCount; Debug.Log($"Scene Count: {count}"); for (int i = 0; i < group.scenes.Count; i++) { bool isSceneLoaded = false; for (int j = 0; j < count; j++) { Scene loadedScene = SceneManager.GetSceneAt(j); if (loadedScene.name == group.scenes[i].Name) { isSceneLoaded = true; break; } } if (!isSceneLoaded) { Debug.Log($"Scene to Load Added: {group.scenes[i].Name}"); scenesToLoad.Add(group.scenes[i].Name); } } StartCoroutine(LoadAndSetActiveScene(scenesToLoad, group)); } private IEnumerator LoadWithLoadingScreenAsync(SceneGroup group) { List<string> scenesToLoad = new List<string>(); string sceneName = loading.Name; //Get the scene name //Load the Loading Scene AsyncOperation op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); //Wait until the Loading Scene is loaded yield return new WaitUntil(() => op.isDone); // Update scene count dynamically int s = SceneManager.sceneCount; //Get the loading screen GameObject loadingCanvas = GameObject.FindGameObjectWithTag("LoadingCanvas"); loadingScreen = loadingCanvas.transform.GetChild(0).gameObject; if (loadingScreen == null) { Debug.LogError("Loading Screen is Null"); yield break; } //Enables the login screen loadingScreen.SetActive(true); //Automatically will trigger the fadeout animation Animator animator; //Try to get the animator from the loading screen if (!loadingScreen.TryGetComponent(out animator)) { Debug.LogError("Animator is Null"); yield break; } AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); float duration = stateInfo.length; //Wait for the rest of the loading screen animation to finish yield return new WaitForSeconds(duration); //Get the all the scenes to Load for (int i = 0; i < group.scenes.Count; i++) { bool isSceneLoaded = false; // Update scene count dynamically int currentSceneCount = SceneManager.sceneCount; Debug.Log($"Current Scene Count: {currentSceneCount}"); for (int j = 0; j < currentSceneCount; j++) { //Get the Scene at index in the SceneManager's list of loaded Scenes Scene loadedScene = SceneManager.GetSceneAt(j); Debug.Log($"LoadedScene: {loadedScene.name}"); // Skip checking if it's the "Loading" scene, which should only be loaded once if (loadedScene.name == sceneName) { continue; // Skip the loading scene } //Compare the names of the SceneManager's list with the group of scenes if (loadedScene.name == group.scenes[i].Name) { //if the scene is loaded flags to true Debug.Log($"The Scene is Loaded: {loadedScene.name}"); isSceneLoaded = true; break; } } //Adds the scenes to load list if (!isSceneLoaded) { Debug.Log($"Scene to Load Added: {group.scenes[i].Name}"); scenesToLoad.Add(group.scenes[i].Name); } } //Unload scenes UnloadScene(group); //load the all the scenes for (int i = 0; i < scenesToLoad.Count; i++) { AsyncOperation loadSceneOp = SceneManager.LoadSceneAsync(scenesToLoad[i], LoadSceneMode.Additive); //Wait until the operation is done yield return new WaitUntil(() => loadSceneOp.isDone); //Set active the scene SceneManager.SetActiveScene(SceneManager.GetSceneByName(scenesToLoad[i])); } //We invoke the fadeout animation of the loading screen animator.SetTrigger("FadeOut"); //Get the current state info stateInfo = animator.GetCurrentAnimatorStateInfo(0); duration = stateInfo.length; //get the state lenght //Wait for the animation to finish yield return new WaitForSeconds(duration); //After the animation is finished //we unload the Loading screen AsyncOperation unloadOp = SceneManager.UnloadSceneAsync(sceneName); yield return new WaitUntil(() => unloadOp.isDone); } private IEnumerator LoadAndSetActiveScene(List<string> scenesToLoad, SceneGroup group) { for (int i = 0; i < scenesToLoad.Count; i++) { AsyncOperation op = SceneManager.LoadSceneAsync(scenesToLoad[i], LoadSceneMode.Additive); Debug.Log($"Loading Scene: {scenesToLoad[i]}"); // Wait for the scene to fully load yield return new WaitUntil(() => op.isDone); // After the scene has loaded, set it as active SceneManager.SetActiveScene(SceneManager.GetSceneByName(scenesToLoad[i])); Debug.Log($"Scene {scenesToLoad[i]} set as active."); } // Once all scenes are loaded, unload the required scenes UnloadScene(group); } private void UnloadScene(SceneGroup group) { List<Scene> scenesToUnload = group.FindSceneRefByType(SceneType.DisableScene); Debug.Log($"Scenes Found To Unload: {scenesToUnload.Count}"); List<string> unloadScenes = new List<string>(); if (scenesToUnload.Count == 0) return; for (int i = 0; i < scenesToUnload.Count; i++) { Scene sceneToUnload = scenesToUnload[i]; if (sceneToUnload.isLoaded) { Debug.Log($"Scene to Unload: {sceneToUnload.name}"); unloadScenes.Add(sceneToUnload.name); } } if (unloadScenes.Count > 0) { for (int i = 0; i < unloadScenes.Count; i++) { SceneManager.UnloadSceneAsync(unloadScenes[i]); Debug.Log($"Unloading Scene: {unloadScenes[i]}"); } } } } [Serializable] public struct SceneDataSaver { //Position where the player should be after changing scene public Vector3 position; public string groupName; } //The trigger loadtype doesn't affect the player gameplay //The Loading loadtype triggers a loading screen public enum LoadType { Trigger, Loading } public enum SceneAction { LoadScene, UnloadScene } }