Add subtitle UI for voice playback

This commit is contained in:
2026-05-16 21:33:00 +01:00
parent 58050abded
commit 3174079e37
81 changed files with 8657 additions and 1231 deletions

View File

@@ -92,15 +92,9 @@ namespace BriarQueen.Game.Items.Environment.General.Book
_bookInterface.CanvasGroup.blocksRaycasts = true;
_bookInterface.CanvasGroup.interactable = true;
ShowTutorialIfNeeded();
UnlockCodexEntry();
}
private void ShowTutorialIfNeeded()
{
TutorialService.DisplayTutorial(TutorialPopupID.ExitItems);
}
private void UnlockCodexEntry()
{
PlayerManager.UnlockCodexEntry(CodexEntryIDs.Get(_documentEntryID));

View File

@@ -16,6 +16,13 @@ namespace BriarQueen.Game.Items.Environment.General
[SerializeField]
private bool _removeTrigger;
[Header("Events")]
[SerializeField]
private SFXKey _soundEffect;
[SerializeField]
private VoiceKey _voiceLine;
public override UICursorService.CursorStyle ApplicableCursorStyle => UICursorService.CursorStyle.Inspect;
public override string InteractableName => InteractableTooltip;
@@ -29,6 +36,16 @@ namespace BriarQueen.Game.Items.Environment.General
if (_removeTrigger)
await Remove();
if (_soundEffect != SFXKey.None)
{
AudioManager.Play(AudioNameIdentifiers.Get(_soundEffect));
}
if (_voiceLine != VoiceKey.None)
{
AudioManager.Play(AudioNameIdentifiers.Get(_voiceLine));
}
}
}
}

View File

@@ -21,9 +21,6 @@ namespace BriarQueen.Game.Levels.ChapterOne.Ashwick
[SerializeField]
private AshwickGate _ashwickGate;
[SerializeField]
private TransitionZone _keypadZone;
[SerializeField]
private TransitionZone _nextLevelZone;
@@ -36,22 +33,17 @@ namespace BriarQueen.Game.Levels.ChapterOne.Ashwick
_background.sprite = _backgroundOpenSprite;
_nextLevelZone.Unlock();
await DestructionService.Destroy(_ashwickGate.gameObject);
await DestructionService.Destroy(_keypadZone.gameObject);
}
}
public async UniTask OpenGate()
{
EventCoordinator.PublishImmediate(new FadeEvent(false));
_background.sprite = _backgroundOpenSprite;
_nextLevelZone.Unlock();
await DestructionService.Destroy(_ashwickGate.gameObject);
await DestructionService.Destroy(_keypadZone.gameObject);
SaveManager.SetLevelFlag(LevelFlag.AshwickGateOpen, true);
EventCoordinator.PublishImmediate(new FadeEvent(true));
}
}
}

View File

@@ -1,24 +0,0 @@
using BriarQueen.Data.Identifiers;
using BriarQueen.Data.IO.Saves;
using BriarQueen.Framework.Events.Save;
using BriarQueen.Framework.Events.UI;
using BriarQueen.Framework.Managers.Levels.Data;
using Cysharp.Threading.Tasks;
namespace BriarQueen.Game.Levels.ChapterOne.Ashwick
{
public class Marketplace : BaseLevel
{
protected override UniTask PostActivateInternal()
{
if (SaveManager.GetLevelFlag(LevelFlag.MarketplaceFirstEntry))
return UniTask.CompletedTask;
EventCoordinator.Publish(new DisplayInteractEvent(InteractEventIDs.Get(LevelInteractKey.MarketplaceFirstEntry)));
SaveManager.SetLevelFlag(LevelFlag.MarketplaceFirstEntry, true);
return UniTask.CompletedTask;
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: 2d9beb847a184e2e897942fff18a396e
timeCreated: 1778696777

View File

@@ -10,6 +10,7 @@ using BriarQueen.Framework.Managers.Levels;
using BriarQueen.Framework.Managers.Player;
using BriarQueen.Framework.Managers.UI;
using BriarQueen.Framework.Services.Settings;
using BriarQueen.Framework.Services.Subtitles;
using BriarQueen.Framework.Services.Tutorials;
using BriarQueen.Game.Cinematics;
using Cysharp.Threading.Tasks;
@@ -30,6 +31,7 @@ namespace BriarQueen.Game.Misc
private readonly SettingsService _settingsService;
private readonly SplashScreens _splashScreens;
private readonly SteamManager _steamManager;
private readonly SubtitleService _subtitleService;
private readonly TutorialService _tutorialService;
private readonly UIManager _uiManager;
@@ -45,6 +47,7 @@ namespace BriarQueen.Game.Misc
SettingsService settingsService,
SteamManager steamManager,
SplashScreens splashScreens,
SubtitleService subtitleService,
TutorialService tutorialService)
{
_audioManager = audioManager;
@@ -58,6 +61,8 @@ namespace BriarQueen.Game.Misc
_settingsService = settingsService;
_steamManager = steamManager;
_splashScreens = splashScreens;
_subtitleService = subtitleService;
_tutorialService = tutorialService;
}
public async UniTask StartAsync(CancellationToken cancellationToken)
@@ -67,6 +72,9 @@ namespace BriarQueen.Game.Misc
Debug.Log("[Bootstrap] Audio...");
_audioManager.Initialize();
Debug.Log("[Bootstrap] Subtitles...");
_subtitleService.Initialize();
Debug.Log("[Bootstrap] Settings...");
await _settingsService.InitializeAsync();
@@ -99,4 +107,4 @@ namespace BriarQueen.Game.Misc
Debug.Log("[Bootstrap] Called SplashScreens.Play()");
}
}
}
}

