Files
A-Fairytale-Gone-Bad-Briar-…/Assets/Scripts/UI/Menus/PauseMenuWindow.cs

308 lines
9.0 KiB
C#

using System;
using System.Threading;
using BriarQueen.Framework.Coordinators.Events;
using BriarQueen.Framework.Events.UI;
using BriarQueen.Framework.Managers.Audio;
using BriarQueen.Framework.Managers.Interaction;
using BriarQueen.Framework.Managers.IO;
using BriarQueen.Framework.Managers.UI.Base;
using BriarQueen.Framework.Managers.UI.Events;
using BriarQueen.Framework.Services.Game;
using Cysharp.Threading.Tasks;
using PrimeTween;
using UnityEngine;
using UnityEngine.UI;
using VContainer;
namespace BriarQueen.UI.Menus
{
public class PauseMenuWindow : MonoBehaviour, IUIWindow
{
[Header("Root UI")]
[SerializeField]
private CanvasGroup _canvasGroup;
[SerializeField]
private RectTransform _windowRect;
[Header("Buttons")]
[SerializeField]
private Button _resumeButton;
[SerializeField]
private Button _saveButton;
[SerializeField]
private Button _settingsButton;
[SerializeField]
private Button _exitButton;
[SerializeField]
private Button _quitToDesktopButton;
[Header("Tween Settings")]
[SerializeField]
private TweenSettings _tweenSettings = new()
{
duration = 0.25f,
ease = Ease.OutQuad,
useUnscaledTime = true
};
[Header("Scale")]
[SerializeField]
private float _hiddenScale = 0.85f;
[Header("Internal")]
[SerializeField]
private GraphicRaycaster _graphicRaycaster;
private AudioManager _audioManager;
private CancellationTokenSource _cts;
private EventCoordinator _eventCoordinator;
private GameService _gameService;
private InteractManager _interactManager;
private SaveManager _saveManager;
private Sequence _sequence;
public bool IsModal => true;
public WindowType WindowType => WindowType.PauseMenuWindow;
private void Awake()
{
// Start hidden by default
if (_canvasGroup != null)
{
_canvasGroup.alpha = 0f;
_canvasGroup.blocksRaycasts = false;
_canvasGroup.interactable = false;
}
if (_windowRect != null)
_windowRect.localScale = Vector3.one * _hiddenScale;
}
private void OnEnable()
{
if (_resumeButton != null) _resumeButton.onClick.AddListener(OnResumeButtonClick);
if (_saveButton != null) _saveButton.onClick.AddListener(OnSaveButtonClick);
if (_settingsButton != null) _settingsButton.onClick.AddListener(OnSettingsButtonClick);
if (_exitButton != null) _exitButton.onClick.AddListener(OnExitButtonClick);
if (_quitToDesktopButton != null) _quitToDesktopButton.onClick.AddListener(OnQuitToDesktopButtonClick);
_interactManager.SetExclusiveRaycaster(_graphicRaycaster);
}
private void OnDisable()
{
if (_resumeButton != null) _resumeButton.onClick.RemoveListener(OnResumeButtonClick);
if (_saveButton != null) _saveButton.onClick.RemoveListener(OnSaveButtonClick);
if (_settingsButton != null) _settingsButton.onClick.RemoveListener(OnSettingsButtonClick);
if (_exitButton != null) _exitButton.onClick.RemoveListener(OnExitButtonClick);
if (_quitToDesktopButton != null) _quitToDesktopButton.onClick.RemoveListener(OnQuitToDesktopButtonClick);
_interactManager.ClearExclusiveRaycaster();
}
private void OnDestroy()
{
StopAndResetCancellation();
}
public async UniTask Show()
{
if (_canvasGroup == null || _windowRect == null)
{
Debug.LogError("[PauseMenuWindow] Missing CanvasGroup or WindowRect reference.");
gameObject.SetActive(true);
return;
}
StopAndResetCancellation();
gameObject.SetActive(true);
_canvasGroup.alpha = 0f;
_canvasGroup.blocksRaycasts = false;
_canvasGroup.interactable = false;
_windowRect.localScale = Vector3.one * _hiddenScale;
var alpha = new TweenSettings<float>
{
startValue = 0f,
endValue = 1f,
settings = _tweenSettings
};
var scale = new TweenSettings<Vector3>
{
startValue = Vector3.one * _hiddenScale,
endValue = Vector3.one,
settings = _tweenSettings
};
_sequence = Sequence.Create(useUnscaledTime: true)
.Group(Tween.Alpha(_canvasGroup, alpha))
.Group(Tween.Scale(_windowRect, scale));
try
{
await _sequence.ToUniTask(cancellationToken: _cts.Token);
}
catch (OperationCanceledException)
{
return;
}
finally
{
_sequence = default;
}
_canvasGroup.alpha = 1f;
_windowRect.localScale = Vector3.one;
_canvasGroup.blocksRaycasts = true;
_canvasGroup.interactable = true;
}
public async UniTask Hide()
{
if (_canvasGroup == null || _windowRect == null)
{
gameObject.SetActive(false);
return;
}
StopAndResetCancellation();
// Block clicks immediately
_canvasGroup.blocksRaycasts = false;
_canvasGroup.interactable = false;
var alpha = new TweenSettings<float>
{
startValue = _canvasGroup.alpha,
endValue = 0f,
settings = _tweenSettings
};
var scale = new TweenSettings<Vector3>
{
startValue = _windowRect.localScale,
endValue = Vector3.one * _hiddenScale,
settings = _tweenSettings
};
_sequence = Sequence.Create(useUnscaledTime: true)
.Group(Tween.Alpha(_canvasGroup, alpha))
.Group(Tween.Scale(_windowRect, scale));
try
{
await _sequence.ToUniTask(cancellationToken: _cts.Token);
}
catch (OperationCanceledException)
{
return;
}
finally
{
_sequence = default;
}
_canvasGroup.alpha = 0f;
_windowRect.localScale = Vector3.one * _hiddenScale;
gameObject.SetActive(false);
}
[Inject]
public void Construct(EventCoordinator eventCoordinator, SaveManager saveManager, GameService gameService,
InteractManager interactManager, AudioManager audioManager)
{
_eventCoordinator = eventCoordinator;
_saveManager = saveManager;
_gameService = gameService;
_interactManager = interactManager;
_audioManager = audioManager;
}
private void StopAndResetCancellation()
{
if (_sequence.isAlive)
_sequence.Stop();
if (_cts != null)
{
try
{
_cts.Cancel();
}
catch
{
}
_cts.Dispose();
_cts = null;
}
_cts = new CancellationTokenSource();
}
private void OnResumeButtonClick()
{
_eventCoordinator?.Publish(new PauseButtonClickedEvent());
}
private void OnSaveButtonClick()
{
SaveGame().Forget();
}
private void OnSettingsButtonClick()
{
_eventCoordinator.Publish(new UIToggleSettingsWindow(true));
}
private void OnExitButtonClick()
{
_eventCoordinator.Publish(new FadeEvent(false, 1f));
ExitButtonInternal().Forget();
}
private async UniTask ExitButtonInternal()
{
await UniTask.Delay(TimeSpan.FromSeconds(1));
_audioManager.StopAllAudio();
await SaveGame();
_eventCoordinator.Publish(new PauseButtonClickedEvent());
await _gameService.LoadMainMenu();
}
private void OnQuitToDesktopButtonClick()
{
QuitButtonInternal().Forget();
}
private async UniTask QuitButtonInternal()
{
_eventCoordinator.Publish(new FadeEvent(false, 1f));
await UniTask.Delay(TimeSpan.FromSeconds(1));
await SaveGame();
_gameService.QuitGame();
}
private async UniTask SaveGame()
{
if (_saveManager == null) return;
await _saveManager.SaveGameDataLatest();
// TODO: Saved feedback popup/toast
}
}
}