using NightclubArcadia.UI;
using UnityEngine;
namespace NightclubArcadia.Cinematics
{
public enum CameraState
{
Follow,
ManualPan,
PointOfInterest,
Reveal,
Dialogue,
Menu
}
///
/// Resolves which camera subsystem may write each frame.
///
public sealed class CameraStateDirector : MonoBehaviour
{
[SerializeField] CameraRigAnchor anchor;
[SerializeField] float dialogueRecenterTime = 0.5f;
int activeRevealCount;
float dialogueRecenterTimer;
bool wasDialogueActive;
bool wasMenuOpen;
public CameraState Current { get; private set; } = CameraState.Follow;
public bool AllowsManualPan =>
Current != CameraState.Dialogue
&& Current != CameraState.Menu
&& Current != CameraState.Reveal;
public bool AllowsPointOfInterest =>
Current == CameraState.Follow || Current == CameraState.PointOfInterest;
void Awake()
{
if (anchor == null)
{
anchor = GetComponent();
}
}
void Start()
{
if (UIStateController.Instance != null)
{
UIStateController.Instance.StateChanged += OnUiStateChanged;
}
ResolveState(false);
}
void OnDestroy()
{
if (UIStateController.Instance != null)
{
UIStateController.Instance.StateChanged -= OnUiStateChanged;
}
}
void Update()
{
ResolveState(true);
if (Current == CameraState.Dialogue && anchor != null)
{
dialogueRecenterTimer += Time.deltaTime;
var t = Mathf.Clamp01(dialogueRecenterTimer / dialogueRecenterTime);
anchor.ManualPanOffset = Vector3.Lerp(anchor.ManualPanOffset, Vector3.zero, t);
}
}
void OnUiStateChanged() => ResolveState(true);
public void RegisterReveal() => activeRevealCount++;
public void UnregisterReveal() => activeRevealCount = Mathf.Max(0, activeRevealCount - 1);
void ResolveState(bool allowManualPanPromotion)
{
var ui = UIStateController.Instance;
var menuOpen = ui != null && ui.IsMenuOpen;
var dialogueActive = ui != null && ui.IsDialogueActive;
if (menuOpen)
{
Current = CameraState.Menu;
}
else if (dialogueActive)
{
if (!wasDialogueActive)
{
dialogueRecenterTimer = 0f;
}
Current = CameraState.Dialogue;
}
else if (activeRevealCount > 0)
{
Current = CameraState.Reveal;
}
else if (allowManualPanPromotion && IsManualPanActive())
{
Current = CameraState.ManualPan;
}
else if (HasActivePointOfInterest())
{
Current = CameraState.PointOfInterest;
}
else
{
Current = CameraState.Follow;
}
wasDialogueActive = dialogueActive;
wasMenuOpen = menuOpen;
}
bool IsManualPanActive()
{
var pan = GetComponent();
return pan != null && pan.IsManualPanActive;
}
bool HasActivePointOfInterest()
{
var director = GetComponent();
return director != null && director.HasActivePoi;
}
}
}