diff --git a/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs b/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs index cf58b89..5c1b3ca 100644 --- a/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs +++ b/Game/CourierOld/Assets/Code/Gameplay/Player/CharacterController.cs @@ -3,22 +3,26 @@ using UnityEngine; namespace Code.Gameplay.Player { + /* + * Структура для хранения входных данных от игрока + * Содержит информацию о движении и состоянии камеры + */ + public struct PlayerInputs + { + public float MoveAxisForward; // Ввод движения вперед/назад (W/S или Up/Down) + public float MoveAxisRight; // Ввод движения влево/вправо (A/D или Left/Right) + public Quaternion CameraRotation; // Текущее вращение камеры для определения направления движения + public CameraMode CameraMode; // Текущий режим камеры для адаптации поведения + public Vector3 CameraPlanarDirection; // Направление камеры в горизонтальной плоскости + } + /* * Скрипт, отвечающий за передвижения игрока * Реализует физическое движение персонажа с использованием Kinematic Character Controller * Обрабатывает ввод пользователя, применяет движение и вращение с учетом поверхности * * Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM - */ - - // Структура для хранения входных данных от игрока - public struct PlayerInputs - { - public float MoveAxisForward; // Ввод движения вперед/назад (W/S или Up/Down) - public float MoveAxisRight; // Ввод движения влево/вправо (A/D или Left/Right) - public Quaternion CameraRotation; // Текущее вращение камеры для определения направления движения - } - + */ public class CharacterController : MonoBehaviour, ICharacterController { [SerializeField] @@ -33,54 +37,143 @@ namespace Code.Gameplay.Player // Векторы движения и направления взгляда private Vector3 _moveInputVector, _lookInputVector; + // Текущий режим камеры для адаптации поведения + private CameraMode _currentCameraMode = CameraMode.ThirdPerson; + + // Вращение камеры в FirstPerson режиме для синхронизации (только горизонтальная компонента) + private Quaternion _firstPersonCameraRotation; + + // Флаг указывающий, что нужно применить вращение камеры к персонажу + private bool _shouldApplyCameraRotation; + // Инициализация контроллера private void Start() { motor.CharacterController = this; // Регистрация этого контроллера в движке + _firstPersonCameraRotation = motor.Transform.rotation; // Начальное вращение совпадает с персонажем } // Обработка и преобразование входных данных от игрока public void SetInputs(ref PlayerInputs inputs) { + // Сохраняем текущий режим камеры + _currentCameraMode = inputs.CameraMode; + // Нормализация вектора движения и ограничение его величины до 1 - Vector3 moveInputVector = + var moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0, inputs.MoveAxisForward), 1f); - + + // Раздельная обработка в зависимости от режима камеры + if (_currentCameraMode == CameraMode.FirstPerson) + { + HandleFirstPersonInputs(ref inputs, moveInputVector); + } + else + { + HandleThirdPersonInputs(ref inputs, moveInputVector); + } + } + + // Обработка ввода для FirstPerson режима + private void HandleFirstPersonInputs(ref PlayerInputs inputs, Vector3 moveInputVector) + { + // Сохраняем вращение камеры для применения в UpdateRotation (только горизонтальная компонента) + _firstPersonCameraRotation = ExtractHorizontalRotation(inputs.CameraRotation); + _shouldApplyCameraRotation = true; + + // В FirstPerson режиме движение всегда относительно направления камеры + // Получаем направление камеры в горизонтальной плоскости + var cameraPlanarDirection = inputs.CameraPlanarDirection; + + // Создание вращения на основе направления камеры + var cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, motor.CharacterUp); + + // Преобразование локального ввода в мировые координаты относительно камеры + _moveInputVector = cameraPlanarRotation * moveInputVector; + + // В FirstPerson режиме направление взгляда всегда совпадает с направлением камеры (горизонтально) + _lookInputVector = cameraPlanarDirection; + } + + // Обработка ввода для ThirdPerson режима + private void HandleThirdPersonInputs(ref PlayerInputs inputs, Vector3 moveInputVector) + { + // Сбрасываем флаг применения вращения камеры + _shouldApplyCameraRotation = false; + // Получение направления камеры в горизонтальной плоскости (игнорируя наклон) - Vector3 cameraPlanarDirection = - Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, motor.CharacterUp).normalized; + var cameraPlanarDirection = inputs.CameraPlanarDirection; // Резервный расчет направления, если основное направление параллельно вертикали if (cameraPlanarDirection.sqrMagnitude == 0f) { cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, motor.CharacterUp); } - + // Создание вращения на основе направления камеры - Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, motor.CharacterUp); - + var cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, motor.CharacterUp); + // Преобразование локального ввода в мировые координаты относительно камеры _moveInputVector = cameraPlanarRotation * moveInputVector; - + // Направление взгляда совпадает с направлением движения (нормализованное) _lookInputVector = _moveInputVector.normalized; } + // Извлечение только горизонтальной компоненты вращения (игнорируя наклон камеры) + private Quaternion ExtractHorizontalRotation(Quaternion cameraRotation) + { + // Получаем вектор направления камеры + var cameraForward = cameraRotation * Vector3.forward; + + // Проецируем на горизонтальную плоскость + var horizontalForward = Vector3.ProjectOnPlane(cameraForward, motor.CharacterUp).normalized; + + // Если проекция вырождена, используем текущее направление персонажа + if (horizontalForward.sqrMagnitude < 0.01f) + { + horizontalForward = motor.CharacterForward; + } + + // Создаем вращение только по горизонтали + return Quaternion.LookRotation(horizontalForward, motor.CharacterUp); + } + // Обновление вращения персонажа на основе входных данных public void UpdateRotation(ref Quaternion currentRotation, float deltaTime) { - // Вращение применяется только если есть направление движения и разрешена резкость вращения - if (_lookInputVector.sqrMagnitude > 0 && orientationSharpness > 0) + switch (_currentCameraMode) { - // Плавная интерполяция текущего направления к целевому с экспоненциальным сглаживанием - Vector3 smoothedLookInputDirection = Vector3.Slerp( - motor.CharacterForward, - _lookInputVector, - 1f - Mathf.Exp(-orientationSharpness * deltaTime) - ).normalized; - - // Установка нового вращения смотря в сглаженном направлении - currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, motor.CharacterUp); + // В FirstPerson режиме применяем вращение камеры напрямую к персонажу (только горизонталь) + case CameraMode.FirstPerson when _shouldApplyCameraRotation: + // Немедленно применяем горизонтальное вращение камеры к персонажу + currentRotation = _firstPersonCameraRotation; + _shouldApplyCameraRotation = false; + break; + // В ThirdPerson режиме плавно поворачиваем персонаж в направлении движения + case CameraMode.ThirdPerson: + { + // Вращение применяется только если есть направление движения и разрешена резкость вращения + if (_lookInputVector.sqrMagnitude > 0 && orientationSharpness > 0) + { + // Плавная интерполяция текущего направления к целевому с экспоненциальным сглаживанием + var smoothedLookInputDirection = Vector3.Slerp( + motor.CharacterForward, + _lookInputVector, + 1f - Mathf.Exp(-orientationSharpness * deltaTime) + ).normalized; + + // Установка нового вращения смотря в сглаженном направлении + currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, motor.CharacterUp); + } + + break; + } + // Заготовка на будущее (если понадобится) + case CameraMode.Static: + case CameraMode.Cinematic: + default: + break; } } @@ -88,20 +181,20 @@ namespace Code.Gameplay.Player public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) { // Сохранение текущей величины скорости - float currentVelocityMagnitude = currentVelocity.magnitude; + var currentVelocityMagnitude = currentVelocity.magnitude; // Получение нормали поверхности для корректного движения по наклонным плоскостям - Vector3 effectiveGroundNormal = motor.GroundingStatus.GroundNormal; + var effectiveGroundNormal = motor.GroundingStatus.GroundNormal; // Переориентация текущей скорости вдоль поверхности currentVelocity = motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) * currentVelocityMagnitude; // Переориентация входного вектора движения вдоль поверхности - Vector3 inputRight = Vector3.Cross(_moveInputVector, motor.CharacterUp); - Vector3 reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * _moveInputVector.magnitude; + var inputRight = Vector3.Cross(_moveInputVector, motor.CharacterUp); + var reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * _moveInputVector.magnitude; // Расчет целевой скорости движения с учетом ограничения максимальной скорости - Vector3 targetMovementVelocity = reorientedInput * maxStableMoveSpeed; + var targetMovementVelocity = reorientedInput * maxStableMoveSpeed; // Плавная интерполяция текущей скорости к целевой с экспоненциальным сглаживанием currentVelocity = Vector3.Lerp( diff --git a/Game/CourierOld/Assets/Code/Gameplay/Player/Player.cs b/Game/CourierOld/Assets/Code/Gameplay/Player/Player.cs index f0a45c6..c135e8b 100644 --- a/Game/CourierOld/Assets/Code/Gameplay/Player/Player.cs +++ b/Game/CourierOld/Assets/Code/Gameplay/Player/Player.cs @@ -4,52 +4,113 @@ using Reflex.Attributes; using UnityEngine; using CharacterController = Code.Gameplay.Player.CharacterController; +/* + * Главный скрипт игрока, объединяющий камеру и контроллер персонажа + * Обрабатывает ввод пользователя и распределяет его между компонентами + * Синхронизирует состояние камеры и персонажа + * Управляет переключением режимов камеры через Input System + */ public class Player : MonoBehaviour { [SerializeField] - private PlayerCamera playerCamera; + private PlayerCamera playerCamera; // Компонент камеры игрока [SerializeField] - private CharacterController characterController; + private CharacterController characterController; // Компонент управления персонажем [SerializeField] - private Transform cameraFollowPoint; - [Inject] private IInputService _inputService; + private Transform cameraFollowPoint; // Точка следования камеры (уровень глаз для FirstPerson) - private Vector3 _lookInputVector; + [Inject] + private IInputService _inputService; // Сервис ввода через DI + // Флаг для отслеживания переключения режима камеры (чтобы избежать многократных срабатываний) + private bool _cameraModeToggleHandled; + + // Инициализация игрока private void Start() { + // Настройка камеры для следования за точкой камеры playerCamera.SetFollowTransform(cameraFollowPoint); + + // Включение Gameplay мапа ввода + _inputService.EnableMap(ActionMappings.Gameplay); } - + + // Обработка ввода для камеры (вращение и зум) private void HandleCameraInput() { + // Получаем данные ввода из Input System var lookInput = _inputService.LookInput; var scrollInput = _inputService.ZoomInput; - + + // Передаем данные в камеру playerCamera.UpdateWithInput(Time.deltaTime, scrollInput, new Vector3(lookInput.x, lookInput.y, 0)); } + // Обработка ввода для движения персонажа private void HandleCharacterInput() { - PlayerInputs inputs = new PlayerInputs(); + // Создаем структуру ввода с полной информацией о камере + var inputs = new PlayerInputs(); - Vector2 moveInput = _inputService.MoveInput; - inputs.MoveAxisForward = moveInput.y; - inputs.MoveAxisRight = moveInput.x; + // Получаем данные движения из Input System + var moveInput = _inputService.MoveInput; + inputs.MoveAxisForward = moveInput.y; // Vertical ось (W/S или Up/Down) + inputs.MoveAxisRight = moveInput.x; // Horizontal ось (A/D или Left/Right) + // Передаем информацию о камере для адаптивного поведения inputs.CameraRotation = playerCamera.transform.rotation; + inputs.CameraMode = playerCamera.CurrentMode; + inputs.CameraPlanarDirection = playerCamera.PlanarDirection; + // Передаем ввод в контроллер персонажа characterController.SetInputs(ref inputs); } + // Обработка переключения режима камеры через Input System + private void HandleCameraModeInput() + { + // Получаем состояние переключения режима камеры из Input System + var togglePressed = _inputService.ToggleCameraModePressed; + + switch (togglePressed) + { + // Обрабатываем нажатие только один раз при первом обнаружении + case true when !_cameraModeToggleHandled: + ToggleCameraMode(); + _cameraModeToggleHandled = true; + break; + // Сбрасываем флаг когда кнопка отпущена + case false: + _cameraModeToggleHandled = false; + break; + } + } + + // Метод для переключения режимов камеры + private void ToggleCameraMode() + { + var currentMode = playerCamera.CurrentMode; + var newMode = currentMode == CameraMode.FirstPerson ? + CameraMode.ThirdPerson : CameraMode.FirstPerson; + + playerCamera.SetCameraMode(newMode); + } + + // Обновление логики каждый кадр private void Update() { + // Обработка ввода для движения в Update (физика) HandleCharacterInput(); + + // Обработка переключения режима камеры + HandleCameraModeInput(); } - + + // Обновление после всех вычислений (идеально для камеры) private void LateUpdate() { + // Обработка ввода для камеры в LateUpdate (после движения персонажа) HandleCameraInput(); } } diff --git a/Game/CourierOld/Assets/Code/Gameplay/Player/PlayerCamera.cs b/Game/CourierOld/Assets/Code/Gameplay/Player/PlayerCamera.cs index 736c4bb..bbee991 100644 --- a/Game/CourierOld/Assets/Code/Gameplay/Player/PlayerCamera.cs +++ b/Game/CourierOld/Assets/Code/Gameplay/Player/PlayerCamera.cs @@ -3,6 +3,21 @@ using UnityEngine; namespace Code.Gameplay.Player { + /* + * Перечисление режимов работы камеры + * Static - статичная камера без следования за целью + * FirstPerson - камера от первого лица (встроена в модель персонажа) + * ThirdPerson - камера от третьего лица (следует за персонажем на расстоянии) + * Cinematic - кинематографическая камера для скриптовых сцен + */ + public enum CameraMode + { + Static, + FirstPerson, + ThirdPerson, + Cinematic + } + /* * Скрипт, отвечающий за поведение камеры при передвижении * Поддерживает как 3rd-person, так и 1st-person режимы камеры @@ -23,27 +38,29 @@ namespace Code.Gameplay.Player distanceMovementSpeed = 5f, // Множитель скорости изменения дистанции при зуме // Скорость интерполяции текущая -> целевая позиция зума - distanceMovementSharpness = 10000f, // Коэффициент плавности изменения дистанции (чем выше - тем резче) + distanceMovementSharpness = 100f, // Коэффициент плавности изменения дистанции (чем выше - тем резче) // Скорость поворота камеры - rotationSpeed = 1f, // Множитель скорости вращения камеры + rotationSpeed = 0.3f, // Множитель скорости вращения камеры // Скорость интерполяции текущее -> целевое вращение - rotationSharpness = 10000f, // Коэффициент плавности вращения камеры (чем выше - тем резче) + rotationSharpness = 100f, // Коэффициент плавности вращения камеры (чем выше - тем резче) // Резкость следования камеры за целью - followSharpness = 10000f, // Коэффициент плавности следования за движущейся целью (чем выше - тем резче) + followSharpness = 100f, // Коэффициент плавности следования за движущейся целью (чем выше - тем резче) // Углы наклона камеры - minVerticalAngle = -45f, // Минимальный угол наклона камеры (вниз) - maxVerticalAngle = 45f, // Максимальный угол наклона камеры (вверх) + minVerticalAngle = -70f, // Минимальный угол наклона камеры (вниз) + maxVerticalAngle = 70f, // Максимальный угол наклона камеры (вверх) defaultVerticalAngle = 10f; // Стандартный угол наклона камеры + // Текущий режим работы камеры + // Трансформ объекта, за которым следует камера (для 1st-person: уровень глаз) private Transform _followTransform; // Позиция следования: текущая сглаженная позиция и горизонтальное направление камеры - private Vector3 _currentFollowPosition, _planarDirection; + private Vector3 _currentFollowPosition; // Целевой вертикальный угол камеры (наклон вверх/вниз) private float _targetVerticalAngle; @@ -51,13 +68,26 @@ namespace Code.Gameplay.Player // Текущая и целевая дистанция камеры от цели private float _currentDistance, _targetDistance; + // Исходные значения дистанции для восстановления после FirstPerson режима + private float _originalDefaultDistance, _originalMinDistance, _originalMaxDistance; + + // Свойства для доступа к важным данным камеры извне + public Vector3 PlanarDirection { get; private set; } // Горизонтальное направление камеры + + public CameraMode CurrentMode { get; private set; } = CameraMode.ThirdPerson; // Текущий режим камеры + // Инициализация камеры при создании private void Awake() { + // Сохраняем исходные значения дистанции для восстановления + _originalDefaultDistance = defaultDistance; + _originalMinDistance = minDistance; + _originalMaxDistance = maxDistance; + _currentDistance = defaultDistance; _targetDistance = _currentDistance; _targetVerticalAngle = 0f; - _planarDirection = Vector3.forward; // Начальное направление - вперед по оси Z + PlanarDirection = Vector3.forward; // Начальное направление - вперед по оси Z } // Установка цели для следования камеры @@ -65,7 +95,7 @@ namespace Code.Gameplay.Player { _followTransform = t; _currentFollowPosition = t.position; - _planarDirection = t.forward; // Начальное направление совпадает с направлением цели + PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели } // Валидация параметров в редакторе Unity @@ -81,8 +111,8 @@ namespace Code.Gameplay.Player { // Вращение вокруг вертикальной оси (горизонтальный поворот) var rotationFromInput = Quaternion.Euler(_followTransform.up * (rotationInput.x * rotationSpeed)); - _planarDirection = rotationFromInput * _planarDirection; - var planarRotation = Quaternion.LookRotation(_planarDirection, _followTransform.up); + PlanarDirection = rotationFromInput * PlanarDirection; + var planarRotation = Quaternion.LookRotation(PlanarDirection, _followTransform.up); // Вращение вокруг горизонтальной оси (вертикальный наклон) _targetVerticalAngle -= rotationInput.y * rotationSpeed; @@ -96,21 +126,38 @@ namespace Code.Gameplay.Player transform.rotation = targetRotation; } - // Обработка позиционирования камеры и зума + // Обработка позиционирования камеры и зума с учетом текущего режима private void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation) { - // Обновление целевой дистанции на основе ввода зума - _targetDistance += zoomInput * distanceMovementSpeed; - _targetDistance = Mathf.Clamp(_targetDistance, minDistance, maxDistance); + // В 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)); - // Вычисление целевой позиции камеры за вычетом дистанции по направлению взгляда - var targetPosition = _currentFollowPosition - targetRotation * Vector3.forward * _currentDistance; + // Вычисление целевой позиции камеры с учетом текущего режима + Vector3 targetPosition; + if (CurrentMode == CameraMode.FirstPerson) + { + // В FirstPerson режиме камера находится прямо на позиции цели + targetPosition = _currentFollowPosition; + } + else + { + // В ThirdPerson режиме камера отодвинута на расстояние от цели + targetPosition = _currentFollowPosition - targetRotation * Vector3.forward * _currentDistance; + } - // Плавное изменение текущей дистанции к целевой - _currentDistance = Mathf.Lerp(_currentDistance, _targetDistance, 1f - Mathf.Exp(-distanceMovementSpeed * deltaTime)); + // Плавное изменение текущей дистанции к целевой (только для ThirdPerson) + if (CurrentMode != CameraMode.FirstPerson) + { + _currentDistance = Mathf.Lerp(_currentDistance, _targetDistance, 1f - Mathf.Exp(-distanceMovementSpeed * deltaTime)); + } // Установка финальной позиции камеры transform.position = targetPosition; @@ -121,8 +168,48 @@ namespace Code.Gameplay.Player { // Проверка наличия цели для следования if (!_followTransform) return; + + // Обработка ввода и позиционирования HandleRotationInput(deltaTime, rotationInput, out Quaternion 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.Static: + case CameraMode.Cinematic: + default: + break; + } + } } } \ No newline at end of file diff --git a/Game/CourierOld/Assets/Code/Input/IInputService.cs b/Game/CourierOld/Assets/Code/Input/IInputService.cs index 6fcf9e8..9a27af8 100644 --- a/Game/CourierOld/Assets/Code/Input/IInputService.cs +++ b/Game/CourierOld/Assets/Code/Input/IInputService.cs @@ -7,8 +7,14 @@ namespace Code.Input void EnableMap(ActionMappings actionMap); void DisableMap(ActionMappings actionMap); + // Для управления камерой Vector2 LookInput { get; } float ZoomInput { get; } + + // Для управления движением персонажа Vector2 MoveInput { get; } + + // Для переключения режима камеры + bool ToggleCameraModePressed { get; } } } \ No newline at end of file diff --git a/Game/CourierOld/Assets/Code/Input/InputService.cs b/Game/CourierOld/Assets/Code/Input/InputService.cs index 7b77428..9c5509f 100644 --- a/Game/CourierOld/Assets/Code/Input/InputService.cs +++ b/Game/CourierOld/Assets/Code/Input/InputService.cs @@ -1,5 +1,4 @@ using System; -using Reflex.Attributes; using UnityEngine; using UnityEngine.InputSystem; @@ -8,12 +7,12 @@ namespace Code.Input public class InputService : IInputService, IDisposable { - private InputActionAsset _inputActionAsset; + private readonly InputActionAsset _inputActionAsset; - // Для работы с камерой public Vector2 LookInput { get; private set; } public float ZoomInput { get; private set; } public Vector2 MoveInput { get; private set; } + public bool ToggleCameraModePressed { get; private set; } public InputService(InputActionAsset inputActionAsset) { @@ -21,24 +20,49 @@ namespace Code.Input SetupInputCallbacks(); } + // Обработка всех карт ввода private void SetupInputCallbacks() { + SetupGameplayInputCallbacks(); + } + + // Обработка геймплейной карты ввода + private void SetupGameplayInputCallbacks() + { + // Инициализация геймплейной карты ввода var gameplayMap = _inputActionAsset.FindActionMap("Gameplay"); + // Обработка взгляда (камера) var lookAction = gameplayMap.FindAction("Look"); - lookAction.performed += OnLookPerformed; - lookAction.canceled += OnLookCanceled; + if (lookAction != null) + { + lookAction.performed += OnLookPerformed; + lookAction.canceled += OnLookCanceled; + } + // Обработка зума (камера) var zoomAction = gameplayMap.FindAction("Zoom"); - zoomAction.performed += OnZoomPerformed; - zoomAction.canceled += OnZoomCanceled; + if (zoomAction != null) + { + zoomAction.performed += OnZoomPerformed; + zoomAction.canceled += OnZoomCanceled; + } + // Обработка движения (персонаж) var moveAction = gameplayMap.FindAction("Move"); if (moveAction != null) { moveAction.performed += OnMovePerformed; moveAction.canceled += OnMoveCanceled; } + + // Обработка переключения режима камеры + var toggleCameraModeAction = gameplayMap.FindAction("ToggleCameraMode"); + if (toggleCameraModeAction != null) + { + toggleCameraModeAction.performed += OnToggleCameraModePerformed; + toggleCameraModeAction.canceled += OnToggleCameraModeCanceled; + } } private void OnLookPerformed(InputAction.CallbackContext context) @@ -70,6 +94,16 @@ namespace Code.Input { MoveInput = Vector2.zero; } + + private void OnToggleCameraModePerformed(InputAction.CallbackContext context) + { + ToggleCameraModePressed = true; + } + + private void OnToggleCameraModeCanceled(InputAction.CallbackContext context) + { + ToggleCameraModePressed = false; + } public void EnableMap(ActionMappings actionMap) => _inputActionAsset.actionMaps[(int)actionMap].Enable(); public void DisableMap(ActionMappings actionMap) => _inputActionAsset.actionMaps[(int)actionMap].Disable(); @@ -86,10 +120,15 @@ namespace Code.Input var gameplayMap = _inputActionAsset.FindActionMap("Gameplay"); gameplayMap.FindAction("Look").performed -= OnLookPerformed; gameplayMap.FindAction("Look").canceled -= OnLookCanceled; + gameplayMap.FindAction("Zoom").performed -= OnZoomPerformed; gameplayMap.FindAction("Zoom").canceled -= OnZoomCanceled; + gameplayMap.FindAction("Move").performed -= OnMovePerformed; gameplayMap.FindAction("Move").canceled -= OnMoveCanceled; + + gameplayMap.FindAction("ToggleCameraMode").performed -= OnToggleCameraModePerformed; + gameplayMap.FindAction("ToggleCameraMode").canceled -= OnToggleCameraModeCanceled; } } } \ No newline at end of file diff --git a/Game/CourierOld/Assets/Resources/Materials/TestMaterial.mat b/Game/CourierOld/Assets/Resources/Materials/GroundTestMaterial.mat similarity index 99% rename from Game/CourierOld/Assets/Resources/Materials/TestMaterial.mat rename to Game/CourierOld/Assets/Resources/Materials/GroundTestMaterial.mat index c4d3026..037b2d4 100644 --- a/Game/CourierOld/Assets/Resources/Materials/TestMaterial.mat +++ b/Game/CourierOld/Assets/Resources/Materials/GroundTestMaterial.mat @@ -20,7 +20,7 @@ Material: m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_Name: TestMaterial + m_Name: GroundTestMaterial m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 diff --git a/Game/CourierOld/Assets/Resources/Materials/TestMaterial.mat.meta b/Game/CourierOld/Assets/Resources/Materials/GroundTestMaterial.mat.meta similarity index 100% rename from Game/CourierOld/Assets/Resources/Materials/TestMaterial.mat.meta rename to Game/CourierOld/Assets/Resources/Materials/GroundTestMaterial.mat.meta diff --git a/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat b/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat new file mode 100644 index 0000000..631a5bc --- /dev/null +++ b/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8082666438668706547 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WallsMateriall + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _DETAIL_MULX2 + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: + - MOTIONVECTORS + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 2800000, guid: 084980307d793717d9a5b1b4852db839, type: 3} + m_Scale: {x: 5, y: 5} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat.meta b/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat.meta new file mode 100644 index 0000000..fcbebf6 --- /dev/null +++ b/Game/CourierOld/Assets/Resources/Materials/WallsMateriall.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b407164ea2464a05a97202efff71afc6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity b/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity index 98149d0..6c42b91 100644 --- a/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity +++ b/Game/CourierOld/Assets/Resources/Scenes/MovementDev.unity @@ -358,20 +358,17 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f1d98e6c5419411098391c07861e627e, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::Code.Gameplay.Player.PlayerCamera - defaultDistance: 0 - minDistance: 0 + defaultDistance: 6 + minDistance: 3 maxDistance: 10 distanceMovementSpeed: 5 - distanceMovementSharpness: 10000 - rotationSpeed: 1 - rotationSharpness: 10000 - followSharpness: 10000 - minVerticalAngle: -45 - maxVerticalAngle: 45 + distanceMovementSharpness: 100 + rotationSpeed: 0.3 + rotationSharpness: 100 + followSharpness: 100 + minVerticalAngle: -70 + maxVerticalAngle: 70 defaultVerticalAngle: 10 - minHorizontalAngle: -90 - maxHorizontalAngle: 90 - defaultHorizontalAngle: 0 --- !u!1 &453575297 GameObject: m_ObjectHideFlags: 0 @@ -547,6 +544,117 @@ Transform: - {fileID: 1533098598} m_Father: {fileID: 1696686254} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1376862591 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1376862595} + - component: {fileID: 1376862594} + - component: {fileID: 1376862593} + - component: {fileID: 1376862592} + m_Layer: 0 + m_Name: Wall + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &1376862592 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1376862591} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1376862593 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1376862591} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b407164ea2464a05a97202efff71afc6, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1376862594 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1376862591} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1376862595 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1376862591} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -10, y: 3, z: 0} + m_LocalScale: {x: 2, y: 6, z: 10} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1533098597 GameObject: m_ObjectHideFlags: 0 @@ -637,6 +745,117 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1533098597} m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1543748505 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1543748509} + - component: {fileID: 1543748508} + - component: {fileID: 1543748507} + - component: {fileID: 1543748506} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &1543748506 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1543748505} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &1543748507 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1543748505} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: b407164ea2464a05a97202efff71afc6, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1543748508 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1543748505} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1543748509 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1543748505} + serializedVersion: 2 + m_LocalRotation: {x: 0.38268343, y: 0, z: 0, w: 0.92387956} + m_LocalPosition: {x: 5, y: 0, z: -10} + m_LocalScale: {x: 5, y: 5, z: 5} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 45, y: 0, z: 0} --- !u!1 &1696686253 GameObject: m_ObjectHideFlags: 0 @@ -822,3 +1041,5 @@ SceneRoots: - {fileID: 1959874991} - {fileID: 1696686254} - {fileID: 481156070} + - {fileID: 1376862595} + - {fileID: 1543748509} diff --git a/Game/CourierOld/Assets/Settings/Input/InputSystem_Actions.inputactions b/Game/CourierOld/Assets/Settings/Input/InputSystem_Actions.inputactions index 0042ac9..bf96e82 100644 --- a/Game/CourierOld/Assets/Settings/Input/InputSystem_Actions.inputactions +++ b/Game/CourierOld/Assets/Settings/Input/InputSystem_Actions.inputactions @@ -555,6 +555,15 @@ "interactions": "", "initialStateCheck": true }, + { + "name": "ToggleCameraMode", + "type": "Button", + "id": "53b8a816-6ab5-4c21-81e2-211187b50e95", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, { "name": "Attack", "type": "Button", @@ -769,7 +778,7 @@ "path": "/delta", "interactions": "", "processors": "", - "groups": ";Keyboard&Mouse;Touch", + "groups": ";Touch", "action": "Look", "isComposite": false, "isPartOfComposite": false @@ -791,7 +800,7 @@ "path": "/delta", "interactions": "", "processors": "", - "groups": "", + "groups": ";Keyboard&Mouse", "action": "Look", "isComposite": false, "isPartOfComposite": false @@ -1022,10 +1031,21 @@ "path": "/scroll/y", "interactions": "", "processors": "", - "groups": "", + "groups": ";Keyboard&Mouse", "action": "Zoom", "isComposite": false, "isPartOfComposite": false + }, + { + "name": "", + "id": "2f4c687f-f66c-4cd8-93f5-28628df0b86f", + "path": "/v", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ToggleCameraMode", + "isComposite": false, + "isPartOfComposite": false } ] }