Files
nightclub-arcadia/NightclubArcadia/Assets/Scripts/Camera/CameraFramingVolume.cs
T
lennartandClaude Opus 5 932cd0582f add camera rig, click-to-move locomotion, and click interaction
Camera: Cinemachine-based rig with an anchor, a state director, point-of-
interest framing, pan input, and dialogue framing volumes.

Player: click-to-move over the NavMesh, a pointer input layer, and a motion
arbiter that reconciles direct stick input with navigation-driven movement.
The pure math is isolated in NightclubArcadia.Locomotion.Math with an EditMode
suite, so the arbitration rules are testable without a scene.

Interaction: IClickInteractable plus a bridge that routes pointer clicks to it.

Supporting project settings: adds the Cinemachine package, the Interactable and
Ground tags the raycasts depend on, and NavMesh agent dimensions matched to the
player capsule (radius 0.3, height 1.8, climb 0.25).

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 19:03:18 +02:00

82 lines
2.0 KiB
C#

using Unity.Cinemachine;
using UnityEngine;
namespace NightclubArcadia.Cinematics
{
/// <summary>
/// Raises a reveal camera priority while the player is inside the volume.
/// </summary>
[RequireComponent(typeof(BoxCollider))]
public sealed class CameraFramingVolume : MonoBehaviour
{
[SerializeField] CinemachineCamera revealCamera;
[SerializeField] int activePriority = 20;
[SerializeField] float minDwell = 0.5f;
CameraStateDirector stateDirector;
int defaultPriority;
int occupants;
float exitTimer;
void Awake()
{
var box = GetComponent<BoxCollider>();
box.isTrigger = true;
if (revealCamera != null)
{
defaultPriority = revealCamera.Priority.Value;
}
stateDirector = FindFirstObjectByType<CameraStateDirector>();
}
void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Player") || revealCamera == null)
{
return;
}
occupants++;
exitTimer = 0f;
revealCamera.Priority.Value = activePriority;
stateDirector?.RegisterReveal();
}
void OnTriggerExit(Collider other)
{
if (!other.CompareTag("Player") || revealCamera == null)
{
return;
}
occupants = Mathf.Max(0, occupants - 1);
if (occupants == 0)
{
exitTimer = minDwell;
}
}
void Update()
{
if (occupants > 0 || revealCamera == null)
{
return;
}
if (exitTimer > 0f)
{
exitTimer -= Time.deltaTime;
return;
}
if (revealCamera.Priority.Value != defaultPriority)
{
revealCamera.Priority.Value = defaultPriority;
stateDirector?.UnregisterReveal();
}
}
}
}