Add subtitle UI for voice playback
This commit is contained in:
212
Assets/Scripts/UI/HUD/SubtitleUI.cs
Normal file
212
Assets/Scripts/UI/HUD/SubtitleUI.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using BriarQueen.Framework.Coordinators.Events;
|
||||
using BriarQueen.Framework.Events.UI;
|
||||
using BriarQueen.Framework.Services.Subtitles;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using PrimeTween;
|
||||
using UnityEngine;
|
||||
using VContainer;
|
||||
|
||||
namespace BriarQueen.UI.HUD
|
||||
{
|
||||
public class SubtitleUI : MonoBehaviour
|
||||
{
|
||||
[Header("UI")]
|
||||
[SerializeField]
|
||||
private InteractTextUI _interactTextUI;
|
||||
|
||||
[SerializeField]
|
||||
private CanvasGroup _canvasGroup;
|
||||
|
||||
[Header("Tweens")]
|
||||
[SerializeField]
|
||||
private TweenSettings _tweenSettings = new()
|
||||
{
|
||||
duration = 0.2f,
|
||||
ease = Ease.InOutSine,
|
||||
useUnscaledTime = true
|
||||
};
|
||||
|
||||
private EventCoordinator _eventCoordinator;
|
||||
private SubtitleService _subtitleService;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private Sequence _sequence;
|
||||
|
||||
[Inject]
|
||||
public void Construct(EventCoordinator eventCoordinator, SubtitleService subtitleService)
|
||||
{
|
||||
_eventCoordinator = eventCoordinator;
|
||||
_subtitleService = subtitleService;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
ApplyImmediate(string.Empty, false);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_eventCoordinator?.Subscribe<SubtitleDisplayChangedEvent>(OnSubtitleDisplayChanged);
|
||||
SyncFromService();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_eventCoordinator?.Unsubscribe<SubtitleDisplayChangedEvent>(OnSubtitleDisplayChanged);
|
||||
StopTween();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
StopTween();
|
||||
}
|
||||
|
||||
private void SyncFromService()
|
||||
{
|
||||
if (_subtitleService != null && _subtitleService.IsVisible)
|
||||
{
|
||||
ApplyImmediate(_subtitleService.CurrentText, true);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyImmediate(string.Empty, false);
|
||||
}
|
||||
|
||||
private void OnSubtitleDisplayChanged(SubtitleDisplayChangedEvent eventData)
|
||||
{
|
||||
if (!eventData.Visible || string.IsNullOrWhiteSpace(eventData.Text))
|
||||
{
|
||||
HideSubtitle().Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
ShowSubtitle(eventData.Text).Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid ShowSubtitle(string text)
|
||||
{
|
||||
if (_canvasGroup == null || _interactTextUI == null)
|
||||
return;
|
||||
|
||||
StopTween();
|
||||
|
||||
_interactTextUI.SetText(text);
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
_canvasGroup.interactable = false;
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var tween = new TweenSettings<float>
|
||||
{
|
||||
startValue = _canvasGroup.alpha,
|
||||
endValue = 1f,
|
||||
settings = _tweenSettings
|
||||
};
|
||||
|
||||
_sequence = Sequence.Create(useUnscaledTime: true)
|
||||
.Group(Tween.Alpha(_canvasGroup, tween));
|
||||
|
||||
try
|
||||
{
|
||||
await _sequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DisposeTweenState();
|
||||
}
|
||||
|
||||
_canvasGroup.alpha = 1f;
|
||||
}
|
||||
|
||||
private async UniTaskVoid HideSubtitle()
|
||||
{
|
||||
if (_canvasGroup == null || _interactTextUI == null)
|
||||
return;
|
||||
|
||||
StopTween();
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var tween = new TweenSettings<float>
|
||||
{
|
||||
startValue = _canvasGroup.alpha,
|
||||
endValue = 0f,
|
||||
settings = _tweenSettings
|
||||
};
|
||||
|
||||
_sequence = Sequence.Create(useUnscaledTime: true)
|
||||
.Group(Tween.Alpha(_canvasGroup, tween));
|
||||
|
||||
try
|
||||
{
|
||||
await _sequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DisposeTweenState();
|
||||
}
|
||||
|
||||
ApplyImmediate(string.Empty, false);
|
||||
}
|
||||
|
||||
private void ApplyImmediate(string text, bool visible)
|
||||
{
|
||||
if (_interactTextUI != null)
|
||||
{
|
||||
if (visible)
|
||||
_interactTextUI.SetText(text);
|
||||
else
|
||||
_interactTextUI.ClearText();
|
||||
}
|
||||
|
||||
if (_canvasGroup == null)
|
||||
return;
|
||||
|
||||
_canvasGroup.alpha = visible ? 1f : 0f;
|
||||
_canvasGroup.blocksRaycasts = false;
|
||||
_canvasGroup.interactable = false;
|
||||
}
|
||||
|
||||
private void StopTween()
|
||||
{
|
||||
if (_sequence.isAlive)
|
||||
_sequence.Stop();
|
||||
|
||||
_sequence = default;
|
||||
|
||||
if (_cancellationTokenSource == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
}
|
||||
|
||||
private void DisposeTweenState()
|
||||
{
|
||||
_sequence = default;
|
||||
|
||||
if (_cancellationTokenSource == null)
|
||||
return;
|
||||
|
||||
_cancellationTokenSource.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user