Files
A-Fairytale-Gone-Bad-Briar-…/Assets/Scripts/Game/Cinematics/SplashScreens.cs

205 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using BriarQueen.Framework.Services.Game;
using BriarQueen.Game.Cinematics.Data;
using Cysharp.Threading.Tasks;
using NaughtyAttributes;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using VContainer;
namespace BriarQueen.Game.Cinematics
{
public class SplashScreens : MonoBehaviour
{
[SerializeField]
[ReorderableList]
private List<CinematicPanel> _splashScreens = new();
[SerializeField]
private Image _activeSplashScreen;
[Header("Playback")]
[Tooltip("Small fade for polish. Set to 0 for hard cuts.")]
[SerializeField]
private float _fadeDuration = 0.15f;
[SerializeField]
private bool _skipInvalidPanels = true;
private CancellationTokenSource _cts;
private GameService _gameService;
private bool _isPlaying;
[Inject]
public void Construct(GameService gameService)
{
_gameService = gameService;
}
private void OnDisable()
{
Stop();
}
public void Play()
{
if (_isPlaying)
return;
Debug.Log("[SplashScreens] Playing splash screens.");
_isPlaying = true;
_cts?.Dispose();
_cts = new CancellationTokenSource();
RunSequence(_cts.Token).Forget();
}
public void Stop()
{
if (!_isPlaying)
return;
_isPlaying = false;
try
{
_cts?.Cancel();
}
catch
{
}
finally
{
_cts?.Dispose();
_cts = null;
}
}
private async UniTaskVoid RunSequence(CancellationToken token)
{
try
{
Debug.Log("[SplashScreens] Splash screen sequence started.");
if (_activeSplashScreen == null)
{
Debug.LogWarning("[SplashScreens] Active splash Image is not assigned.");
await EndSplashScreens();
return;
}
var cg = _activeSplashScreen.GetComponent<CanvasGroup>();
if (cg == null)
cg = _activeSplashScreen.gameObject.AddComponent<CanvasGroup>();
cg.alpha = 0f;
_activeSplashScreen.enabled = true;
if (_splashScreens == null || _splashScreens.Count == 0)
{
Debug.LogWarning("[SplashScreens] No splash panels configured.");
await EndSplashScreens();
return;
}
for (var i = 0; i < _splashScreens.Count; i++)
{
token.ThrowIfCancellationRequested();
var panel = _splashScreens[i];
if (panel == null || panel.CinematicImage == null)
{
if (_skipInvalidPanels)
continue;
Debug.LogWarning($"[SplashScreens] Splash panel at index {i} is null or missing image.");
continue;
}
_activeSplashScreen.sprite = panel.CinematicImage;
if (_fadeDuration > 0f)
await FadeTo(cg, 1f, _fadeDuration, token);
else
cg.alpha = 1f;
var hold = Mathf.Max(0f, panel.DisplayTime);
if (hold > 0f)
await UniTask.Delay(TimeSpan.FromSeconds(hold), cancellationToken: token);
if (_fadeDuration > 0f)
await FadeTo(cg, 0f, _fadeDuration, token);
else
cg.alpha = 0f;
}
await EndSplashScreens();
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
Debug.LogError($"[SplashScreens] Sequence failed: {ex}");
try
{
await EndSplashScreens();
}
catch
{
}
}
finally
{
_isPlaying = false;
}
}
private async UniTask FadeTo(CanvasGroup cg, float target, float duration, CancellationToken token)
{
var start = cg.alpha;
if (Mathf.Approximately(start, target))
{
cg.alpha = target;
return;
}
var t = 0f;
while (t < duration)
{
token.ThrowIfCancellationRequested();
t += Time.deltaTime;
var p = Mathf.Clamp01(t / duration);
cg.alpha = Mathf.Lerp(start, target, p);
await UniTask.NextFrame(token);
}
cg.alpha = target;
}
private async UniTask EndSplashScreens()
{
if (_gameService != null)
{
await _gameService.LoadUIAndMainMenuScene();
}
else
{
Debug.LogWarning("[SplashScreens] GameService is null; cannot load UI/MainMenu scene.");
}
const string bootstrapSceneName = "00_Bootstrap";
var scene = SceneManager.GetSceneByName(bootstrapSceneName);
if (scene.IsValid() && scene.isLoaded)
await SceneManager.UnloadSceneAsync(bootstrapSceneName);
}
}
}