(Fix) Loading Screen
This commit is contained in:
@@ -15,9 +15,11 @@ namespace Ashwild.UI
|
||||
/// switch behind a quote-cycling curtain.
|
||||
///
|
||||
/// Place it on its own high-sorting-order Canvas in the menu scene (mirror SplashScreenController).
|
||||
/// It is driven entirely by the PlayerEvents bus: SessionStarting/SessionJoining raise it,
|
||||
/// LocalPlayerSpawned lowers it, and SessionError/SessionStopped lower it as a safety net so a
|
||||
/// failed host never leaves the player stuck behind the curtain.
|
||||
/// It is driven entirely by the PlayerEvents bus: SessionStarting/SessionJoining raise it for the
|
||||
/// menu→game transition (lowered by LocalPlayerSpawned), and ReturningToMenu raises it for the
|
||||
/// game→menu transition (lowered by MenuReady once the menu has loaded). SessionError lowers it as
|
||||
/// a safety net so a failed host never leaves the player stuck behind the curtain; SessionStopped
|
||||
/// does the same except while a return-to-menu is in flight, where that teardown event is expected.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[RequireComponent(typeof(CanvasGroup))]
|
||||
@@ -41,6 +43,12 @@ namespace Ashwild.UI
|
||||
[Tooltip("Minimum time the curtain stays up once raised, so an instant load doesn't flash.")]
|
||||
[SerializeField] private float minimumDisplayTime = 1.5f;
|
||||
|
||||
[Tooltip("Extra time the curtain holds after the ready signal (player spawned / menu loaded) " +
|
||||
"before fading out, so the scene's first heavy frames (object pop-in, shader warmup) " +
|
||||
"settle behind it instead of stuttering on screen. Stacks as the max with the " +
|
||||
"remaining minimum display time.")]
|
||||
[SerializeField] private float settleDelay = 0.75f;
|
||||
|
||||
[Header("Quote Cycling")]
|
||||
[Tooltip("How long each quote stays on screen before swapping to the next.")]
|
||||
[SerializeField] private float quoteDuration = 4f;
|
||||
@@ -68,6 +76,13 @@ namespace Ashwild.UI
|
||||
/// </summary>
|
||||
private float shownAt;
|
||||
|
||||
/// <summary>
|
||||
/// True while the curtain is covering a return-to-menu transition. SessionStopped fires during
|
||||
/// that teardown, so this flag tells the curtain to ignore it and wait for MenuReady instead —
|
||||
/// otherwise the curtain would drop the instant the session stopped, before the menu has loaded.
|
||||
/// </summary>
|
||||
private bool awaitingMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the quote currently displayed, so the next pick can avoid repeating it.
|
||||
/// </summary>
|
||||
@@ -82,6 +97,12 @@ namespace Ashwild.UI
|
||||
|
||||
/// <summary>
|
||||
/// Enforces the singleton, persists across the menu→game scene swap, and starts hidden.
|
||||
///
|
||||
/// Detaches to a root object before <see cref="Object.DontDestroyOnLoad"/>: that call is a
|
||||
/// no-op on a child, so a nested curtain would be destroyed the moment FishNet unloads the menu
|
||||
/// (ReplaceOption.All) — leaving the load uncovered and, later, no curtain at all to raise on
|
||||
/// the return to menu. Promoting it here keeps the scene authoring free to nest it under a
|
||||
/// layout object while still guaranteeing it survives every scene swap.
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
@@ -91,6 +112,7 @@ namespace Ashwild.UI
|
||||
return;
|
||||
}
|
||||
instance = this;
|
||||
transform.SetParent(null, false);
|
||||
DontDestroyOnLoad(gameObject);
|
||||
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
@@ -107,6 +129,8 @@ namespace Ashwild.UI
|
||||
PlayerEvents.SessionStarting += HandleSessionBeginning;
|
||||
PlayerEvents.SessionJoining += HandleSessionJoining;
|
||||
PlayerEvents.LocalPlayerSpawned += HandleLocalPlayerSpawned;
|
||||
PlayerEvents.ReturningToMenu += HandleReturningToMenu;
|
||||
PlayerEvents.MenuReady += HandleMenuReady;
|
||||
PlayerEvents.SessionError += HandleSessionError;
|
||||
PlayerEvents.SessionStopped += HandleSessionStopped;
|
||||
}
|
||||
@@ -119,6 +143,8 @@ namespace Ashwild.UI
|
||||
PlayerEvents.SessionStarting -= HandleSessionBeginning;
|
||||
PlayerEvents.SessionJoining -= HandleSessionJoining;
|
||||
PlayerEvents.LocalPlayerSpawned -= HandleLocalPlayerSpawned;
|
||||
PlayerEvents.ReturningToMenu -= HandleReturningToMenu;
|
||||
PlayerEvents.MenuReady -= HandleMenuReady;
|
||||
PlayerEvents.SessionError -= HandleSessionError;
|
||||
PlayerEvents.SessionStopped -= HandleSessionStopped;
|
||||
}
|
||||
@@ -140,12 +166,30 @@ namespace Ashwild.UI
|
||||
/// <summary>
|
||||
/// Raises the curtain when the local player starts hosting a session.
|
||||
/// </summary>
|
||||
private void HandleSessionBeginning() => Show();
|
||||
private void HandleSessionBeginning()
|
||||
{
|
||||
awaitingMenu = false;
|
||||
Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the curtain when the local player begins joining a remote session.
|
||||
/// </summary>
|
||||
private void HandleSessionJoining(string code) => Show();
|
||||
private void HandleSessionJoining(string code)
|
||||
{
|
||||
awaitingMenu = false;
|
||||
Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the curtain over a return-to-menu transition and arms the wait for MenuReady, so the
|
||||
/// upcoming SessionStopped (part of the teardown) does not drop it prematurely.
|
||||
/// </summary>
|
||||
private void HandleReturningToMenu()
|
||||
{
|
||||
awaitingMenu = true;
|
||||
Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lowers the curtain once the local player has spawned into the loaded game scene.
|
||||
@@ -153,14 +197,32 @@ namespace Ashwild.UI
|
||||
private void HandleLocalPlayerSpawned() => Hide();
|
||||
|
||||
/// <summary>
|
||||
/// Safety net: a connection failure must drop the curtain so the menu becomes usable again.
|
||||
/// Lowers the curtain once the menu scene has finished loading on a return-to-menu transition.
|
||||
/// </summary>
|
||||
private void HandleSessionError(string reason) => Hide();
|
||||
private void HandleMenuReady()
|
||||
{
|
||||
awaitingMenu = false;
|
||||
Hide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safety net: if the session tears down before a player spawns, never leave the curtain up.
|
||||
/// Safety net: a connection failure must drop the curtain so the menu becomes usable again.
|
||||
/// </summary>
|
||||
private void HandleSessionStopped() => Hide();
|
||||
private void HandleSessionError(string reason)
|
||||
{
|
||||
awaitingMenu = false;
|
||||
Hide();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safety net for a session that tears down before a player spawns. Skipped while returning to
|
||||
/// the menu, where SessionStopped is expected and the curtain must stay up until MenuReady.
|
||||
/// </summary>
|
||||
private void HandleSessionStopped()
|
||||
{
|
||||
if (awaitingMenu) return;
|
||||
Hide();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -169,6 +231,12 @@ namespace Ashwild.UI
|
||||
/// <summary>
|
||||
/// Fades the curtain in (blocking input underneath) and starts cycling quotes. Ignored when
|
||||
/// already shown so re-entrant session events don't restart the animation.
|
||||
///
|
||||
/// Raises <see cref="PlayerEvents.LoadingCurtainShown"/> only once the fade-in has fully
|
||||
/// completed: NetworkSessionManager waits for that signal before kicking off the heavy game
|
||||
/// scene load, so the unavoidable activation freeze always happens behind an already-opaque
|
||||
/// curtain instead of stalling the very frame the curtain was meant to appear on. Killing the
|
||||
/// tween early (an instant Hide) suppresses the signal, which is the intended behaviour.
|
||||
/// </summary>
|
||||
private void Show()
|
||||
{
|
||||
@@ -182,15 +250,18 @@ namespace Ashwild.UI
|
||||
|
||||
curtainTween = canvasGroup.DOFade(1f, fadeInDuration)
|
||||
.SetEase(fadeInEase)
|
||||
.SetUpdate(true);
|
||||
.SetUpdate(true)
|
||||
.OnComplete(PlayerEvents.RaiseLoadingCurtainShown);
|
||||
|
||||
ShowNextQuote(instant: true);
|
||||
StartQuoteCycle();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fades the curtain out and stops the quote cycle. Honours the minimum display time so an
|
||||
/// instant load still shows the loading screen for a readable beat instead of flashing.
|
||||
/// Fades the curtain out and stops the quote cycle. The fade is delayed by the larger of the
|
||||
/// remaining minimum display time (so an instant load still shows the curtain for a readable
|
||||
/// beat instead of flashing) and the settle delay (so the scene's first heavy frames after the
|
||||
/// ready signal happen behind the curtain rather than stuttering on screen).
|
||||
/// </summary>
|
||||
private void Hide()
|
||||
{
|
||||
@@ -198,7 +269,7 @@ namespace Ashwild.UI
|
||||
isShown = false;
|
||||
|
||||
float elapsed = Time.unscaledTime - shownAt;
|
||||
float delay = Mathf.Max(0f, minimumDisplayTime - elapsed);
|
||||
float delay = Mathf.Max(settleDelay, minimumDisplayTime - elapsed);
|
||||
|
||||
curtainTween?.Kill();
|
||||
curtainTween = canvasGroup.DOFade(0f, fadeOutDuration)
|
||||
|
||||
Reference in New Issue
Block a user