Соединение всё со всем что имеется, дописывание стейт-машины
Теперь мне удобно кастить и получать тип камеры, всё вроде работает нормисно
This commit is contained in:
1 parent
4549617275
commit
665114b7dc
28 files changed
+292
-598
No files matched your search
@@ -1,16 +1,13 @@
|
|||||||
using Code.App.StateMachine;
|
using Code.App.StateMachine;
|
||||||
using Code.Gameplay.Camera;
|
using Code.Gameplay.Camera;
|
||||||
using Code.Gameplay.Player;
|
|
||||||
using Code.Input;
|
using Code.Input;
|
||||||
using Code.Scenes;
|
using Code.Scenes;
|
||||||
using Code.StateMachine;
|
using Code.StateMachine;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Code.App.AppStates
|
namespace Code.App.AppStates
|
||||||
{
|
{
|
||||||
public class GameplayState : BaseState<AppStateMachineContext>
|
public class GameplayState : BaseState<AppStateMachineContext>
|
||||||
{
|
{
|
||||||
private PlayerHealth _playerHealthPoints;
|
|
||||||
|
|
||||||
public GameplayState(AppStateMachineContext context) : base(context)
|
public GameplayState(AppStateMachineContext context) : base(context)
|
||||||
{
|
{
|
||||||
@@ -21,9 +18,6 @@ namespace Code.App.AppStates
|
|||||||
Context.SceneLoaderService.LoadScene((int)SceneIds.MovementDev, SceneLoaded);
|
Context.SceneLoaderService.LoadScene((int)SceneIds.MovementDev, SceneLoaded);
|
||||||
Context.InputService.EnableMap(ActionMappings.Gameplay);
|
Context.InputService.EnableMap(ActionMappings.Gameplay);
|
||||||
|
|
||||||
Context.UIService.LoadingScreen.Show();
|
|
||||||
Context.UIService.SwitchPanelTo(UIPanel.Gameplay);
|
|
||||||
|
|
||||||
Context.CameraStateMachine.SwitchState(CameraMode.FirstPerson);
|
Context.CameraStateMachine.SwitchState(CameraMode.FirstPerson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,17 +16,11 @@ namespace Code.App.AppStates
|
|||||||
Context.SceneLoaderService.LoadScene((int)SceneIds.MainMenu, SceneLoaded);
|
Context.SceneLoaderService.LoadScene((int)SceneIds.MainMenu, SceneLoaded);
|
||||||
Context.InputService.EnableMap(ActionMappings.MainMenu);
|
Context.InputService.EnableMap(ActionMappings.MainMenu);
|
||||||
|
|
||||||
Context.UIService.LoadingScreen.Show();
|
|
||||||
Context.UIService.SwitchPanelTo(UIPanel.MainMenu);
|
|
||||||
((MainMenuPanel)Context.UIService.CurrentPanel).startButton.onClick.AddListener(StartGame);
|
|
||||||
((MainMenuPanel)Context.UIService.CurrentPanel).exitButton.onClick.AddListener(ExitGame);
|
|
||||||
|
|
||||||
Context.CameraStateMachine.SwitchState(CameraMode.Static);
|
Context.CameraStateMachine.SwitchState(CameraMode.Static);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SceneLoaded()
|
private void SceneLoaded()
|
||||||
{
|
{
|
||||||
Context.UIService.LoadingScreen.Hide();
|
|
||||||
|
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Code.App.StateMachine;
|
using Code.App.StateMachine;
|
||||||
|
using Code.Gameplay.Camera;
|
||||||
using Code.Input;
|
using Code.Input;
|
||||||
using Code.Scenes;
|
using Code.Scenes;
|
||||||
using Code.StateMachine;
|
using Code.StateMachine;
|
||||||
@@ -16,6 +17,8 @@ namespace Code.App.AppStates
|
|||||||
{
|
{
|
||||||
Context.SceneLoaderService.LoadScene((int)SceneIds.MovementDev, SceneLoaded);
|
Context.SceneLoaderService.LoadScene((int)SceneIds.MovementDev, SceneLoaded);
|
||||||
Context.InputService.EnableMap(ActionMappings.Gameplay);
|
Context.InputService.EnableMap(ActionMappings.Gameplay);
|
||||||
|
|
||||||
|
Context.CameraStateMachine.SwitchState(CameraMode.FirstPerson);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SceneLoaded()
|
private void SceneLoaded()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Code.App.StateMachine;
|
using Code.App.StateMachine;
|
||||||
using Code.Configs;
|
using Code.Configs;
|
||||||
using Code.Gameplay.Camera;
|
using Code.Gameplay.Camera;
|
||||||
using Code.Gameplay.Character.Camera;
|
|
||||||
using Code.Input;
|
using Code.Input;
|
||||||
using Code.Scenes;
|
using Code.Scenes;
|
||||||
using Code.StaticData;
|
using Code.StaticData;
|
||||||
@@ -22,7 +21,6 @@ namespace Code.App
|
|||||||
InstallInfrastructureUnit(containerBuilder, staticDataService);
|
InstallInfrastructureUnit(containerBuilder, staticDataService);
|
||||||
|
|
||||||
containerBuilder.AddSingleton(typeof(InputService), typeof(IInputService));
|
containerBuilder.AddSingleton(typeof(InputService), typeof(IInputService));
|
||||||
containerBuilder.AddSingleton(typeof(UIService), typeof(IUIService));
|
|
||||||
|
|
||||||
InitializeCamera(containerBuilder, staticDataService);
|
InitializeCamera(containerBuilder, staticDataService);
|
||||||
|
|
||||||
@@ -37,7 +35,7 @@ namespace Code.App
|
|||||||
// containerBuilder.AddSingleton(cameraService);
|
// containerBuilder.AddSingleton(cameraService);
|
||||||
// DontDestroyOnLoad(cameraService);
|
// DontDestroyOnLoad(cameraService);
|
||||||
|
|
||||||
Camera camera = Instantiate(staticDataService.CameraConfig.cameraPrefab2);
|
Camera camera = Instantiate(staticDataService.CameraConfig.cameraPrefab);
|
||||||
DontDestroyOnLoad(camera);
|
DontDestroyOnLoad(camera);
|
||||||
containerBuilder.AddSingleton(camera);
|
containerBuilder.AddSingleton(camera);
|
||||||
}
|
}
|
||||||
@@ -61,9 +59,7 @@ namespace Code.App
|
|||||||
|
|
||||||
containerBuilder.AddSingleton(staticDataService, typeof(IStaticDataService));
|
containerBuilder.AddSingleton(staticDataService, typeof(IStaticDataService));
|
||||||
containerBuilder.AddSingleton(staticDataService.InputConfig.inputActionAsset, typeof(InputActionAsset));
|
containerBuilder.AddSingleton(staticDataService.InputConfig.inputActionAsset, typeof(InputActionAsset));
|
||||||
containerBuilder.AddSingleton(staticDataService.UIConfig.canvasPrefab, typeof(Canvas));
|
|
||||||
containerBuilder.AddSingleton(staticDataService.CameraConfig, typeof(CameraConfig));
|
containerBuilder.AddSingleton(staticDataService.CameraConfig, typeof(CameraConfig));
|
||||||
containerBuilder.AddSingleton(staticDataService.UIConfig.uiElementsPrefabs, typeof(UIElement[]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Bootstrap(Container container)
|
private void Bootstrap(Container container)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ namespace Code.App.StateMachine
|
|||||||
{
|
{
|
||||||
[Inject] public ISceneLoaderService SceneLoaderService;
|
[Inject] public ISceneLoaderService SceneLoaderService;
|
||||||
[Inject] public IInputService InputService;
|
[Inject] public IInputService InputService;
|
||||||
[Inject] public IUIService UIService;
|
|
||||||
[Inject] public AppStateMachine StateMachine;
|
[Inject] public AppStateMachine StateMachine;
|
||||||
[Inject] public CameraStateMachine CameraStateMachine;
|
[Inject] public CameraStateMachine CameraStateMachine;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
using Code.Gameplay.Camera;
|
|
||||||
using Code.Gameplay.Character.Camera;
|
|
||||||
using Code.Gameplay.Character.Core;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Code.Configs
|
namespace Code.Configs
|
||||||
{
|
{
|
||||||
[CreateAssetMenu(fileName = "CharacterCameraConfig", menuName = "Config/CharacterCameraConfig")]
|
[CreateAssetMenu(fileName = "CameraConfig", menuName = "Config/CameraConfig")]
|
||||||
public class CameraConfig : ScriptableObject
|
public class CameraConfig : ScriptableObject
|
||||||
{
|
{
|
||||||
public float
|
public float
|
||||||
@@ -31,13 +28,10 @@ namespace Code.Configs
|
|||||||
maxVerticalAngle = 70f, // Максимальный угол наклона камеры (вверх)
|
maxVerticalAngle = 70f, // Максимальный угол наклона камеры (вверх)
|
||||||
defaultVerticalAngle = 10f; // Стандартный угол наклона камеры
|
defaultVerticalAngle = 10f; // Стандартный угол наклона камеры
|
||||||
|
|
||||||
// Текущий режим камеры
|
// Позиция следования по умолчанию
|
||||||
public CameraMode defaultCameraMode = CameraMode.Bogdan;
|
|
||||||
|
|
||||||
// Позиция следования по умолчанию (для меню)
|
|
||||||
public Vector3 defaultFollowPosition = Vector3.zero;
|
public Vector3 defaultFollowPosition = Vector3.zero;
|
||||||
|
|
||||||
public CameraService cameraPrefab;
|
// Префаб камеры
|
||||||
public Camera cameraPrefab2;
|
public Camera cameraPrefab;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
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 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 = 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; // Начальное направление совпадает с направлением цели
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 92ff312b40a647b392af24877e699bd5
|
||||||
|
timeCreated: 1761685916
|
||||||
@@ -1,153 +1,43 @@
|
|||||||
using System;
|
|
||||||
using Code.Input;
|
|
||||||
using Code.StateMachine;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Code.Gameplay.Camera.CameraStates
|
namespace Code.Gameplay.Camera.CameraStates
|
||||||
{
|
{
|
||||||
public class FirstPersonState : BaseState<CameraStateMachineContext>
|
/*
|
||||||
|
* Состояние камеры от первого лица
|
||||||
|
* Камера размещается непосредственно на позиции цели (например, на уровне глаз персонажа)
|
||||||
|
* Дистанция до цели принудительно устанавливается в 0
|
||||||
|
* Вращение управляется мышью, позиция следует за целью без отступа
|
||||||
|
*/
|
||||||
|
public class FirstPersonState : BaseCameraState, ICameraState
|
||||||
{
|
{
|
||||||
// Параметры загружаются из CameraConfig
|
public FirstPersonState(CameraStateMachineContext context) : base(context) { }
|
||||||
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()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
// В FirstPerson режиме дистанция всегда равна 0
|
// В FirstPerson режиме дистанция всегда равна 0
|
||||||
_minDistance = 0f;
|
MinDistance = 0f;
|
||||||
_maxDistance = 0f;
|
MaxDistance = 0f;
|
||||||
_defaultDistance = 0f;
|
DefaultDistance = 0f;
|
||||||
_targetDistance = 0f;
|
TargetDistance = 0f;
|
||||||
_currentDistance = 0f;
|
CurrentDistance = 0f;
|
||||||
|
|
||||||
_camera = Context.Camera;
|
base.EnterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LateTick()
|
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
|
||||||
{
|
|
||||||
|
|
||||||
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));
|
CurrentFollowPosition = Vector3.Lerp(CurrentFollowPosition, FollowTransform.position, 1f - Mathf.Exp(-FollowSharpness * deltaTime));
|
||||||
|
|
||||||
// Вычисление целевой позиции камеры с учетом текущего режима
|
// В FirstPerson режиме камера находится прямо на позиции цели
|
||||||
Vector3 targetPosition;
|
var targetPosition = CurrentFollowPosition;
|
||||||
// В FirstPerson режиме камера находится прямо на позиции цели
|
|
||||||
targetPosition = _currentFollowPosition;
|
|
||||||
|
|
||||||
// Установка финальной позиции камеры
|
// Установка финальной позиции камеры
|
||||||
_camera.transform.position = targetPosition;
|
Camera.transform.position = targetPosition;
|
||||||
}
|
}
|
||||||
|
public CameraMode GetCameraMode()
|
||||||
// Основной метод обновления камеры, вызываемый извне каждый кадр
|
|
||||||
public void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
|
|
||||||
{
|
{
|
||||||
// Проверка наличия цели для следования и проверка на режим главного меню
|
return CameraMode.FirstPerson;
|
||||||
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,7 @@
|
|||||||
|
namespace Code.Gameplay.Camera.CameraStates
|
||||||
|
{
|
||||||
|
public interface ICameraState
|
||||||
|
{
|
||||||
|
CameraMode GetCameraMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4f25670e547242e8a91e19894cf6889c
|
||||||
|
timeCreated: 1761687204
|
||||||
@@ -1,23 +1,27 @@
|
|||||||
using Code.StateMachine;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Code.Gameplay.Camera.CameraStates
|
namespace Code.Gameplay.Camera.CameraStates
|
||||||
{
|
{
|
||||||
public class StaticState : BaseState<CameraStateMachineContext>
|
public class StaticState : BaseCameraState, ICameraState
|
||||||
{
|
{
|
||||||
private Transform _target;
|
private Transform _target;
|
||||||
private Transform _position;
|
private Transform _position;
|
||||||
private UnityEngine.Camera _camera;
|
public StaticState(CameraStateMachineContext context) : base(context) { }
|
||||||
public StaticState(CameraStateMachineContext context) : base(context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void EnterState()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
_camera = Context.Camera;
|
Debug.Log("Static State Enter");
|
||||||
|
|
||||||
base.EnterState();
|
base.EnterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CameraMode GetCameraMode()
|
||||||
|
{
|
||||||
|
return CameraMode.Static;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,164 +1,58 @@
|
|||||||
using System;
|
|
||||||
using Code.Input;
|
|
||||||
using Code.StateMachine;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Code.Gameplay.Camera.CameraStates
|
namespace Code.Gameplay.Camera.CameraStates
|
||||||
{
|
{
|
||||||
public class ThirdPersonState : BaseState<CameraStateMachineContext>
|
/*
|
||||||
|
* Состояние камеры от третьего лица
|
||||||
|
* Камера следует за персонажем на заданном расстоянии
|
||||||
|
* Поддерживает зум, плавное следование и вращение с учётом угла наклона
|
||||||
|
* Дистанция и углы настраиваются через конфигурацию
|
||||||
|
*/
|
||||||
|
public class ThirdPersonState : BaseCameraState, ICameraState
|
||||||
{
|
{
|
||||||
// Параметры загружаются из CameraConfig
|
public ThirdPersonState(CameraStateMachineContext context) : base(context) { }
|
||||||
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()
|
public override void EnterState()
|
||||||
{
|
{
|
||||||
// Восстанавливаем исходные значения дистанции
|
// Восстанавливаем исходные значения дистанции
|
||||||
_minDistance = _originalMinDistance;
|
MinDistance = OriginalMinDistance;
|
||||||
_maxDistance = _originalMaxDistance;
|
MaxDistance = OriginalMaxDistance;
|
||||||
_defaultDistance = _originalDefaultDistance;
|
DefaultDistance = OriginalDefaultDistance;
|
||||||
_targetDistance = _defaultDistance;
|
TargetDistance = DefaultDistance;
|
||||||
|
|
||||||
_camera = Context.Camera;
|
base.EnterState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void LateTick()
|
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
|
||||||
{
|
|
||||||
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 += zoomInput * DistanceMovementSpeed;
|
||||||
_targetDistance = Mathf.Clamp(_targetDistance, _minDistance, _maxDistance);
|
TargetDistance = Mathf.Clamp(TargetDistance, MinDistance, MaxDistance);
|
||||||
|
|
||||||
// Плавное следование за целью с использованием экспоненциального сглаживания
|
// Плавное следование за целью с использованием экспоненциального сглаживания
|
||||||
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, _followTransform.position,
|
CurrentFollowPosition = Vector3.Lerp(
|
||||||
1f - Mathf.Exp(-_followSharpness * deltaTime));
|
CurrentFollowPosition,
|
||||||
|
FollowTransform.position,
|
||||||
// Вычисление целевой позиции камеры с учетом текущего режима
|
1f - Mathf.Exp(-FollowSharpness * deltaTime)
|
||||||
Vector3 targetPosition;
|
);
|
||||||
|
|
||||||
// В ThirdPerson режиме камера отодвинута на расстояние от цели
|
// В ThirdPerson режиме камера отодвинута на расстояние от цели
|
||||||
targetPosition = _currentFollowPosition - targetRotation * Vector3.forward * _currentDistance;
|
var targetPosition = CurrentFollowPosition - targetRotation * Vector3.forward * CurrentDistance;
|
||||||
|
|
||||||
// Плавное изменение текущей дистанции к целевой (только для ThirdPerson)
|
|
||||||
|
|
||||||
_currentDistance = Mathf.Lerp(_currentDistance, _targetDistance,
|
|
||||||
1f - Mathf.Exp(-_distanceMovementSpeed * deltaTime));
|
|
||||||
|
|
||||||
|
// Плавное изменение текущей дистанции к целевой
|
||||||
|
CurrentDistance = Mathf.Lerp(
|
||||||
|
CurrentDistance,
|
||||||
|
TargetDistance,
|
||||||
|
1f - Mathf.Exp(-DistanceMovementSpeed * deltaTime)
|
||||||
|
);
|
||||||
|
|
||||||
// Установка финальной позиции камеры
|
// Установка финальной позиции камеры
|
||||||
_camera.transform.position = targetPosition;
|
Camera.transform.position = targetPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Установка цели для следования камеры
|
public CameraMode GetCameraMode()
|
||||||
public void SetFollowTransform(Transform t)
|
|
||||||
{
|
{
|
||||||
_followTransform = t;
|
return CameraMode.ThirdPerson;
|
||||||
_currentFollowPosition = t.position;
|
|
||||||
PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b36ec6a31fb74d608232394fd5df657c
|
|
||||||
timeCreated: 1761570832
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Code.Configs;
|
|
||||||
using Code.Gameplay.Camera;
|
|
||||||
using Code.Gameplay.Character.Core;
|
|
||||||
using Code.StaticData;
|
|
||||||
using Reflex.Attributes;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Code.Gameplay.Character.Camera
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Скрипт, отвечающий за поведение камеры при передвижении
|
|
||||||
* Поддерживает как 3rd-person, так и 1st-person режимы камеры
|
|
||||||
* Реализует плавное следование за персонажем, вращение и зум камеры
|
|
||||||
*
|
|
||||||
* Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM
|
|
||||||
*/
|
|
||||||
public class CameraService : MonoBehaviour
|
|
||||||
{
|
|
||||||
// Параметры загружаются из 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; }
|
|
||||||
|
|
||||||
// Текущий режим работы камеры
|
|
||||||
public CameraMode CurrentMode { get; private set; }
|
|
||||||
|
|
||||||
// Загрузка конфига для камеры
|
|
||||||
[Inject]
|
|
||||||
private void LoadConfig(CameraConfig config)
|
|
||||||
{
|
|
||||||
// Загрузка значений из конфига
|
|
||||||
|
|
||||||
_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;
|
|
||||||
CurrentMode = config.defaultCameraMode;
|
|
||||||
_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 void SetFollowTransform(Transform t)
|
|
||||||
{
|
|
||||||
_followTransform = t;
|
|
||||||
_currentFollowPosition = t.position;
|
|
||||||
PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка вращения камеры на основе пользовательского ввода
|
|
||||||
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(transform.rotation, planarRotation * verticalRotation, deltaTime * _rotationSharpness);
|
|
||||||
|
|
||||||
// Применение финального вращения
|
|
||||||
transform.rotation = targetRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обработка позиционирования камеры и зума с учетом текущего режима
|
|
||||||
private void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
|
|
||||||
{
|
|
||||||
// В FirstPerson режиме зум отключается
|
|
||||||
if (CurrentMode != CameraMode.FirstPerson)
|
|
||||||
{
|
|
||||||
// Обновление целевой дистанции на основе ввода зума
|
|
||||||
_targetDistance += zoomInput * _distanceMovementSpeed;
|
|
||||||
_targetDistance = Mathf.Clamp(_targetDistance, _minDistance, _maxDistance);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Плавное следование за целью с использованием экспоненциального сглаживания
|
|
||||||
_currentFollowPosition = Vector3.Lerp(_currentFollowPosition, _followTransform.position, 1f - Mathf.Exp(-_followSharpness * deltaTime));
|
|
||||||
|
|
||||||
// Вычисление целевой позиции камеры с учетом текущего режима
|
|
||||||
Vector3 targetPosition;
|
|
||||||
if (CurrentMode == CameraMode.FirstPerson)
|
|
||||||
{
|
|
||||||
// В FirstPerson режиме камера находится прямо на позиции цели
|
|
||||||
targetPosition = _currentFollowPosition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// В ThirdPerson режиме камера отодвинута на расстояние от цели
|
|
||||||
targetPosition = _currentFollowPosition - targetRotation * Vector3.forward * _currentDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Плавное изменение текущей дистанции к целевой (только для ThirdPerson)
|
|
||||||
if (CurrentMode != CameraMode.FirstPerson)
|
|
||||||
{
|
|
||||||
_currentDistance = Mathf.Lerp(_currentDistance, _targetDistance, 1f - Mathf.Exp(-_distanceMovementSpeed * deltaTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Установка финальной позиции камеры
|
|
||||||
transform.position = targetPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Основной метод обновления камеры, вызываемый извне каждый кадр
|
|
||||||
public void UpdateWithInput(float deltaTime, float zoomInput, Vector3 rotationInput)
|
|
||||||
{
|
|
||||||
// Проверка наличия цели для следования и проверка на режим главного меню
|
|
||||||
if (!_followTransform || CurrentMode == CameraMode.Bogdan) return;
|
|
||||||
|
|
||||||
// Обработка ввода и позиционирования
|
|
||||||
HandleRotationInput(deltaTime, rotationInput, out var targetRotation);
|
|
||||||
HandlePosition(deltaTime, zoomInput, targetRotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Смена режима камеры
|
|
||||||
public void SetCameraMode(CameraMode newMode)
|
|
||||||
{
|
|
||||||
if (CurrentMode == newMode) return;
|
|
||||||
CurrentMode = newMode;
|
|
||||||
|
|
||||||
// Применяем настройки специфичные для режима
|
|
||||||
ApplyModeSpecificSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Применение настроек специфичных для текущего режима
|
|
||||||
private void ApplyModeSpecificSettings()
|
|
||||||
{
|
|
||||||
switch (CurrentMode)
|
|
||||||
{
|
|
||||||
case CameraMode.FirstPerson:
|
|
||||||
// В FirstPerson режиме дистанция всегда равна 0
|
|
||||||
_minDistance = 0f;
|
|
||||||
_maxDistance = 0f;
|
|
||||||
_defaultDistance = 0f;
|
|
||||||
_targetDistance = 0f;
|
|
||||||
_currentDistance = 0f;
|
|
||||||
break;
|
|
||||||
case CameraMode.ThirdPerson:
|
|
||||||
// Восстанавливаем исходные значения дистанции
|
|
||||||
_minDistance = _originalMinDistance;
|
|
||||||
_maxDistance = _originalMaxDistance;
|
|
||||||
_defaultDistance = _originalDefaultDistance;
|
|
||||||
_targetDistance = _defaultDistance;
|
|
||||||
break;
|
|
||||||
// Заготовка на будущее (если понадобится)
|
|
||||||
case CameraMode.Bogdan:
|
|
||||||
_minDistance = 0f;
|
|
||||||
_maxDistance = 0f;
|
|
||||||
_defaultDistance = 0f;
|
|
||||||
_targetDistance = 0f;
|
|
||||||
_currentDistance = 0f;
|
|
||||||
break;
|
|
||||||
case CameraMode.Static:
|
|
||||||
case CameraMode.Cinematic:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f1d98e6c5419411098391c07861e627e
|
|
||||||
timeCreated: 1760627986
|
|
||||||
+1
-1
@@ -54,7 +54,7 @@ namespace Code.Gameplay.Character.Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Текущий режим камеры для адаптации поведения
|
// Текущий режим камеры для адаптации поведения
|
||||||
private CameraMode _currentCameraMode = CameraMode.ThirdPerson;
|
private CameraMode _currentCameraMode = CameraMode.FirstPerson;
|
||||||
|
|
||||||
// Инициализация контроллера
|
// Инициализация контроллера
|
||||||
private void Start()
|
private void Start()
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
using Code.Gameplay.Camera;
|
using Code.Gameplay.Camera;
|
||||||
using Code.Gameplay.Camera.CameraStates;
|
using Code.Gameplay.Camera.CameraStates;
|
||||||
using Code.Gameplay.Character.Camera;
|
|
||||||
using Code.Gameplay.Character.Controller;
|
using Code.Gameplay.Character.Controller;
|
||||||
using Code.Input;
|
using Code.Input;
|
||||||
using Reflex.Attributes;
|
using Reflex.Attributes;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Serialization;
|
|
||||||
|
|
||||||
namespace Code.Gameplay.Character.Core
|
namespace Code.Gameplay.Character.Core
|
||||||
{
|
{
|
||||||
@@ -17,7 +15,7 @@ namespace Code.Gameplay.Character.Core
|
|||||||
*/
|
*/
|
||||||
public class Character : MonoBehaviour
|
public class Character : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Inject] private CameraStateMachine _cameraService; // Компонент камеры персонажа
|
[Inject] private CameraStateMachine _cameraStateMachine; // Стейт-машина камеры (нужна для транзакций и т.п.)
|
||||||
[SerializeField] private CustomCharacterController customCharacterController; // Компонент управления персонажем
|
[SerializeField] private CustomCharacterController customCharacterController; // Компонент управления персонажем
|
||||||
[SerializeField] private Transform cameraFollowPoint; // Точка следования камеры (уровень глаз для FirstPerson)
|
[SerializeField] private Transform cameraFollowPoint; // Точка следования камеры (уровень глаз для FirstPerson)
|
||||||
|
|
||||||
@@ -30,7 +28,7 @@ namespace Code.Gameplay.Character.Core
|
|||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
// Настройка камеры для следования за точкой камеры
|
// Настройка камеры для следования за точкой камеры
|
||||||
((FirstPersonState)_cameraService.CurrentBaseState).SetFollowTransform(cameraFollowPoint);
|
((BaseCameraState)_cameraStateMachine.CurrentBaseState).SetFollowTransform(cameraFollowPoint);
|
||||||
|
|
||||||
// Включение Gameplay мапа ввода
|
// Включение Gameplay мапа ввода
|
||||||
_inputService.EnableMap(ActionMappings.Gameplay);
|
_inputService.EnableMap(ActionMappings.Gameplay);
|
||||||
@@ -49,9 +47,11 @@ namespace Code.Gameplay.Character.Core
|
|||||||
inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space)
|
inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space)
|
||||||
inputs.SprintPressed = _inputService.SprintPressed; // Спринт (Shift)
|
inputs.SprintPressed = _inputService.SprintPressed; // Спринт (Shift)
|
||||||
inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl)
|
inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl)
|
||||||
|
inputs.CameraMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode();
|
||||||
|
|
||||||
// Передаем информацию о камере для адаптивного поведения
|
// Передаем информацию о камере для адаптивного поведения
|
||||||
inputs.CameraRotation = _cameraService.transform.rotation;
|
inputs.CameraRotation = ((BaseCameraState)_cameraStateMachine.CurrentBaseState).GetCameraRotation();
|
||||||
|
inputs.CameraPlanarDirection = ((BaseCameraState)_cameraStateMachine.CurrentBaseState).GetPlanarDirection();
|
||||||
|
|
||||||
// Передаем ввод в контроллер персонажа
|
// Передаем ввод в контроллер персонажа
|
||||||
customCharacterController.SetInputs(ref inputs);
|
customCharacterController.SetInputs(ref inputs);
|
||||||
@@ -67,7 +67,7 @@ namespace Code.Gameplay.Character.Core
|
|||||||
{
|
{
|
||||||
// Обрабатываем нажатие только один раз при первом обнаружении
|
// Обрабатываем нажатие только один раз при первом обнаружении
|
||||||
case true when !_cameraModeToggleHandled:
|
case true when !_cameraModeToggleHandled:
|
||||||
// ToggleCameraMode();
|
ToggleCameraMode();
|
||||||
_cameraModeToggleHandled = true;
|
_cameraModeToggleHandled = true;
|
||||||
break;
|
break;
|
||||||
// Сбрасываем флаг когда кнопка отпущена
|
// Сбрасываем флаг когда кнопка отпущена
|
||||||
@@ -76,6 +76,17 @@ namespace Code.Gameplay.Character.Core
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Метод для переключения режимов камеры
|
||||||
|
private void ToggleCameraMode()
|
||||||
|
{
|
||||||
|
var currentMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode();
|
||||||
|
var newMode = currentMode == CameraMode.FirstPerson ? CameraMode.ThirdPerson : CameraMode.FirstPerson;
|
||||||
|
|
||||||
|
_cameraStateMachine.SwitchState(newMode);
|
||||||
|
((BaseCameraState)_cameraStateMachine.CurrentBaseState).SetFollowTransform(cameraFollowPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Обновление логики каждый кадр
|
// Обновление логики каждый кадр
|
||||||
private void Update()
|
private void Update()
|
||||||
@@ -86,10 +97,5 @@ namespace Code.Gameplay.Character.Core
|
|||||||
// Обработка переключения режима камеры
|
// Обработка переключения режима камеры
|
||||||
HandleCameraModeInput();
|
HandleCameraModeInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обновление после всех вычислений (идеально для камеры)
|
|
||||||
private void LateUpdate()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
using Code.Configs;
|
|
||||||
using Reflex.Attributes;
|
|
||||||
|
|
||||||
namespace Code.Gameplay.Player
|
|
||||||
{
|
|
||||||
public class PlayerFactory
|
|
||||||
{
|
|
||||||
[Inject] PlayerConfig _playerConfig;
|
|
||||||
|
|
||||||
public PlayerHealth CreatePlayerHP(int count = -1)
|
|
||||||
{
|
|
||||||
if (count < 0) count = _playerConfig.maxHealth;
|
|
||||||
|
|
||||||
return new PlayerHealth(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ namespace Code.StaticData
|
|||||||
void Load();
|
void Load();
|
||||||
InputConfig InputConfig { get; }
|
InputConfig InputConfig { get; }
|
||||||
AppConfig AppConfig { get; }
|
AppConfig AppConfig { get; }
|
||||||
UIConfig UIConfig { get; }
|
|
||||||
CameraConfig CameraConfig { get; }
|
CameraConfig CameraConfig { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,15 +8,13 @@ namespace Code.StaticData
|
|||||||
{
|
{
|
||||||
public AppConfig AppConfig { get; private set; }
|
public AppConfig AppConfig { get; private set; }
|
||||||
public InputConfig InputConfig { get; private set; }
|
public InputConfig InputConfig { get; private set; }
|
||||||
public UIConfig UIConfig { get; private set; }
|
|
||||||
public CameraConfig CameraConfig { get; private set; }
|
public CameraConfig CameraConfig { get; private set; }
|
||||||
|
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
InputConfig = Resources.Load<InputConfig>(string.Format(StringPaths.ConfigSingle, "App", "InputConfig"));
|
InputConfig = Resources.Load<InputConfig>(string.Format(StringPaths.ConfigSingle, "App", "InputConfig"));
|
||||||
AppConfig = Resources.Load<AppConfig>(string.Format(StringPaths.ConfigSingle, "App", "AppConfig"));
|
AppConfig = Resources.Load<AppConfig>(string.Format(StringPaths.ConfigSingle, "App", "AppConfig"));
|
||||||
CameraConfig = Resources.Load<CameraConfig>(string.Format(StringPaths.ConfigSingle, "App", "CharacterCameraConfig"));
|
CameraConfig = Resources.Load<CameraConfig>(string.Format(StringPaths.ConfigSingle, "App", "CameraConfig"));
|
||||||
UIConfig = Resources.Load<UIConfig>(string.Format(StringPaths.ConfigSingle, "App", "UIConfig"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Code.UI
|
|
||||||
{
|
|
||||||
public class UIService : IUIService
|
|
||||||
{
|
|
||||||
private UIElement[] _uiPanelsPrefabs;
|
|
||||||
private Canvas _canvas;
|
|
||||||
public UIElement CurrentPanel { get; private set; }
|
|
||||||
public LoadingPanel LoadingScreen { get; private set; }
|
|
||||||
|
|
||||||
public UIService(UIElement[] uiPanelsPrefabs, Canvas canvas)
|
|
||||||
{
|
|
||||||
_canvas = Object.Instantiate(canvas);
|
|
||||||
Object.DontDestroyOnLoad(_canvas);
|
|
||||||
|
|
||||||
_uiPanelsPrefabs = uiPanelsPrefabs;
|
|
||||||
|
|
||||||
LoadingScreen = (LoadingPanel)Object.Instantiate(_uiPanelsPrefabs[(int)UIPanel.Loading], _canvas.transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EnablePanel() => CurrentPanel.gameObject.SetActive(true);
|
|
||||||
public void DisablePanel() => CurrentPanel.gameObject.SetActive(false);
|
|
||||||
|
|
||||||
public void SwitchPanelTo(UIPanel uiPanel)
|
|
||||||
{
|
|
||||||
if (CurrentPanel != null)
|
|
||||||
Object.Destroy(CurrentPanel.gameObject);
|
|
||||||
|
|
||||||
CurrentPanel = Object.Instantiate(_uiPanelsPrefabs[(int)uiPanel], _canvas.transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-4
@@ -10,8 +10,8 @@ MonoBehaviour:
|
|||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 11500000, guid: 72fbf590e5fd4747acfdd32eb26bba3a, type: 3}
|
m_Script: {fileID: 11500000, guid: 72fbf590e5fd4747acfdd32eb26bba3a, type: 3}
|
||||||
m_Name: CharacterCameraConfig
|
m_Name: CameraConfig
|
||||||
m_EditorClassIdentifier: Assembly-CSharp::Code.Configs.CharacterCameraConfig
|
m_EditorClassIdentifier: Assembly-CSharp::Code.Configs.CameraConfig
|
||||||
defaultDistance: 6
|
defaultDistance: 6
|
||||||
minDistance: 3
|
minDistance: 3
|
||||||
maxDistance: 10
|
maxDistance: 10
|
||||||
@@ -24,5 +24,4 @@ MonoBehaviour:
|
|||||||
defaultVerticalAngle: 10
|
defaultVerticalAngle: 10
|
||||||
defaultCameraMode: 0
|
defaultCameraMode: 0
|
||||||
defaultFollowPosition: {x: 0, y: 0, z: 0}
|
defaultFollowPosition: {x: 0, y: 0, z: 0}
|
||||||
cameraPrefab: {fileID: 4646144043143727929, guid: 8b8bf5712dc5a42c7bd8e22cddb884c3, type: 3}
|
cameraPrefab: {fileID: 374984699890489845, guid: 8b8bf5712dc5a42c7bd8e22cddb884c3, type: 3}
|
||||||
cameraPrefab2: {fileID: 374984699890489845, guid: 8b8bf5712dc5a42c7bd8e22cddb884c3, type: 3}
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 6938984fc7d25285abb4922dd46d9272
|
guid: d63c98162aec4c9f9b55578df6aee277
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 608c7bc920473dfe5a28da884a28fa9d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f669a7bf66e9d7f868d912b64e88e3ec
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2a6b8d1e15a85328cbaff95e3c73cdfd
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c37e59bfd1d9cd5d083d88fcd9784d1f
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Reference in new issue
Block a user