using UnityEngine; using UnityEngine.InputSystem; [RequireComponent(typeof(CharacterController))] public class PlayerMovement : MonoBehaviour { [Header("Настройки скорости")] public float walkSpeed = 3.0f; // Обычный шаг public float runSpeed = 6.0f; // Бег (Shift) public float sneakSpeed = 1.5f; // Тактический шаг (Ctrl) [Header("Настройки вращения")] public float turnSmoothTime = 0.1f; // Плавность поворота модельки при свободном беге [Tooltip("Плавность поворота к прицелу при стрельбе/прицеливании (быстро, но без телепорта)")] public float aimTurnSmoothTime = 0.05f; private float turnSmoothVelocity; private float aimTurnSmoothVelocity; [Header("Камера")] public Transform cam; // Ссылка на главную камеру [Header("Анимация")] public Animator animator; // Аниматор персонажа private CharacterController controller; private Vector3 velocity; private float gravity = -9.81f; private float currentAnimSpeed = 0f; private float aimLockTimer = 0f; public bool IsAimLocked => aimLockTimer > 0f; void Start() { Time.timeScale = 1f; controller = GetComponent(); if (cam == null && Camera.main != null) cam = Camera.main.transform; if (animator == null) animator = GetComponentInChildren(); if (animator != null) { animator.SetFloat("Speed", 0f); animator.SetBool("IsMoving", false); } // Скрываем и блокируем курсор Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } /// /// Активирует быстрый плавный разворот персонажа к прицелу камеры (для стрельбы/ударов) /// и удерживает режим стрейфа на заданное время. /// public void SnapToAim(float lockDuration = 0.5f) { if (cam == null && Camera.main != null) cam = Camera.main.transform; if (aimLockTimer <= 0f) { aimTurnSmoothVelocity = 0f; } aimLockTimer = Mathf.Max(aimLockTimer, lockDuration); } void Update() { HandleMovement(); } void HandleMovement() { if (cam == null && Camera.main != null) cam = Camera.main.transform; if (aimLockTimer > 0f) { aimLockTimer -= Time.deltaTime; if (aimLockTimer <= 0f) { turnSmoothVelocity = 0f; } } // Гравитация if (controller.isGrounded && velocity.y < 0) { velocity.y = -2f; } float currentSpeed = walkSpeed; float horizontal = 0f; float vertical = 0f; // Читаем ввод с клавиатуры через New Input System var keyboard = Keyboard.current; if (keyboard != null) { // Ускорение и замедление if (keyboard.leftShiftKey.isPressed) currentSpeed = runSpeed; else if (keyboard.leftCtrlKey.isPressed) currentSpeed = sneakSpeed; // Направления (WASD) if (keyboard.dKey.isPressed) horizontal += 1f; if (keyboard.aKey.isPressed) horizontal -= 1f; if (keyboard.wKey.isPressed) vertical += 1f; if (keyboard.sKey.isPressed) vertical -= 1f; } Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized; bool isMoving = direction.magnitude >= 0.1f; if (aimLockTimer > 0f) { // При стрельбе/прицеливании персонаж быстро и плавно поворачивается в сторону прицела камеры if (cam != null) { float targetAngle = cam.eulerAngles.y; float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref aimTurnSmoothVelocity, aimTurnSmoothTime); transform.rotation = Quaternion.Euler(0f, angle, 0f); } // Перемещение работает в режиме стрейфа относительно камеры (нажатие назад = отступать спиной к камере) if (isMoving && cam != null) { Vector3 camFwd = cam.forward; camFwd.y = 0f; camFwd.Normalize(); Vector3 camRight = cam.right; camRight.y = 0f; camRight.Normalize(); Vector3 moveDir = (camFwd * vertical + camRight * horizontal).normalized; controller.Move(moveDir * currentSpeed * Time.deltaTime); } } else if (isMoving) { // Свободный бег: вычисляем угол поворота с учетом направления камеры float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y; // Плавно поворачиваем капсулу в сторону бега float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime); transform.rotation = Quaternion.Euler(0f, angle, 0f); // Двигаем контроллер Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward; controller.Move(moveDir.normalized * currentSpeed * Time.deltaTime); } // Обновляем параметры аниматора if (animator != null) { float targetSpeed = isMoving ? currentSpeed : 0f; currentAnimSpeed = Mathf.MoveTowards(currentAnimSpeed, targetSpeed, 12f * Time.deltaTime); animator.SetFloat("Speed", currentAnimSpeed); animator.SetBool("IsMoving", isMoving); } // Применяем гравитацию velocity.y += gravity * Time.deltaTime; controller.Move(velocity * Time.deltaTime); } }