diff --git a/Assets/Prefabs/Managers/SceneManager.prefab b/Assets/Prefabs/Managers/SceneManager.prefab
index ea036003..7c1883c3 100644
--- a/Assets/Prefabs/Managers/SceneManager.prefab
+++ b/Assets/Prefabs/Managers/SceneManager.prefab
@@ -29,7 +29,8 @@ Transform:
m_LocalPosition: {x: -3.4031, y: -1.84829, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
- m_Children: []
+ m_Children:
+ - {fileID: 4689617562113187593}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5327225408302228741
@@ -44,3 +45,105 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 360f320f4d7a48e38f5fd7cdfa28144a, type: 3}
m_Name:
m_EditorClassIdentifier:
+--- !u!1001 &4881964705042195055
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 3506046067200272545}
+ m_Modifications:
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4869161796575291839, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Name
+ value: LoadingScreen
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+--- !u!224 &4689617562113187593 stripped
+RectTransform:
+ m_CorrespondingSourceObject: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ m_PrefabInstance: {fileID: 4881964705042195055}
+ m_PrefabAsset: {fileID: 0}
diff --git a/Assets/Scenes/StartingScene.unity b/Assets/Scenes/StartingScene.unity
index bae07f91..da88ad34 100644
--- a/Assets/Scenes/StartingScene.unity
+++ b/Assets/Scenes/StartingScene.unity
@@ -119,6 +119,144 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
+--- !u!1001 &180679694
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Pivot.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Pivot.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMax.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMax.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMin.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchorMin.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_SizeDelta.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_SizeDelta.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchoredPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_AnchoredPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 4869161796575291839, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ propertyPath: m_Name
+ value: LoadingScreen
+ objectReference: {fileID: 0}
+ m_RemovedComponents:
+ - {fileID: 5737877680156686392, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents:
+ - targetCorrespondingSourceObject: {fileID: 4869161796575291839, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ insertIndex: -1
+ addedObject: {fileID: 180679698}
+ m_SourcePrefab: {fileID: 100100000, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+--- !u!1 &180679695 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 4869161796575291839, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ m_PrefabInstance: {fileID: 180679694}
+ m_PrefabAsset: {fileID: 0}
+--- !u!114 &180679696 stripped
+MonoBehaviour:
+ m_CorrespondingSourceObject: {fileID: 1674678211233966532, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ m_PrefabInstance: {fileID: 180679694}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
+--- !u!1 &180679697 stripped
+GameObject:
+ m_CorrespondingSourceObject: {fileID: 7270617579256400696, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
+ m_PrefabInstance: {fileID: 180679694}
+ m_PrefabAsset: {fileID: 0}
+--- !u!114 &180679698
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 180679695}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 8968b564891a474baae157792b88e75f, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: AppleHillsScripts::Bootstrap.InitialLoadingScreen
+ loadingScreenContainer: {fileID: 180679697}
+ progressBarImage: {fileID: 180679696}
+ minimumDisplayTime: 2
+ progressUpdateInterval: 0.1
--- !u!1 &400217123
GameObject:
m_ObjectHideFlags: 0
@@ -256,103 +394,6 @@ MonoBehaviour:
m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0
m_Version: 2
---- !u!1001 &1355357999
-PrefabInstance:
- m_ObjectHideFlags: 0
- serializedVersion: 2
- m_Modification:
- serializedVersion: 3
- m_TransformParent: {fileID: 0}
- m_Modifications:
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_Pivot.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_Pivot.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchorMax.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchorMax.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchorMin.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchorMin.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_SizeDelta.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_SizeDelta.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalPosition.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalPosition.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalPosition.z
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalRotation.w
- value: 1
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalRotation.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalRotation.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalRotation.z
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchoredPosition.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_AnchoredPosition.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalEulerAnglesHint.x
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalEulerAnglesHint.y
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 204042265062571366, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_LocalEulerAnglesHint.z
- value: 0
- objectReference: {fileID: 0}
- - target: {fileID: 4869161796575291839, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
- propertyPath: m_Name
- value: LoadingScreen
- objectReference: {fileID: 0}
- m_RemovedComponents: []
- m_RemovedGameObjects: []
- m_AddedGameObjects: []
- m_AddedComponents: []
- m_SourcePrefab: {fileID: 100100000, guid: 19fad826fce26d34ba304620216a7f47, type: 3}
--- !u!1 &1710655392
GameObject:
m_ObjectHideFlags: 0
@@ -385,6 +426,8 @@ MonoBehaviour:
mainMenuSceneName: MainMenu
minDelayAfterBoot: 0.5
debugMode: 0
+ initialLoadingScreen: {fileID: 180679698}
+ bootProgressWeight: 0.5
--- !u!4 &1710655394
Transform:
m_ObjectHideFlags: 0
@@ -405,5 +448,5 @@ SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 400217126}
- - {fileID: 1355357999}
- {fileID: 1710655394}
+ - {fileID: 180679694}
diff --git a/Assets/Scripts/Bootstrap/BootSceneController.cs b/Assets/Scripts/Bootstrap/BootSceneController.cs
index 239d8b0c..d2877526 100644
--- a/Assets/Scripts/Bootstrap/BootSceneController.cs
+++ b/Assets/Scripts/Bootstrap/BootSceneController.cs
@@ -3,6 +3,7 @@ using UnityEngine;
using UI;
using Core;
using UnityEngine.SceneManagement;
+using Cinematics;
namespace Bootstrap
{
@@ -14,6 +15,7 @@ namespace Bootstrap
[SerializeField] private string mainMenuSceneName = "MainMenu";
[SerializeField] private float minDelayAfterBoot = 0.5f; // Small delay after boot to ensure smooth transition
[SerializeField] private bool debugMode = false;
+ [SerializeField] private InitialLoadingScreen initialLoadingScreen; // Reference to our specialized loading screen
// Progress distribution between bootstrap and scene loading
[SerializeField, Range(0.1f, 0.9f)] private float bootProgressWeight = 0.5f; // Default 50/50 split
@@ -29,20 +31,18 @@ namespace Bootstrap
{
Debug.Log("[BootSceneController] Boot scene started");
- // Ensure the loading screen controller exists
- if (LoadingScreenController.Instance == null)
+ // Ensure the initial loading screen exists
+ if (initialLoadingScreen == null)
{
- Debug.LogError("[BootSceneController] No LoadingScreenController found in the scene!");
+ Debug.LogError("[BootSceneController] No InitialLoadingScreen assigned! Please assign it in the inspector.");
return;
}
+ // Subscribe to the loading screen completion event
+ initialLoadingScreen.OnLoadingScreenFullyHidden += OnInitialLoadingComplete;
+
// Show the loading screen immediately with our combined progress provider
- LoadingScreenController.Instance.ShowLoadingScreen(
- progressProvider: GetCombinedProgress,
- onComplete: () => {
- Debug.Log("[BootSceneController] Loading screen fully hidden, boot sequence completed");
- }
- );
+ initialLoadingScreen.ShowLoadingScreen(GetCombinedProgress);
// Start the boot process if not already initialized
if (!CustomBoot.Initialised)
@@ -68,12 +68,43 @@ namespace Bootstrap
}
}
+ ///
+ /// Called when the initial loading screen is fully hidden
+ ///
+ private void OnInitialLoadingComplete()
+ {
+ Debug.Log("[BootSceneController] Initial loading screen fully hidden, boot sequence completed");
+
+ // Play the intro cinematic if available
+ if (CinematicsManager.Instance != null)
+ {
+ Debug.Log("[BootSceneController] Attempting to play intro cinematic");
+
+ // Use LoadAndPlayCinematic to play the intro sequence
+ CinematicsManager.Instance.LoadAndPlayCinematic("IntroSequence");
+
+ // Immediately unload the StartingScene - no need to wait for cinematic to finish
+ // since CinematicsManager is bootstrapped and won't be unloaded
+ UnloadStartingScene();
+ }
+ else
+ {
+ // If no cinematics manager, unload the StartingScene directly
+ UnloadStartingScene();
+ }
+ }
+
private void OnDestroy()
{
// Clean up event subscriptions
CustomBoot.OnBootCompleted -= OnBootCompleted;
CustomBoot.OnBootProgressChanged -= OnBootProgressChanged;
+ if (initialLoadingScreen != null)
+ {
+ initialLoadingScreen.OnLoadingScreenFullyHidden -= OnInitialLoadingComplete;
+ }
+
if (debugMode)
{
CancelInvoke(nameof(LogDebugInfo));
@@ -146,31 +177,97 @@ namespace Bootstrap
// Initialize scene loading progress to 0 to ensure proper remapping
_sceneLoadingProgress = 0f;
- // Create a progress object that remaps scene loading progress (0-1) to our second phase range
- var progress = new Progress(p => {
+ // Create a custom progress reporter using a custom class
+ var progressHandler = new ProgressHandler(value => {
// Store the raw scene loading progress (0-1)
- _sceneLoadingProgress = p;
+ _sceneLoadingProgress = value;
if (debugMode)
{
- Debug.Log($"[BootSceneController] Scene loading raw: {p:P0}, Combined: {GetCombinedProgress():P0}");
+ Debug.Log($"[BootSceneController] Scene loading raw: {value:P0}, Combined: {GetCombinedProgress():P0}");
}
});
- // Load the scene but don't auto-hide loading screen (we're managing that ourselves)
- await SceneManagerService.Instance.SwitchSceneAsync(mainMenuSceneName, progress, autoHideLoadingScreen: false);
+ // Step 1: Additively load the main menu scene - don't unload StartingScene yet
+ var op = SceneManager.LoadSceneAsync(mainMenuSceneName, LoadSceneMode.Additive);
+
+ // Disable scene activation until we're ready to show it
+ op.allowSceneActivation = true;
+
+ // Track progress while loading
+ while (!op.isDone)
+ {
+ progressHandler.ReportProgress(op.progress);
+ await System.Threading.Tasks.Task.Yield();
+ }
+
+ // Update the current gameplay scene in SceneManagerService
+ SceneManagerService.Instance.CurrentGameplayScene = mainMenuSceneName;
// Ensure progress is complete
_sceneLoadingProgress = 1f;
- // Scene is fully loaded, we can now hide the loading screen
- LoadingScreenController.Instance.HideLoadingScreen();
+ // Step 2: Scene is fully loaded, now hide the loading screen
+ // This will trigger OnInitialLoadingComplete via the event when animation completes
+ initialLoadingScreen.HideLoadingScreen();
+
+ // Step 3: The OnInitialLoadingComplete method will handle playing the intro cinematic
+ // Step 4: StartingScene will be unloaded after the cinematic completes in OnIntroCinematicFinished
}
catch (Exception e)
{
Debug.LogError($"[BootSceneController] Error loading main menu: {e.Message}");
// Still try to hide the loading screen even if there was an error
- LoadingScreenController.Instance.HideLoadingScreen();
+ initialLoadingScreen.HideLoadingScreen();
+ }
+ }
+
+ ///
+ /// Unloads the StartingScene, completing the transition to the main menu
+ ///
+ private async void UnloadStartingScene()
+ {
+ try
+ {
+ // Get the current scene (StartingScene)
+ Scene currentScene = SceneManager.GetActiveScene();
+ string startingSceneName = currentScene.name;
+
+ Debug.Log($"[BootSceneController] Unloading StartingScene: {startingSceneName}");
+
+ // Unload the StartingScene
+ await SceneManager.UnloadSceneAsync(startingSceneName);
+
+ // Set the main menu scene as the active scene
+ Scene mainMenuScene = SceneManager.GetSceneByName(mainMenuSceneName);
+ SceneManager.SetActiveScene(mainMenuScene);
+
+ Debug.Log($"[BootSceneController] Transition complete: {startingSceneName} unloaded, {mainMenuSceneName} is now active");
+
+ // Destroy the boot scene controller since its job is done
+ Destroy(gameObject);
+ }
+ catch (Exception e)
+ {
+ Logging.Warning($"[BootSceneController] Error unloading StartingScene: {e.Message}");
+ }
+ }
+
+ ///
+ /// Helper class to handle progress reporting without running into explicit interface implementation issues
+ ///
+ private class ProgressHandler
+ {
+ private Action _progressAction;
+
+ public ProgressHandler(Action progressAction)
+ {
+ _progressAction = progressAction;
+ }
+
+ public void ReportProgress(float value)
+ {
+ _progressAction?.Invoke(value);
}
}
}
diff --git a/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs b/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs
new file mode 100644
index 00000000..bebe4d9b
--- /dev/null
+++ b/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs
@@ -0,0 +1,240 @@
+using System;
+using System.Collections;
+using UnityEngine;
+using UnityEngine.UI;
+using Core;
+
+namespace Bootstrap
+{
+ ///
+ /// Specialized loading screen controller specifically for the initial boot sequence.
+ /// This handles the combined progress of bootstrap initialization and main menu loading.
+ ///
+ public class InitialLoadingScreen : MonoBehaviour
+ {
+ [Header("UI References")]
+ [SerializeField] private GameObject loadingScreenContainer;
+ [SerializeField] private Image progressBarImage;
+
+ [Header("Settings")]
+ [SerializeField] private float minimumDisplayTime = 1.0f;
+ [SerializeField] private float progressUpdateInterval = 0.1f;
+
+ private float _displayStartTime;
+ private Coroutine _progressCoroutine;
+ private bool _loadingComplete = false;
+ private bool _animationComplete = false;
+ private Action _onLoadingScreenFullyHidden;
+
+ ///
+ /// Event that fires when the loading screen is fully hidden (both loading and animation completed)
+ ///
+ public event Action OnLoadingScreenFullyHidden;
+
+ ///
+ /// Delegate for providing progress values from different sources
+ ///
+ public delegate float ProgressProvider();
+
+ ///
+ /// Current progress provider being used for the loading screen
+ ///
+ private ProgressProvider _currentProgressProvider;
+
+ ///
+ /// Default progress provider that returns 0 (or 1 if loading is complete)
+ ///
+ private float DefaultProgressProvider() => _loadingComplete ? 1f : 0f;
+
+ ///
+ /// Check if the loading screen is currently active
+ ///
+ public bool IsActive => loadingScreenContainer != null && loadingScreenContainer.activeSelf;
+
+ private void Awake()
+ {
+ if (loadingScreenContainer == null)
+ loadingScreenContainer = gameObject;
+
+ // Ensure the loading screen is initially hidden
+ if (loadingScreenContainer != null)
+ {
+ loadingScreenContainer.SetActive(false);
+ }
+ }
+
+ ///
+ /// Shows the loading screen and resets the progress bar to zero
+ ///
+ /// Optional delegate to provide progress values (0-1). If null, uses default provider.
+ /// Optional callback when loading screen is fully hidden
+ public void ShowLoadingScreen(ProgressProvider progressProvider = null, Action onComplete = null)
+ {
+ // Store the completion callback
+ _onLoadingScreenFullyHidden = onComplete;
+
+ // Set the progress provider, use default if none provided
+ _currentProgressProvider = progressProvider ?? DefaultProgressProvider;
+
+ // Stop any existing progress coroutine
+ if (_progressCoroutine != null)
+ {
+ StopCoroutine(_progressCoroutine);
+ _progressCoroutine = null;
+ }
+
+ _displayStartTime = Time.time;
+ _loadingComplete = false;
+ _animationComplete = false;
+
+ if (progressBarImage != null)
+ {
+ progressBarImage.fillAmount = 0f;
+ }
+
+ if (loadingScreenContainer != null)
+ {
+ loadingScreenContainer.SetActive(true);
+ }
+
+ // Start the progress filling coroutine
+ _progressCoroutine = StartCoroutine(AnimateProgressBar());
+ }
+
+ ///
+ /// Animates the progress bar at a steady pace over the minimum display time,
+ /// while also checking actual loading progress from the current progress provider
+ ///
+ private IEnumerator AnimateProgressBar()
+ {
+ float startTime = Time.time;
+
+ // Continue until both animation and loading are complete
+ while (!_animationComplete)
+ {
+ // Calculate the steady progress based on elapsed time
+ float elapsedTime = Time.time - startTime;
+ float steadyProgress = Mathf.Clamp01(elapsedTime / minimumDisplayTime);
+
+ // Get the actual loading progress from the current provider
+ float actualProgress = _currentProgressProvider();
+
+ // If loading is complete, actualProgress should be 1.0
+ if (_loadingComplete)
+ {
+ actualProgress = 1.0f;
+ }
+
+ // Use the minimum of steady progress and actual progress
+ // This ensures we don't show more progress than actual loading
+ float displayProgress = Mathf.Min(steadyProgress, actualProgress);
+
+ // Log the progress values for debugging
+ Debug.Log($"[InitialLoadingScreen] Progress - Default: {steadyProgress:F2}, Actual: {actualProgress:F2}, Display: {displayProgress:F2}");
+
+ // Directly set the progress bar fill amount without smoothing
+ if (progressBarImage != null)
+ {
+ progressBarImage.fillAmount = displayProgress;
+ }
+
+ // Check if the animation has completed
+ // Animation is complete when we've reached the minimum display time AND we're at 100% progress
+ if (steadyProgress >= 1.0f && displayProgress >= 1.0f)
+ {
+ _animationComplete = true;
+ Debug.Log("[InitialLoadingScreen] Animation complete");
+ break;
+ }
+
+ // Wait for the configured interval before updating again
+ yield return new WaitForSeconds(progressUpdateInterval);
+ }
+
+ // Ensure we end at 100% progress
+ if (progressBarImage != null)
+ {
+ progressBarImage.fillAmount = 1.0f;
+ Debug.Log("[InitialLoadingScreen] Final progress set to 1.0");
+ }
+
+ // Hide the screen if loading is also complete
+ if (_loadingComplete)
+ {
+ if (loadingScreenContainer != null)
+ {
+ loadingScreenContainer.SetActive(false);
+ Debug.Log("[InitialLoadingScreen] Animation AND loading complete, hiding screen");
+
+ // Invoke the callback when fully hidden
+ _onLoadingScreenFullyHidden?.Invoke();
+ OnLoadingScreenFullyHidden?.Invoke();
+ _onLoadingScreenFullyHidden = null;
+ }
+ }
+
+ _progressCoroutine = null;
+ }
+
+ ///
+ /// Called when the actual loading process is complete
+ ///
+ public void HideLoadingScreen()
+ {
+ Debug.Log("[InitialLoadingScreen] Loading complete, marking loading as finished");
+
+ // Mark that loading is complete
+ _loadingComplete = true;
+
+ // If animation is already complete, we can hide the screen now
+ if (_animationComplete)
+ {
+ if (loadingScreenContainer != null)
+ {
+ loadingScreenContainer.SetActive(false);
+ Debug.Log("[InitialLoadingScreen] Animation already complete, hiding screen immediately");
+
+ // Invoke the callback when fully hidden
+ _onLoadingScreenFullyHidden?.Invoke();
+ OnLoadingScreenFullyHidden?.Invoke();
+ _onLoadingScreenFullyHidden = null;
+ }
+ }
+ else
+ {
+ Debug.Log("[InitialLoadingScreen] Animation still in progress, waiting for it to complete");
+ // The coroutine will handle hiding when animation completes
+ }
+ }
+
+ ///
+ /// Waits until the loading screen is fully hidden before continuing
+ ///
+ /// Task that completes when the loading screen is hidden
+ public System.Threading.Tasks.Task WaitForLoadingScreenToHideAsync()
+ {
+ var tcs = new System.Threading.Tasks.TaskCompletionSource();
+
+ // If the loading screen is not active, complete immediately
+ if (!IsActive)
+ {
+ tcs.SetResult(true);
+ return tcs.Task;
+ }
+
+ // Store existing callback to chain it
+ Action existingCallback = _onLoadingScreenFullyHidden;
+
+ // Set new callback
+ _onLoadingScreenFullyHidden = () => {
+ // Call existing callback if any
+ existingCallback?.Invoke();
+
+ // Complete the task
+ tcs.SetResult(true);
+ };
+
+ return tcs.Task;
+ }
+ }
+}
diff --git a/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs.meta b/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs.meta
new file mode 100644
index 00000000..cf2bd6e7
--- /dev/null
+++ b/Assets/Scripts/Bootstrap/InitialLoadingScreen.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8968b564891a474baae157792b88e75f
+timeCreated: 1760613320
\ No newline at end of file
diff --git a/Assets/Scripts/Cinematics/CinematicsManager.cs b/Assets/Scripts/Cinematics/CinematicsManager.cs
index 884090d1..0fcbefd1 100644
--- a/Assets/Scripts/Cinematics/CinematicsManager.cs
+++ b/Assets/Scripts/Cinematics/CinematicsManager.cs
@@ -45,6 +45,14 @@ namespace Cinematics
}
}
public PlayableDirector playableDirector;
+
+ private void Awake()
+ {
+ _instance = this;
+
+ // Initialize required components
+ InitializeComponents();
+ }
private void OnEnable()
{
@@ -63,15 +71,55 @@ namespace Cinematics
private void OnApplicationQuit()
{
+ _isQuitting = true;
ReleaseAllHandles();
}
+ ///
+ /// Initializes required components for the CinematicsManager
+ ///
+ private void InitializeComponents()
+ {
+ // Initialize PlayableDirector if not set
+ if (playableDirector == null)
+ {
+ playableDirector = GetComponent();
+
+ // If still null, try to add the component
+ if (playableDirector == null)
+ {
+ playableDirector = gameObject.AddComponent();
+ Debug.Log("[CinematicsManager] Added missing PlayableDirector component");
+ }
+ }
+
+ // Initialize _cinematicSprites if not set
+ if (_cinematicSprites == null)
+ {
+ // First try to find in children
+ _cinematicSprites = GetComponentInChildren(true);
+
+ // If still null, create a new UI Image for cinematics
+ if (_cinematicSprites == null)
+ {
+ Debug.LogWarning("[CinematicsManager] No Image found for cinematics display. Cinematics may not display correctly.");
+ }
+ }
+ }
+
///
/// Plays a cinematic from an object reference and returns the PlayableDirector playing the timeline
///
public PlayableDirector PlayCinematic(PlayableAsset assetToPlay)
{
- _cinematicSprites.enabled = true;
+ // Ensure components are initialized before playing
+ InitializeComponents();
+
+ if (_cinematicSprites != null)
+ {
+ _cinematicSprites.enabled = true;
+ }
+
playableDirector.stopped += OnPlayableDirectorStopped;
playableDirector.Play(assetToPlay);
Logging.Debug("Playing cinematic " + assetToPlay.name);
@@ -146,68 +194,5 @@ namespace Cinematics
}
_addressableHandles.Clear();
}
-
- private void Start()
- {
-
- }
-
- ///
- /// Loads a cinematic asynchronously while showing a loading screen, then plays it
- ///
- /// The addressable key of the cinematic to load
- /// The PlayableDirector playing the cinematic
- public async System.Threading.Tasks.Task PlayCinematicWithLoadingScreen(string key)
- {
- Logging.Debug($"[CinematicsManager] Preparing to load cinematic with loading screen: {key}");
-
- // First, show the loading screen BEFORE creating any async operations
- UI.LoadingScreenController.Instance.ShowLoadingScreen();
-
- // Give the loading screen a frame to render
- await System.Threading.Tasks.Task.Yield();
-
- // Now create the load handle and track its progress
- Logging.Debug($"[CinematicsManager] Starting cinematic asset load: {key}");
- AsyncOperationHandle handle = Addressables.LoadAssetAsync(key);
-
- // Update the loading screen with the progress provider after the handle is created
- UI.LoadingScreenController.Instance.ShowLoadingScreen(() => handle.PercentComplete);
-
- // Wait for the loading to complete
- var result = await handle.Task;
-
- // Store the handle for later release
- _addressableHandles[playableDirector] = handle;
-
- Logging.Debug($"[CinematicsManager] Cinematic loaded: {key}");
-
- // Hide the loading screen
- UI.LoadingScreenController.Instance.HideLoadingScreen();
-
- // Important: Wait for the loading screen to be fully hidden before playing the cinematic
- await UI.LoadingScreenController.Instance.WaitForLoadingScreenToHideAsync();
-
- Logging.Debug($"[CinematicsManager] Loading screen hidden, now playing cinematic: {key}");
-
- // Play the cinematic
- return PlayCinematic(result);
- }
-
- private async void PlayStartCinematicOnGameLoad()
- {
- if (!SceneManager.GetActiveScene().name.ToLower().Contains("mainmenu"))
- {
- return;
- }
-
- _instance = this;
-
- playableDirector = GetComponent();
- _cinematicSprites = GetComponentInChildren(true);
-
- // Use the new method with loading screen instead of direct load
- await PlayCinematicWithLoadingScreen("IntroSequence");
- }
}
}
diff --git a/Assets/Scripts/Core/SceneManagerService.cs b/Assets/Scripts/Core/SceneManagerService.cs
index c36e7405..2df3ca5f 100644
--- a/Assets/Scripts/Core/SceneManagerService.cs
+++ b/Assets/Scripts/Core/SceneManagerService.cs
@@ -262,7 +262,7 @@ namespace Core
}
// Tracks the currently loaded gameplay scene (not persistent/bootstrapper)
- public string CurrentGameplayScene { get; private set; } = "MainMenu";
+ public string CurrentGameplayScene { get; set; } = "MainMenu";
public async Task ReloadCurrentScene(IProgress progress = null, bool autoHideLoadingScreen = true)
{
diff --git a/Assets/Scripts/UI/LoadingScreenController.cs b/Assets/Scripts/UI/LoadingScreenController.cs
index 085fdead..e902b7f7 100644
--- a/Assets/Scripts/UI/LoadingScreenController.cs
+++ b/Assets/Scripts/UI/LoadingScreenController.cs
@@ -68,7 +68,6 @@ namespace UI
private void Awake()
{
_instance = this;
- DontDestroyOnLoad(gameObject);
if (loadingScreenContainer == null)
loadingScreenContainer = gameObject;
diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset
index cf1d829f..9ac34527 100644
--- a/ProjectSettings/EditorBuildSettings.asset
+++ b/ProjectSettings/EditorBuildSettings.asset
@@ -5,6 +5,9 @@ EditorBuildSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Scenes:
+ - enabled: 1
+ path: Assets/Scenes/StartingScene.unity
+ guid: cf01e2d0135b06c4486d00ef393d0274
- enabled: 1
path: Assets/Scenes/MainMenu.unity
guid: b93f2f3b39a62684c8474ba79c8f698d