282 lines
8.1 KiB
C#
282 lines
8.1 KiB
C#
using System;
|
|
using System.Threading;
|
|
using BriarQueen.Framework.Managers.UI;
|
|
using BriarQueen.Framework.Managers.UI.Base;
|
|
using Cysharp.Threading.Tasks;
|
|
using PrimeTween;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using VContainer;
|
|
|
|
namespace BriarQueen.UI.HUD
|
|
{
|
|
/// <summary>
|
|
/// Minimal HUD holder:
|
|
/// - Registers itself with UIManager
|
|
/// - Handles HUD visibility (alpha tween only)
|
|
/// </summary>
|
|
public class HUDContainer : MonoBehaviour, IHud
|
|
{
|
|
private const float DISPLAY_TIME = 4f;
|
|
|
|
[Header("UI")]
|
|
[SerializeField]
|
|
private CursorTooltip _cursorTooltip;
|
|
[SerializeField]
|
|
private InteractTextUI _interactText;
|
|
|
|
[Header("Inventory")]
|
|
[SerializeField]
|
|
private InventoryBar _inventoryBar;
|
|
|
|
[Header("Components")]
|
|
[SerializeField]
|
|
private CanvasGroup _mainCanvasGroup;
|
|
|
|
|
|
[SerializeField]
|
|
private CanvasGroup _interactTextCanvasGroup;
|
|
|
|
[Header("Tweens")]
|
|
[SerializeField]
|
|
private TweenSettings _tweenSettings = new()
|
|
{
|
|
duration = 0.2f,
|
|
ease = Ease.InOutSine,
|
|
useUnscaledTime = true
|
|
};
|
|
|
|
[SerializeField]
|
|
private GraphicRaycaster _graphicRaycaster;
|
|
public GraphicRaycaster Raycaster => _graphicRaycaster;
|
|
|
|
private CancellationTokenSource _cancellationTokenSource;
|
|
|
|
private Sequence _hudSequence;
|
|
private CancellationTokenSource _interactCancellationTokenSource;
|
|
|
|
private Sequence _interactErrorSequence;
|
|
private UIManager _uiManager;
|
|
|
|
public CursorTooltip CursorTooltip => _cursorTooltip;
|
|
public InventoryBar InventoryBar => _inventoryBar;
|
|
|
|
private void Awake()
|
|
{
|
|
if (_mainCanvasGroup != null)
|
|
{
|
|
_mainCanvasGroup.alpha = 1f;
|
|
_mainCanvasGroup.interactable = true;
|
|
_mainCanvasGroup.blocksRaycasts = true;
|
|
}
|
|
|
|
if (_interactTextCanvasGroup != null)
|
|
{
|
|
_interactTextCanvasGroup.alpha = 0f;
|
|
_interactTextCanvasGroup.blocksRaycasts = false;
|
|
_interactTextCanvasGroup.interactable = false;
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
StopTween();
|
|
|
|
StopInteractErrorTween();
|
|
}
|
|
|
|
[Inject]
|
|
public void Construct(UIManager uiManager)
|
|
{
|
|
_uiManager = uiManager;
|
|
}
|
|
|
|
// --------------------
|
|
// Visibility
|
|
// --------------------
|
|
|
|
public async UniTask DisplayInteractText(string interactText)
|
|
{
|
|
if (_interactTextCanvasGroup == null || _interactText == null)
|
|
return;
|
|
|
|
// Cancel any in-flight error display and restart from current alpha.
|
|
StopInteractErrorTween();
|
|
|
|
// Set text immediately.
|
|
var text = interactText ?? string.Empty;
|
|
|
|
_interactText.SetText(text);
|
|
|
|
_interactCancellationTokenSource = new CancellationTokenSource();
|
|
var token = _interactCancellationTokenSource.Token;
|
|
|
|
// Make sure it can show (but don't let it steal clicks).
|
|
_interactTextCanvasGroup.blocksRaycasts = false;
|
|
_interactTextCanvasGroup.interactable = false;
|
|
|
|
var fadeIn = new TweenSettings<float>
|
|
{
|
|
startValue = _interactTextCanvasGroup.alpha,
|
|
endValue = 1f,
|
|
settings = _tweenSettings
|
|
};
|
|
|
|
var fadeOut = new TweenSettings<float>
|
|
{
|
|
startValue = 1f,
|
|
endValue = 0f,
|
|
settings = _tweenSettings
|
|
};
|
|
|
|
try
|
|
{
|
|
// Fade in
|
|
_interactErrorSequence = Sequence.Create(useUnscaledTime: true)
|
|
.Group(Tween.Alpha(_interactTextCanvasGroup, fadeIn));
|
|
|
|
await _interactErrorSequence.ToUniTask(cancellationToken: token);
|
|
|
|
_interactTextCanvasGroup.alpha = 1f;
|
|
|
|
// Hold
|
|
if (DISPLAY_TIME > 0f)
|
|
await UniTask.Delay(TimeSpan.FromSeconds(DISPLAY_TIME), DelayType.UnscaledDeltaTime,
|
|
cancellationToken: token);
|
|
|
|
// Fade out
|
|
_interactErrorSequence = Sequence.Create(useUnscaledTime: true)
|
|
.Group(Tween.Alpha(_interactTextCanvasGroup, fadeOut));
|
|
|
|
await _interactErrorSequence.ToUniTask(cancellationToken: token);
|
|
|
|
_interactTextCanvasGroup.alpha = 0f;
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// If interrupted by a newer DisplayError call or destroy, just stop cleanly.
|
|
}
|
|
finally
|
|
{
|
|
if (_interactCancellationTokenSource != null)
|
|
{
|
|
_interactCancellationTokenSource.Dispose();
|
|
_interactCancellationTokenSource = null;
|
|
}
|
|
|
|
_interactErrorSequence = default;
|
|
}
|
|
}
|
|
|
|
public async UniTask Show()
|
|
{
|
|
if (_mainCanvasGroup == null)
|
|
return;
|
|
|
|
StopTween();
|
|
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
_mainCanvasGroup.blocksRaycasts = true;
|
|
_mainCanvasGroup.interactable = true;
|
|
|
|
var alphaTween = new TweenSettings<float>
|
|
{
|
|
startValue = _mainCanvasGroup.alpha,
|
|
endValue = 1f,
|
|
settings = _tweenSettings
|
|
};
|
|
|
|
_hudSequence = Sequence.Create(useUnscaledTime: true)
|
|
.Group(Tween.Alpha(_mainCanvasGroup, alphaTween));
|
|
|
|
try
|
|
{
|
|
await _hudSequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// interrupted by Hide / destroy — safe to ignore
|
|
}
|
|
|
|
_mainCanvasGroup.alpha = 1f;
|
|
}
|
|
public async UniTask Hide()
|
|
{
|
|
if (_mainCanvasGroup == null)
|
|
return;
|
|
|
|
StopTween();
|
|
|
|
_cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
_mainCanvasGroup.blocksRaycasts = false;
|
|
_mainCanvasGroup.interactable = false;
|
|
|
|
var alphaTween = new TweenSettings<float>
|
|
{
|
|
startValue = _mainCanvasGroup.alpha,
|
|
endValue = 0f,
|
|
settings = _tweenSettings
|
|
};
|
|
|
|
_hudSequence = Sequence.Create(useUnscaledTime: true)
|
|
.Group(Tween.Alpha(_mainCanvasGroup, alphaTween));
|
|
|
|
try
|
|
{
|
|
await _hudSequence.ToUniTask(cancellationToken: _cancellationTokenSource.Token);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// interrupted — safe
|
|
}
|
|
|
|
_mainCanvasGroup.alpha = 0f;
|
|
}
|
|
|
|
private void StopTween()
|
|
{
|
|
if (_hudSequence.isAlive)
|
|
_hudSequence.Stop();
|
|
|
|
_hudSequence = default;
|
|
|
|
if (_cancellationTokenSource != null)
|
|
{
|
|
_cancellationTokenSource.Cancel();
|
|
_cancellationTokenSource.Dispose();
|
|
_cancellationTokenSource = null;
|
|
}
|
|
}
|
|
|
|
private void StopInteractErrorTween()
|
|
{
|
|
if (_interactErrorSequence.isAlive)
|
|
_interactErrorSequence.Stop();
|
|
|
|
_interactErrorSequence = default;
|
|
|
|
if (_interactCancellationTokenSource != null)
|
|
{
|
|
try
|
|
{
|
|
_interactCancellationTokenSource.Cancel();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
|
|
_interactCancellationTokenSource.Dispose();
|
|
_interactCancellationTokenSource = null;
|
|
}
|
|
}
|
|
|
|
private void OnMapClicked()
|
|
{
|
|
// Placeholder for later:
|
|
// - open map window
|
|
// - toggle map overlay
|
|
}
|
|
}
|
|
} |