Теперь камера - это стейт-машина

This commit is contained in:
ThomasCharester authored and Loša Ceviel committed 2025-10-28 22:11:46 +03:00
1 parent db541fed8a
commit 4549617275
31 files changed
+1145 -210

No files matched your search

@@ -0,0 +1,153 @@
using System;
using Code.Input;
using Code.StateMachine;
using UnityEngine;
namespace Code.Gameplay.Camera.CameraStates
{
public class FirstPersonState : BaseState<CameraStateMachineContext>
{
// Параметры загружаются из CameraConfig
private float
_defaultDistance,
_minDistance,
_maxDistance,
_distanceMovementSpeed,
_rotationSpeed,
_rotationSharpness,
_followSharpness,
_minVerticalAngle,
_maxVerticalAngle,
_defaultVerticalAngle;
// Трансформ объекта, за которым следует камера (для 1st-person: уровень глаз)
private Transform _followTransform;
// Позиция следования: текущая сглаженная позиция и горизонтальное направление камеры
private Vector3 _currentFollowPosition;
// Fallback-позиция для режимов без цели (например, MainMenu)
private Vector3 _defaultFollowPosition;
// Целевой вертикальный угол камеры (наклон вверх/вниз)
private float _targetVerticalAngle;
// Текущая и целевая дистанция камеры от цели
private float _currentDistance, _targetDistance;
// Исходные значения дистанции для восстановления после FirstPerson режима
private float _originalDefaultDistance, _originalMinDistance, _originalMaxDistance;
// Горизонтальное направление камеры (проекция forward на плоскость)
public Vector3 PlanarDirection { get; private set; }
private IInputService _inputService;
private UnityEngine.Camera _camera;
public FirstPersonState(CameraStateMachineContext context) : base(context)
{
_inputService = context.InputService;
// Загрузка значений из конфига
_defaultDistance = context.Config.defaultDistance;
_minDistance = context.Config.minDistance;
_maxDistance = context.Config.maxDistance;
_distanceMovementSpeed = context.Config.distanceMovementSpeed;
_rotationSpeed = context.Config.rotationSpeed;
_rotationSharpness = context.Config.rotationSharpness;
_followSharpness = context.Config.followSharpness;
_minVerticalAngle = context.Config.minVerticalAngle;
_maxVerticalAngle = context.Config.maxVerticalAngle;
_defaultVerticalAngle = context.Config.defaultVerticalAngle;
_defaultFollowPosition = context.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()
{
// В FirstPerson режиме дистанция всегда равна 0
_minDistance = 0f;
_maxDistance = 0f;
_defaultDistance = 0f;
_targetDistance = 0f;
_currentDistance = 0f;
_camera = Context.Camera;
}
public override void LateTick()
{
UpdateWithInput(Time.deltaTime,_inputService.ZoomInput, _inputService.LookInput);
}
// Обработка вращения камеры на основе пользовательского ввода
private void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion targetRotation)
{
// Вращение вокруг вертикальной оси (горизонтальный поворот)
var rotationFromInput = Quaternion.Euler(_followTransform.up * (rotationInput.x * _rotationSpeed));
PlanarDirection = rotationFromInput * PlanarDirection;
var planarRotation = Quaternion.LookRotation(PlanarDirection, _followTransform.up);
// Вращение вокруг горизонтальной оси (вертикальный наклон)
_targetVerticalAngle -= rotationInput.y * _rotationSpeed;
_targetVerticalAngle = Math.Clamp(_targetVerticalAngle, _minVerticalAngle, _maxVerticalAngle);
var verticalRotation = Quaternion.Euler(_targetVerticalAngle, 0, 0);
// Интерполяция к целевому вращению для плавности
targetRotation = Quaternion.Slerp(_camera.transform.rotation, planarRotation * verticalRotation, deltaTime * _rotationSharpness);
Debug.Log(_camera.transform.rotation.eulerAngles);
// Применение финального вращения
_camera.transform.rotation = targetRotation;
Debug.Log(_camera.transform.rotation.eulerAngles);
}
// Обработка позиционирования камеры и зума с учетом текущего режима
private void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
{
// Плавное следование за целью с использованием экспоненциального сглаживания
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, _followTransform.position, 1f - Mathf.Exp(-_followSharpness * deltaTime));
// Вычисление целевой позиции камеры с учетом текущего режима
Vector3 targetPosition;
// В FirstPerson режиме камера находится прямо на позиции цели
targetPosition = _currentFollowPosition;
// Установка финальной позиции камеры
_camera.transform.position = targetPosition;
}
// Основной метод обновления камеры, вызываемый извне каждый кадр
public void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
{
// Проверка наличия цели для следования и проверка на режим главного меню
if (!_followTransform) return;
// Обработка ввода и позиционирования
HandleRotationInput(deltaTime, rotationInput, out var targetRotation);
HandlePosition(deltaTime, zoomInput, targetRotation);
}
// Установка цели для следования камеры
public void SetFollowTransform(Transform t)
{
_followTransform = t;
_currentFollowPosition = t.position;
PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8bd4b9c56b1e435d8699160bc950994c
timeCreated: 1761672032
@@ -0,0 +1,23 @@
using Code.StateMachine;
using UnityEngine;
namespace Code.Gameplay.Camera.CameraStates
{
public class StaticState : BaseState<CameraStateMachineContext>
{
private Transform _target;
private Transform _position;
private UnityEngine.Camera _camera;
public StaticState(CameraStateMachineContext context) : base(context)
{
}
public override void EnterState()
{
_camera = Context.Camera;
base.EnterState();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ddbcc6a073b744a08ce31c0607c1e9e9
timeCreated: 1761671944
@@ -0,0 +1,164 @@
using System;
using Code.Input;
using Code.StateMachine;
using UnityEngine;
namespace Code.Gameplay.Camera.CameraStates
{
public class ThirdPersonState : BaseState<CameraStateMachineContext>
{
// Параметры загружаются из CameraConfig
private float
_defaultDistance,
_minDistance,
_maxDistance,
_distanceMovementSpeed,
_rotationSpeed,
_rotationSharpness,
_followSharpness,
_minVerticalAngle,
_maxVerticalAngle,
_defaultVerticalAngle;
// Трансформ объекта, за которым следует камера (для 1st-person: уровень глаз)
private Transform _followTransform;
// Позиция следования: текущая сглаженная позиция и горизонтальное направление камеры
private Vector3 _currentFollowPosition;
// Fallback-позиция для режимов без цели (например, MainMenu)
private Vector3 _defaultFollowPosition;
// Целевой вертикальный угол камеры (наклон вверх/вниз)
private float _targetVerticalAngle;
// Текущая и целевая дистанция камеры от цели
private float _currentDistance, _targetDistance;
// Исходные значения дистанции для восстановления после FirstPerson режима
private float _originalDefaultDistance, _originalMinDistance, _originalMaxDistance;
// Горизонтальное направление камеры (проекция forward на плоскость)
public Vector3 PlanarDirection { get; private set; }
private IInputService _inputService;
private UnityEngine.Camera _camera;
public ThirdPersonState(CameraStateMachineContext context) : base(context)
{
_inputService = context.InputService;
// Загрузка значений из конфига
_defaultDistance = context.Config.defaultDistance;
_minDistance = context.Config.minDistance;
_maxDistance = context.Config.maxDistance;
_distanceMovementSpeed = context.Config.distanceMovementSpeed;
_rotationSpeed = context.Config.rotationSpeed;
_rotationSharpness = context.Config.rotationSharpness;
_followSharpness = context.Config.followSharpness;
_minVerticalAngle = context.Config.minVerticalAngle;
_maxVerticalAngle = context.Config.maxVerticalAngle;
_defaultVerticalAngle = context.Config.defaultVerticalAngle;
_defaultFollowPosition = context.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()
{
// Восстанавливаем исходные значения дистанции
_minDistance = _originalMinDistance;
_maxDistance = _originalMaxDistance;
_defaultDistance = _originalDefaultDistance;
_targetDistance = _defaultDistance;
_camera = Context.Camera;
}
public override void LateTick()
{
UpdateWithInput(Time.deltaTime, _inputService.ZoomInput, _inputService.LookInput);
}
// Основной метод обновления камеры, вызываемый извне каждый кадр
public void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
{
// Проверка наличия цели для следования и проверка на режим главного меню
if (!_followTransform) return;
// Обработка ввода и позиционирования
HandleRotationInput(deltaTime, rotationInput, out var targetRotation);
HandlePosition(deltaTime, zoomInput, targetRotation);
}
// Обработка вращения камеры на основе пользовательского ввода
private void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion targetRotation)
{
// Вращение вокруг вертикальной оси (горизонтальный поворот)
var rotationFromInput = Quaternion.Euler(_followTransform.up * (rotationInput.x * _rotationSpeed));
PlanarDirection = rotationFromInput * PlanarDirection;
var planarRotation = Quaternion.LookRotation(PlanarDirection, _followTransform.up);
// Вращение вокруг горизонтальной оси (вертикальный наклон)
_targetVerticalAngle -= rotationInput.y * _rotationSpeed;
_targetVerticalAngle = Math.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 HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
{
// Обновление целевой дистанции на основе ввода зума
_targetDistance += zoomInput * _distanceMovementSpeed;
_targetDistance = Mathf.Clamp(_targetDistance, _minDistance, _maxDistance);
// Плавное следование за целью с использованием экспоненциального сглаживания
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, _followTransform.position,
1f - Mathf.Exp(-_followSharpness * deltaTime));
// Вычисление целевой позиции камеры с учетом текущего режима
Vector3 targetPosition;
// В ThirdPerson режиме камера отодвинута на расстояние от цели
targetPosition = _currentFollowPosition - targetRotation * Vector3.forward * _currentDistance;
// Плавное изменение текущей дистанции к целевой (только для ThirdPerson)
_currentDistance = Mathf.Lerp(_currentDistance, _targetDistance,
1f - Mathf.Exp(-_distanceMovementSpeed * deltaTime));
// Установка финальной позиции камеры
_camera.transform.position = targetPosition;
}
// Установка цели для следования камеры
public void SetFollowTransform(Transform t)
{
_followTransform = t;
_currentFollowPosition = t.position;
PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ec6778ceb9854ff8af7cba4f6285c370
timeCreated: 1761672071