Files
DeviantMobile-Rohan/Assets/Scripts/Announcement/LoadingScreen.cs

549 lines
20 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.Analytics;
using CustomAssetBundleSystem;
/*
DESCRIPTION:
1. When the Loading_Screen gameobject with this script is enabled, the loading slider animates to show progress when changing
between UI's or scenes
*/
public class LoadingScreen : MonoBehaviour
{
public GameObject BackgroundImg_GameObject; //Reference to the background image in the loading UI
public GameObject Hints_GameObject; //Reference to Hints text in the loading UI
public Slider loadingSlider; //Reference to the slider in the loading UI
//For the "Loading..." text shown
public TextMeshProUGUI loadingText;
public string loadingBaseText; //Text showing "Loading..." whereas the dots appear to animate
public string og_text;
public string ui_to_show;
public int to_change_to; //1. Scene, 2. UI
public Sprite[] backgroundImages; // Array of background images
public string[] hintsArray; //Array of hints to be displayed while loading
private int maxBackgroundChanges = 1, backgroundChangeCount = 0; // Maximum number of background changes
private int maxhintsChanges = 1, hintsChangeCount = 0; // Counter to keep track of background changes
private int maxLoaderChanges = 3, loaderChangeCount = 0; // Counter to keep track of background changes
bool flag = true; //flag to check if loading has been initialized
private GameManager gameManager;
private float barProgess;
private bool pendingInitialization;
private string targetSceneName; // remember scene we are loading so we can react on load
private bool sceneHideHookRegistered;
private bool fallbackHideHookRegistered; // subscribed when we didn't initialize via to_change_to==1
// Scenes on which we should auto-hide the loading UI even if we didn't initiate the load via this component.
// Keeps prior behavior intact while fixing cases like WaitingSceneManager.
[SerializeField]
private string[] autoHideOnSceneNames = new[] { "Game" };
// AssetBundle Download Integration
[Header("AssetBundle Download Settings")]
[SerializeField] private bool enableAssetBundleDownload = false; // DISABLED: Using Build Settings scenes instead
[SerializeField] private bool downloadBeforeMenu = false; // DISABLED: Using Build Settings scenes instead
private AssetBundleDownloadManager downloadManager;
// Force disable AssetBundle system at runtime (overrides serialized Inspector values)
private void Awake()
{
// IMPORTANT: Force disable AssetBundle downloading until you want to re-enable it
enableAssetBundleDownload = false;
downloadBeforeMenu = false;
}
private void OnEnable()
{
gameManager = GameManager.Instance;
if (gameManager == null)
{
gameManager = GetComponent<GameManager>() ?? GetComponentInParent<GameManager>();
}
if (gameManager == null)
{
#if UNITY_2022_2_OR_NEWER
gameManager = FindFirstObjectByType<GameManager>();
#else
gameManager = FindObjectOfType<GameManager>();
#endif
}
// Initialize AssetBundle download manager
if (enableAssetBundleDownload && downloadManager == null)
{
downloadManager = gameObject.AddComponent<AssetBundleDownloadManager>();
// Pass UI references to download manager
var downloadManagerType = downloadManager.GetType();
var sliderField = downloadManagerType.GetField("loadingSlider", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var loadingTextField = downloadManagerType.GetField("loadingText", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var hintsTextField = downloadManagerType.GetField("hintsText", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (sliderField != null) sliderField.SetValue(downloadManager, loadingSlider);
if (loadingTextField != null) loadingTextField.SetValue(downloadManager, loadingText);
if (hintsTextField != null) hintsTextField.SetValue(downloadManager, Hints_GameObject.GetComponent<TextMeshProUGUI>());
}
// Hints to be shown
hintsArray = new string[]
{
"Complete Weekly Missions to gain XP",
"Complete a 20 Wins streak to level up in Rank",
"Missions change every Week"
};
og_text = loadingText.text; // "Loading..." text
loadingBaseText = loadingText.text;
if (pendingInitialization)
{
InitializeLoading();
}
// Always attach a lightweight fallback so if another system loads the scene (e.g., WaitingSceneManager),
// we still hide the loading UI when the gameplay scene is ready.
if (!fallbackHideHookRegistered)
{
SceneManager.sceneLoaded += FallbackSceneLoadedHide;
fallbackHideHookRegistered = true;
}
}
private void OnDisable()
{
StopAllCoroutines();
// Ensure we unsubscribe any scene hooks to avoid leaks.
if (sceneHideHookRegistered)
{
SceneManager.sceneLoaded -= HandleSceneLoadedInternal;
sceneHideHookRegistered = false;
}
if (fallbackHideHookRegistered)
{
SceneManager.sceneLoaded -= FallbackSceneLoadedHide;
fallbackHideHookRegistered = false;
}
}
// Function called when loading has been initialized
public void InitializeLoading()
{
pendingInitialization = false;
StopAllCoroutines();
backgroundChangeCount = 0;
hintsChangeCount = 0;
loaderChangeCount = 0;
flag = true;
if (loadingSlider != null)
{
loadingSlider.value = 0f;
}
if (!string.IsNullOrEmpty(og_text) && loadingText != null)
{
loadingBaseText = og_text;
loadingText.text = og_text;
}
ChangeBackgroundImage();
ChangeHintsText();
StartCoroutine(ChangeBackgroundWithDelay());
StartCoroutine(ChangeHintsWithDelay());
// Check if we should download AssetBundles BEFORE loading menu
if (enableAssetBundleDownload && downloadBeforeMenu && ui_to_show == "MenuScene" && to_change_to == 1)
{
Debug.Log("[LoadingScreen] Starting AssetBundle download before MenuScene...");
StartCoroutine(DownloadThenLoadScene(ui_to_show));
return; // Don't proceed with normal loading yet
}
if (to_change_to == 1)
{
if (GameManager.Instance != null)
{
SceneManager.sceneLoaded += GameManager.Instance.OnSceneLoaded;
}
targetSceneName = ui_to_show;
// Also register a local handler to guarantee the loading UI hides even if external code path changes.
if (!sceneHideHookRegistered)
{
SceneManager.sceneLoaded += HandleSceneLoadedInternal;
sceneHideHookRegistered = true;
}
StartCoroutine(LoadSceneAsync(ui_to_show));
}
else
{
StartCoroutine(AnimateSliderFill(5f));//duration should be 3 for editor simulation, 5 for mobile apk lower than that the corouting gets jammed
}
}
/// <summary>
/// Download AssetBundles first, then load the target scene
/// </summary>
private IEnumerator DownloadThenLoadScene(string sceneName)
{
if (downloadManager == null)
{
Debug.LogError("[LoadingScreen] DownloadManager not initialized!");
// Fallback to normal loading
StartCoroutine(LoadSceneAsync(sceneName));
yield break;
}
Debug.Log("[LoadingScreen] Starting AssetBundle download process...");
bool downloadSuccess = false;
// Start download with callback
yield return downloadManager.StartDownloadProcess((success) =>
{
downloadSuccess = success;
});
if (downloadSuccess)
{
Debug.Log("[LoadingScreen] ✓ AssetBundle download complete! Loading scene...");
// Now proceed with scene loading
if (GameManager.Instance != null)
{
SceneManager.sceneLoaded += GameManager.Instance.OnSceneLoaded;
}
targetSceneName = sceneName;
if (!sceneHideHookRegistered)
{
SceneManager.sceneLoaded += HandleSceneLoadedInternal;
sceneHideHookRegistered = true;
}
yield return LoadSceneAsync(sceneName);
}
else
{
Debug.LogError("[LoadingScreen] ✗ AssetBundle download failed! Cannot proceed.");
// Show error message - user must retry or have internet
if (loadingText != null)
{
loadingText.text = "Download Failed - Check Internet Connection";
}
if (Hints_GameObject != null)
{
Hints_GameObject.GetComponent<TextMeshProUGUI>().text = "Please connect to the internet and restart the game";
}
// Don't proceed to menu - block here
}
}
// Function to animate the loading slider being filled from empty to full
private IEnumerator AnimateSliderFill(float duration)
{
loadingBaseText = "LOADING";
int dotsCount = 3;
float timer = 0f;
float startValue = loadingSlider.value;
float targetValue = 1f; // Assuming the slider's range is 0 to 1
float fakeProgress = 0;
loadingSlider.value = 0.01f;
while (timer < duration)
{
if (fakeProgress >= 0.25f && fakeProgress < 0.26f)
{
yield return new WaitForSeconds(0.15f); // Set a delay of 0.5 seconds
}
if (fakeProgress >= 0.75f && fakeProgress < 0.76f)
{
yield return new WaitForSeconds(0.25f); // Set a delay of 0.5 seconds
}
fakeProgress = Mathf.Lerp(startValue, targetValue, timer / duration);
if (loadingSlider != null)
{
loadingSlider.value = fakeProgress;
}
//Create ... animation effect on the Loading... text
int dotsToShow = Mathf.FloorToInt(timer % (dotsCount + 1));
string dots = new string('.', dotsToShow);
loadingText.text = loadingBaseText + dots;
timer += Time.deltaTime;
if ((loaderChangeCount < maxLoaderChanges) && (fakeProgress >= 0.01f && fakeProgress < 0.4f ||
fakeProgress >= 0.5f && fakeProgress < 0.65f ||
fakeProgress >= 0.8f && fakeProgress < 0.9f))
{
float randomLoaderDelay = Mathf.Round(Random.Range(0.01f, 0.09f) * 100) / 100; // Random value between 1 and 2 with 2 decimal places
//Debug.Log("randomdelay " + randomLoaderDelay);
yield return new WaitForSeconds(randomLoaderDelay);
loaderChangeCount++;
}
yield return null;
}
//loadingSlider.value = targetValue;
loadingText.text = "LOADING."; // Reset text to the original after completion
yield return new WaitForSeconds(0.5f);
if (to_change_to == 2) // UI
{
GameObject uiObject = GameObject.Find("UI");
GameObject UI_to_be_shown = uiObject.transform.Find(ui_to_show).gameObject;
UI_to_be_shown.SetActive(true);
}
}
// Function to load scene, and update slider value based on the loading progress
private IEnumerator LoadSceneAsync(string sceneName)
{
// Start a guarded async scene load (Single mode) and prevent duplicates
SceneLoader.SceneLoadHandle asyncLoad = SceneLoader.LoadSceneAsyncOnce(sceneName, LoadSceneMode.Single, allowSceneActivation: false);
// If a different scene is already loading, try to reuse the current operation if available
if (asyncLoad == null)
{
asyncLoad = SceneLoader.CurrentOperation;
if (asyncLoad == null)
yield break; // Nothing to wait on
}
if (gameManager != null)
{
gameManager.ShowLoadingUI();
}
yield return new WaitForSeconds(2f);
float timer = 0f;
float previousValue = 0;
while (!asyncLoad.isDone)
{
if (loadingSlider.value >= 0.25f && loadingSlider.value < 0.26f)
{
yield return new WaitForSeconds(0.15f); // Set a delay of 0.5 seconds
}
if (loadingSlider.value >= 0.75f && loadingSlider.value < 0.76f)
{
yield return new WaitForSeconds(0.25f); // Set a delay of 0.5 seconds
}
if (previousValue < Mathf.Lerp(0, asyncLoad.progress, timer / 4f))
{
previousValue = Mathf.Lerp(0, asyncLoad.progress, timer / 4f);
loadingSlider.value = Mathf.Lerp(0, asyncLoad.progress, timer / 4f);
}
else
loadingSlider.value = previousValue;
int dotsToShow = Mathf.FloorToInt(timer % (3 + 1));
string dots = new string('.', dotsToShow);
loadingText.text = loadingBaseText + dots;
timer += Time.deltaTime;
if ((loaderChangeCount < maxLoaderChanges) && (loadingSlider.value >= 0.01f && loadingSlider.value < 0.4f ||
loadingSlider.value >= 0.5f && loadingSlider.value < 0.65f ||
loadingSlider.value >= 0.8f && loadingSlider.value < 0.9f))
{
float randomLoaderDelay = Mathf.Round(Random.Range(0.01f, 0.09f) * 100) / 100; // Random value between 1 and 2 with 2 decimal places
yield return new WaitForSeconds(randomLoaderDelay);
loaderChangeCount++;
}
if (loadingSlider.value >= 0.9f)
{
loadingText.text = "LOADING...";
loadingSlider.value = 1.0f;
float randomLoaderDelay = Mathf.Round(Random.Range(0.01f, 0.09f) * 100) / 100; // Random value between 1 and 2 with 2 decimal places
yield return new WaitForSeconds(randomLoaderDelay);
loaderChangeCount++;
// Activate the scene once ready
asyncLoad.allowSceneActivation = true;
Debug.Log("[LoadingScreen] Scene activation triggered, waiting for isDone...");
}
yield return null;
}
Debug.Log("[LoadingScreen] Scene load complete (asyncLoad.isDone=true), hiding loading UI...");
// Use GameManager.Instance singleton instead of cached reference (which may be stale after scene change)
if (GameManager.Instance != null)
{
GameManager.Instance.HideLoadingUI();
}
else if (gameManager != null)
{
gameManager.HideLoadingUI();
}
else
{
Debug.LogWarning("[LoadingScreen] No GameManager available to hide loading UI!");
// Fallback: try to disable our own root
if (transform.root != null)
{
transform.root.gameObject.SetActive(false);
}
}
}
// Internal safety: ensure we always hide loading when the intended scene finishes loading.
private void HandleSceneLoadedInternal(Scene scene, LoadSceneMode mode)
{
if (!string.IsNullOrEmpty(targetSceneName) && scene.name == targetSceneName)
{
// Stop anim coroutines.
StopAllCoroutines();
// Hide through GameManager if available.
if (GameManager.Instance != null)
{
GameManager.Instance.HideLoadingUI();
}
else if (gameObject.activeInHierarchy)
{
// Fallback: disable our root canvas (assumes parent = loadingUI)
transform.root.gameObject.SetActive(false);
}
// cleanup subscription
SceneManager.sceneLoaded -= HandleSceneLoadedInternal;
sceneHideHookRegistered = false;
targetSceneName = null;
}
}
// Fallback hide when we didn't initiate the load, or targetSceneName wasn't set.
private void FallbackSceneLoadedHide(Scene scene, LoadSceneMode mode)
{
// If InitializeLoading set a specific target, let HandleSceneLoadedInternal manage it.
if (!string.IsNullOrEmpty(targetSceneName))
return;
if (autoHideOnSceneNames != null)
{
for (int i = 0; i < autoHideOnSceneNames.Length; i++)
{
var name = autoHideOnSceneNames[i];
if (!string.IsNullOrEmpty(name) && scene.name == name)
{
// Stop any visuals if they were running.
StopAllCoroutines();
if (GameManager.Instance != null)
{
GameManager.Instance.HideLoadingUI();
}
else if (gameObject.activeInHierarchy)
{
transform.root.gameObject.SetActive(false);
}
// Once done, remove fallback hook
SceneManager.sceneLoaded -= FallbackSceneLoadedHide;
fallbackHideHookRegistered = false;
break;
}
}
}
}
// Function to change the background image of the loading UI
private IEnumerator ChangeBackgroundWithDelay()
{
while (true)
{
if (backgroundChangeCount < maxBackgroundChanges)
{
float randomDelay = Mathf.Round(Random.Range(1f, 2f) * 100) / 100; // Random value between 1 and 2 with 2 decimal places
yield return new WaitForSeconds(randomDelay); // Adjust the time to wait as needed (2 seconds in this case)
ChangeBackgroundImage();
backgroundChangeCount++;
}
else
{
yield break; // Exit coroutine when maximum number of background changes is reached
}
yield return null;
}
}
// Function to change the hints being displayed in the loading UI while the player waits the loading to be completed
private IEnumerator ChangeHintsWithDelay()
{
while (true)
{
if (hintsChangeCount < maxhintsChanges)
{
float randomDelay = Mathf.Round(Random.Range(0.75f, 2.25f) * 100) / 100; // Random value between 1 and 2 with 2 decimal places
yield return new WaitForSeconds(randomDelay); // Adjust the time to wait as needed (2 seconds in this case)
ChangeHintsText();
hintsChangeCount++;
}
else
{
yield break; // Exit coroutine when maximum number of background changes is reached
}
yield return null;
}
}
// Function to change the hints text being displayed
private void ChangeHintsText()
{
// Remove stray literal text assignment; pick a random hint safely.
if (hintsArray.Length > 0)
{
int randomIndex = Random.Range(0, hintsArray.Length);
Hints_GameObject.GetComponent<TextMeshProUGUI>().text = hintsArray[randomIndex];
}
}
// Function to change the background image in the loading UI
private void ChangeBackgroundImage()
{
if (backgroundImages.Length > 0)
{
int randomIndex = Random.Range(0, backgroundImages.Length);
BackgroundImg_GameObject.GetComponent<Image>().sprite = backgroundImages[randomIndex];
}
}
// Function that is referenced/called in other script which specifies what Scene or UI to change to after the loading plays out
public void UI_to_show_AfterLoading(int x, string ui_name)
{
to_change_to = x;
ui_to_show = ui_name;
backgroundChangeCount = 0;
hintsChangeCount = 0;
loaderChangeCount = 0;
flag = true;
pendingInitialization = true;
if (isActiveAndEnabled)
{
InitializeLoading();
}
}
}