using System.Collections.Generic;
using UnityEngine;
namespace NightclubArcadia.Cinematics
{
///
/// Scores registered POIs and writes bias onto the camera anchor.
///
public sealed class CameraPointOfInterestDirector : MonoBehaviour
{
static readonly List Registered = new List();
[SerializeField] CameraRigAnchor anchor;
[SerializeField] CameraStateDirector stateDirector;
[SerializeField] float poiSmoothTime = 1f;
[SerializeField] float poiReleaseTime = 1.4f;
[SerializeField] float maxHeadingAngle = 100f;
Vector3 poiVelocity;
float distanceVelocity;
CameraPointOfInterest activePoi;
public bool HasActivePoi => activePoi != null;
public static void Register(CameraPointOfInterest poi)
{
if (poi != null && !Registered.Contains(poi))
{
Registered.Add(poi);
}
}
public static void Unregister(CameraPointOfInterest poi)
{
Registered.Remove(poi);
}
void Awake()
{
if (anchor == null)
{
anchor = GetComponent();
}
if (stateDirector == null)
{
stateDirector = GetComponent();
}
}
void LateUpdate()
{
if (anchor == null || stateDirector == null)
{
return;
}
var follow = anchor.FollowTarget;
if (follow == null)
{
return;
}
if (!stateDirector.AllowsPointOfInterest)
{
return;
}
if (stateDirector.Current == CameraState.ManualPan)
{
return;
}
activePoi = FindBestPoi(follow);
if (activePoi == null)
{
ReleasePoi();
return;
}
var toPoi = activePoi.Target.position - follow.position;
toPoi.y = 0f;
var targetBias = Vector3.ClampMagnitude(toPoi, activePoi.MaxBias);
anchor.PoiBias = Vector3.SmoothDamp(
anchor.PoiBias,
targetBias,
ref poiVelocity,
poiSmoothTime);
anchor.DistanceBias = Mathf.SmoothDamp(
anchor.DistanceBias,
activePoi.ExtraDistance,
ref distanceVelocity,
poiSmoothTime);
}
CameraPointOfInterest FindBestPoi(Transform follow)
{
CameraPointOfInterest best = null;
var bestScore = 0f;
var forward = follow.forward;
foreach (var poi in Registered)
{
if (poi == null || !poi.isActiveAndEnabled)
{
continue;
}
var offset = poi.Target.position - follow.position;
offset.y = 0f;
var distance = offset.magnitude;
if (distance > poi.TriggerRadius || distance <= 0.01f)
{
continue;
}
var angle = Vector3.Angle(forward, offset);
if (angle > maxHeadingAngle)
{
continue;
}
var score = poi.Weight * (1f - distance / poi.TriggerRadius);
if (score > bestScore)
{
bestScore = score;
best = poi;
}
}
return best;
}
void ReleasePoi()
{
if (anchor == null)
{
return;
}
anchor.PoiBias = Vector3.SmoothDamp(
anchor.PoiBias,
Vector3.zero,
ref poiVelocity,
poiReleaseTime);
anchor.DistanceBias = Mathf.SmoothDamp(
anchor.DistanceBias,
0f,
ref distanceVelocity,
poiReleaseTime);
if (anchor.PoiBias.sqrMagnitude < 0.0001f && Mathf.Abs(anchor.DistanceBias) < 0.01f)
{
activePoi = null;
}
}
}
}