170 lines
6.4 KiB
C#
170 lines
6.4 KiB
C#
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);
|
||
}
|
||
} |