View File

@@ -1,5 +1,6 @@
using BriarQueen.Framework.Managers.Levels.Data;
using BriarQueen.Framework.Managers.Player.Data;
using BriarQueen.Framework.Managers.UI;
using Cysharp.Threading.Tasks;
using UnityEngine;
@@ -7,10 +8,13 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
{
public class AshwickGate : BaseItem
{
[Header("Keypad")]
[SerializeField] private AshwickGateKeypadPuzzle _keypadPuzzle;
public override string InteractableName => "Iron Gate";
public override UICursorService.CursorStyle ApplicableCursorStyle => UICursorService.CursorStyle.Interact;
public override UniTask OnInteract(ItemDataSo item = null)
{
if (!CheckEmptyHands())

View File

@@ -5,7 +5,10 @@ using BriarQueen.Data.IO.Saves;
using BriarQueen.Framework.Effects;
using BriarQueen.Framework.Events.Save;
using BriarQueen.Framework.Managers.Interaction;
using BriarQueen.Framework.Managers.UI;
using BriarQueen.Framework.Managers.UI.Base;
using BriarQueen.Framework.Services.Puzzles.Base;
using BriarQueen.Framework.Services.Tutorials;
using BriarQueen.Game.Levels.ChapterOne.Ashwick;
using Cysharp.Threading.Tasks;
using MemoryPack;
@@ -24,7 +27,7 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
public string Digits;
}
public class AshwickGateKeypadPuzzle : BasePuzzle, IPuzzleStateful
public class AshwickGateKeypadPuzzle : BasePuzzle, IPuzzleStateful, IUIWindow, IUIBackHandler, IUIOverlayHost
{
private const string CorrectCode = "312";
private const int RequiredDigits = 3;
@@ -63,14 +66,25 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
private bool _isEvaluating;
private bool _isOpen;
private bool _raycasterRegistered;
private bool _skipSaveOnHide;
private TutorialService _tutorialService;
private UIManager _uiManager;
public override string PuzzleID => PuzzleIdentifiers.AllPuzzles[PuzzleKey.AshwickMarketGate];
public bool IsCompleted => _isCompleted || SaveManager.GetLevelFlag(LevelFlag.AshwickGateOpen);
public WindowType WindowType => WindowType.AshwickGateKeypadWindow;
public UIPauseBehavior PauseBehavior => UIPauseBehavior.OpenPauseOverlay;
[Inject]
public void ConstructKeypad(InteractManager interactManager)
public void ConstructKeypad(
InteractManager interactManager,
UIManager uiManager,
TutorialService tutorialService)
{
_interactManager = interactManager;
_uiManager = uiManager;
_tutorialService = tutorialService;
}
private void Awake()
@@ -86,8 +100,14 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
SyncDisplay();
}
private void Start()
{
_uiManager?.RegisterWindow(this);
}
private void OnDestroy()
{
_uiManager?.UnregisterWindow(this);
UnbindButtons();
TryUnregisterRaycaster();
CancelPanelTween();
@@ -98,10 +118,7 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
_isCompleted = SaveManager.GetLevelFlag(LevelFlag.AshwickGateOpen);
_isOpen = false;
_isEvaluating = false;
SetPanelState(0f, false, false);
SyncDisplay();
_statusGlow?.TurnOff().Forget();
_skipSaveOnHide = false;
return UniTask.CompletedTask;
}
@@ -113,12 +130,15 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
public void Open()
{
OpenInternal().Forget();
if (IsCompleted || _uiManager == null)
return;
_uiManager.OpenWindow(WindowType);
}
public void Close()
{
CloseInternal(requestSave: true).Forget();
_uiManager?.CloseWindow(WindowType);
}
public UniTask<byte[]> CaptureState()
@@ -159,12 +179,13 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
SyncDisplay();
SaveManager.SetPuzzleCompleted(PuzzleKey.AshwickMarketGate, true, requestSave: false);
await CloseInternal(requestSave: false);
_skipSaveOnHide = true;
_uiManager?.CloseWindow(WindowType);
AudioManager.Play(AudioNameIdentifiers.Get(SFXKey.AshwickGateOpening));
await _outskirts.OpenGate();
}
private async UniTaskVoid OpenInternal()
public async UniTask Show()
{
if (IsCompleted || _isEvaluating || _isOpen)
return;
@@ -174,8 +195,7 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
SetPanelState(0f, false, true);
SyncDisplay();
TryRegisterRaycaster();
_statusGlow?.TurnOff().Forget();
EnsureExclusiveRaycaster();
try
{
@@ -199,9 +219,10 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
}
SetPanelState(1f, true, true);
_tutorialService?.DisplayTutorial(TutorialPopupID.LeavingPuzzles);
}
private async UniTask CloseInternal(bool requestSave)
public async UniTask Hide()
{
if (!_isOpen)
return;
@@ -239,8 +260,91 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
SetPanelState(0f, false, false);
TryUnregisterRaycaster();
if (requestSave)
if (!_skipSaveOnHide && !_isCompleted)
EventCoordinator.PublishImmediate(new RequestGameSaveEvent());
_skipSaveOnHide = false;
}
public bool HandleBackRequest()
{
Close();
return true;
}
public bool CanSuspendFor(WindowType incomingWindowType)
{
return incomingWindowType == WindowType.PauseMenuWindow;
}
public async UniTask SuspendForOverlay()
{
if (!_isOpen)
return;
ResetPanelTween();
if (_panelGroup != null)
{
_panelGroup.interactable = false;
_panelGroup.blocksRaycasts = false;
}
try
{
_panelSequence = Sequence.Create(useUnscaledTime: true)
.Group(Tween.Alpha(_panelGroup, new TweenSettings<float>
{
startValue = _panelGroup != null ? _panelGroup.alpha : 1f,
endValue = 0f,
settings = _panelFadeTweenSettings
}));
await _panelSequence.ToUniTask(cancellationToken: _panelCts.Token);
}
catch (OperationCanceledException)
{
return;
}
finally
{
_panelSequence = default;
}
SetPanelState(0f, false, false);
}
public async UniTask ResumeFromOverlay()
{
if (!_isOpen)
return;
ResetPanelTween();
EnsureExclusiveRaycaster();
SetPanelState(0f, false, true);
try
{
_panelSequence = Sequence.Create(useUnscaledTime: true)
.Group(Tween.Alpha(_panelGroup, new TweenSettings<float>
{
startValue = 0f,
endValue = 1f,
settings = _panelFadeTweenSettings
}));
await _panelSequence.ToUniTask(cancellationToken: _panelCts.Token);
}
catch (OperationCanceledException)
{
return;
}
finally
{
_panelSequence = default;
}
SetPanelState(1f, !_isEvaluating, true);
}
private void OnDigitPressed(int digit)
@@ -370,14 +474,18 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
}
}
private void TryRegisterRaycaster()
private void EnsureExclusiveRaycaster()
{
if (_raycasterRegistered || _interactManager == null || _graphicRaycaster == null)
if (_interactManager == null || _graphicRaycaster == null)
return;
_interactManager.AddUIRaycaster(_graphicRaycaster);
if (!_raycasterRegistered)
{
_interactManager.AddUIRaycaster(_graphicRaycaster);
_raycasterRegistered = true;
}
_interactManager.SetExclusiveRaycaster(_graphicRaycaster);
_raycasterRegistered = true;
}
private void TryUnregisterRaycaster()
@@ -386,7 +494,7 @@ namespace BriarQueen.Game.Puzzles.ChapterOne.AshwickHallow
return;
_interactManager.RemoveUIRaycaster(_graphicRaycaster);
_interactManager.ClearExclusiveRaycaster();
_interactManager.ReleaseExclusiveRaycaster(_graphicRaycaster);
_raycasterRegistered = false;
}
}

View File

@@ -15,6 +15,7 @@ using BriarQueen.Framework.Services.Destruction;
using BriarQueen.Framework.Services.Game;
using BriarQueen.Framework.Services.Puzzles;
using BriarQueen.Framework.Services.Settings;
using BriarQueen.Framework.Services.Subtitles;
using BriarQueen.Framework.Services.Tutorials;
using BriarQueen.Game.Cinematics;
using BriarQueen.Game.Misc;
@@ -89,8 +90,9 @@ namespace BriarQueen.Game.Scopes
builder.Register<SaveManager>(Lifetime.Singleton);
builder.Register<SettingsService>(Lifetime.Singleton);
builder.Register<SteamManager>(Lifetime.Singleton);
builder.Register<SubtitleService>(Lifetime.Singleton);
builder.Register<TutorialService>(Lifetime.Singleton);
builder.Register<UIManager>(Lifetime.Singleton);
}
}
}
}