Kursach_StealthAction/Assets/Scripts/PlayerMovement.cs
2026-10-23 15:44:09 +03:00

170 lines
6.4 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<CharacterController>();
if (cam == null && Camera.main != null)
cam = Camera.main.transform;
if (animator == null)
animator = GetComponentInChildren<Animator>();
if (animator != null)
{
animator.SetFloat("Speed", 0f);
animator.SetBool("IsMoving", false);
}
// Скрываем и блокируем курсор
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
/// <summary>
/// Активирует быстрый плавный разворот персонажа к прицелу камеры (для стрельбы/ударов)
/// и удерживает режим стрейфа на заданное время.
/// </summary>
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);
}
}