using UnityEngine; namespace Vanguard.Battle { /// /// Единственный владелец кинематографичного движения камеры. /// Снимок исходного pose берётся один раз на цепочку и /// восстанавливается идемпотентно. /// public sealed class CameraDirector { private struct Pose { public Vector3 Position; public Quaternion Rotation; public float FieldOfView; } private readonly Camera _camera; private Pose _origin; private Pose _from; private Pose _to; private float _duration; private float _elapsed; private bool _moving; private bool _hasOrigin; public CameraDirector(Camera camera) { _camera = camera; } public bool IsActive => _hasOrigin && _camera != null; public bool IsMoving => _moving; public void BeginChain() { if (_camera == null || _hasOrigin) return; _origin = Capture(); _hasOrigin = true; } public void ZoomTo( Vector3 target, float duration, float fieldOfView = 34f) { if (_camera == null) return; BeginChain(); var current = Capture(); var targetPosition = target + (Vector3.back * 3.4f) + (Vector3.up * 2.6f); var targetRotation = Quaternion.LookRotation( target - targetPosition, Vector3.up); AnimateTo( new Pose { Position = targetPosition, Rotation = targetRotation, FieldOfView = fieldOfView, }, duration); } public void ReturnToOrigin(float duration) { if (!_hasOrigin) return; AnimateTo(_origin, duration); } public void Restore() { if (_camera == null || !_hasOrigin) return; _moving = false; Apply(_origin); _hasOrigin = false; } public void Tick(float deltaTime) { if (!_moving || _camera == null) return; _elapsed += deltaTime; var t = Mathf.Clamp01(_elapsed / Mathf.Max(0.01f, _duration)); var eased = t * t * (3f - (2f * t)); Apply(new Pose { Position = Vector3.Lerp(_from.Position, _to.Position, eased), Rotation = Quaternion.Slerp( _from.Rotation, _to.Rotation, eased), FieldOfView = Mathf.Lerp( _from.FieldOfView, _to.FieldOfView, eased), }); if (t >= 1f) _moving = false; } private void AnimateTo(Pose target, float duration) { if (_camera == null) return; _from = Capture(); _to = target; _duration = Mathf.Max(0.01f, duration); _elapsed = 0f; _moving = true; } private Pose Capture() => new Pose { Position = _camera.transform.position, Rotation = _camera.transform.rotation, FieldOfView = _camera.fieldOfView, }; private void Apply(Pose pose) { if (_camera == null) return; _camera.transform.position = pose.Position; _camera.transform.rotation = pose.Rotation; _camera.fieldOfView = pose.FieldOfView; } } }