152 lines
7.5 KiB
C#
152 lines
7.5 KiB
C#
using Code.Configs;
|
|
using Code.Input;
|
|
using Code.StateMachine;
|
|
using UnityEngine;
|
|
|
|
namespace Code.Gameplay.Camera.CameraStates
|
|
{
|
|
public abstract class BaseCameraState : BaseState<CameraStateMachineContext>
|
|
{
|
|
// DI сервиса ввода
|
|
private readonly IInputService _inputService;
|
|
|
|
// Конфиг камеры
|
|
private readonly CameraConfig _config;
|
|
|
|
// Используемая камера
|
|
protected UnityEngine.Camera Camera { get; private set; }
|
|
|
|
// Трансформ объекта, за которым следует камера
|
|
protected Transform FollowTransform;
|
|
|
|
// Позиция следования: текущая сглаженная позиция и горизонтальное направление камеры
|
|
protected Vector3 CurrentFollowPosition;
|
|
|
|
// Fallback-позиция для режимов без цели
|
|
private Vector3 _defaultFollowPosition;
|
|
|
|
// Целевой вертикальный угол камеры (наклон вверх/вниз)
|
|
private float _targetVerticalAngle;
|
|
|
|
// Текущая и целевая дистанция камеры от цели
|
|
protected float CurrentDistance, TargetDistance;
|
|
|
|
// Исходные значения дистанции для восстановления
|
|
protected float OriginalDefaultDistance, OriginalMinDistance, OriginalMaxDistance;
|
|
|
|
// Горизонтальное направление камеры (проекция forward на плоскость)
|
|
private Vector3 PlanarDirection { get; set; }
|
|
|
|
// Параметры загружаются из CameraConfig
|
|
protected float
|
|
DefaultDistance,
|
|
MinDistance,
|
|
MaxDistance,
|
|
DistanceMovementSpeed,
|
|
RotationSpeed,
|
|
RotationSharpness,
|
|
FollowSharpness,
|
|
MinVerticalAngle,
|
|
MaxVerticalAngle,
|
|
DefaultVerticalAngle;
|
|
|
|
// Свойства для доступа к важным данным камеры извне
|
|
public Vector3 GetPlanarDirection() => PlanarDirection; // Горизонтальное направление камеры
|
|
public Quaternion GetCameraRotation() => Camera.transform.rotation; // Текущее вращение камеры
|
|
|
|
// Конструктор базового состояния
|
|
protected BaseCameraState(CameraStateMachineContext context) : base(context)
|
|
{
|
|
_inputService = context.InputService;
|
|
_config = context.Config;
|
|
LoadConfig();
|
|
}
|
|
|
|
// Загрузка конфига для камеры
|
|
private void LoadConfig()
|
|
{
|
|
// Загрузка значений из конфигов
|
|
DefaultDistance = _config.defaultDistance;
|
|
MinDistance = _config.minDistance;
|
|
MaxDistance = _config.maxDistance;
|
|
DistanceMovementSpeed = _config.distanceMovementSpeed;
|
|
RotationSpeed = _config.rotationSpeed;
|
|
RotationSharpness = _config.rotationSharpness;
|
|
FollowSharpness = _config.followSharpness;
|
|
MinVerticalAngle = _config.minVerticalAngle;
|
|
MaxVerticalAngle = _config.maxVerticalAngle;
|
|
DefaultVerticalAngle = _config.defaultVerticalAngle;
|
|
_defaultFollowPosition = _config.defaultFollowPosition;
|
|
|
|
// Обеспечиваем корректные значения дистанции и угла
|
|
DefaultDistance = Mathf.Clamp(DefaultDistance, MinDistance, MaxDistance);
|
|
DefaultVerticalAngle = Mathf.Clamp(DefaultVerticalAngle, MinVerticalAngle, MaxVerticalAngle);
|
|
|
|
// Сохраняем оригинальные значения для восстановления
|
|
OriginalDefaultDistance = DefaultDistance;
|
|
OriginalMinDistance = MinDistance;
|
|
OriginalMaxDistance = MaxDistance;
|
|
|
|
CurrentDistance = DefaultDistance;
|
|
TargetDistance = CurrentDistance;
|
|
_targetVerticalAngle = DefaultVerticalAngle;
|
|
PlanarDirection = Vector3.forward; // Начальное направление - вперед по оси Z
|
|
CurrentFollowPosition = _defaultFollowPosition;
|
|
}
|
|
|
|
// Переход в состояние
|
|
public override void EnterState()
|
|
{
|
|
Camera = Context.Camera;
|
|
}
|
|
|
|
public override void LateTick()
|
|
{
|
|
// Обновляем камеру только если есть цель для следования
|
|
if (FollowTransform)
|
|
{
|
|
UpdateWithInput(Time.deltaTime, _inputService.ZoomInput, _inputService.LookInput);
|
|
}
|
|
}
|
|
|
|
// Абстрактные методы для специфики режима
|
|
protected abstract void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation);
|
|
|
|
// Обработка вращения камеры на основе пользовательского ввода
|
|
// Теперь виртуальный, чтобы статический режим мог работать как хочет
|
|
protected virtual void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion targetRotation)
|
|
{
|
|
// Вращение вокруг вертикальной оси (горизонтальный поворот)
|
|
var rotationFromInput = Quaternion.Euler(Vector3.up * (rotationInput.x * RotationSpeed));
|
|
PlanarDirection = rotationFromInput * PlanarDirection;
|
|
var planarRotation = Quaternion.LookRotation(PlanarDirection, FollowTransform.up);
|
|
|
|
// Вращение вокруг горизонтальной оси (вертикальный наклон)
|
|
_targetVerticalAngle -= rotationInput.y * RotationSpeed;
|
|
_targetVerticalAngle = Mathf.Clamp(_targetVerticalAngle, MinVerticalAngle, MaxVerticalAngle);
|
|
var verticalRotation = Quaternion.Euler(_targetVerticalAngle, 0, 0);
|
|
|
|
// Интерполяция к целевому вращению для плавности
|
|
targetRotation = Quaternion.Slerp(Camera.transform.rotation, planarRotation * verticalRotation, deltaTime * RotationSharpness);
|
|
|
|
// Применение финального вращения
|
|
Camera.transform.rotation = targetRotation;
|
|
}
|
|
|
|
// Основной метод обновления камеры, вызываемый извне каждый кадр
|
|
private void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
|
|
{
|
|
// Обработка ввода и позиционирования
|
|
HandleRotationInput(deltaTime, rotationInput, out var targetRotation);
|
|
HandlePosition(deltaTime, zoomInput, targetRotation);
|
|
}
|
|
|
|
// Установка цели для следования камеры
|
|
public void SetFollowTransform(Transform t)
|
|
{
|
|
FollowTransform = t;
|
|
CurrentFollowPosition = t ? t.position : _defaultFollowPosition;
|
|
if (t) PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
|
|
}
|
|
}
|
|
} |