Perekyp/Assets/Scripts/Player/Movement/PlayerMovement.cs

112 lines
4.1 KiB
C#

using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
[Header("Movement Settings")]
[SerializeField] private float moveSpeed = 4f;
[SerializeField] private float crouchSpeed = 2f;
[SerializeField] private float gravity = -9.81f;
[Header("Crouch Settings")]
[SerializeField] private KeyCode crouchKey = KeyCode.LeftControl;
[SerializeField] private float standHeight = 2.0f;
[SerializeField] private float crouchHeight = 1.0f;
[SerializeField] private float crouchTransitionSpeed = 10f;
[SerializeField] private Transform playerCamera; // Ссылка на камеру игрока
[Header("Ground Check")]
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundDistance = 0.4f;
[SerializeField] private LayerMask groundMask;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private float initialHeight;
private Vector3 standCameraPos;
private Vector3 crouchCameraPos;
private Vector3 initialCenter;
private bool isCrouching;
private void Awake()
{
controller = GetComponent<CharacterController>();
}
private void Start()
{
// Запоминаем исходные значения из Инспектора
initialHeight = controller.height;
initialCenter = controller.center;
if (playerCamera == null)
{
Camera cam = GetComponentInChildren<Camera>();
if (cam != null) playerCamera = cam.transform;
}
if (playerCamera != null)
{
standCameraPos = playerCamera.localPosition;
// Камера опускается ровно на разницу высоты
crouchCameraPos = new Vector3(
standCameraPos.x,
standCameraPos.y - (standHeight - crouchHeight),
standCameraPos.z
);
}
}
private void Update()
{
HandleCrouch();
}
private void HandleCrouch()
{
isCrouching = Input.GetKey(crouchKey);
float targetHeight = isCrouching ? crouchHeight : standHeight;
float currentDelta = initialHeight - targetHeight;
// ГЛАВНАЯ ФОРМУЛА: дно капсулы остается на земле
Vector3 targetCenter = new Vector3(
initialCenter.x,
initialCenter.y - (currentDelta * 0.5f),
initialCenter.z
);
controller.height = Mathf.MoveTowards(controller.height, targetHeight, Time.deltaTime * crouchTransitionSpeed);
controller.center = Vector3.MoveTowards(controller.center, targetCenter, Time.deltaTime * crouchTransitionSpeed);
if (playerCamera != null)
{
Vector3 targetCamPos = isCrouching ? crouchCameraPos : standCameraPos;
playerCamera.localPosition = Vector3.MoveTowards(playerCamera.localPosition, targetCamPos, Time.deltaTime * crouchTransitionSpeed);
}
}
public void ProcessMove(Vector2 input)
{
// Проверка касания земли (сфера на уровне ног)
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f; // Небольшое прижатие к земле для стабильного спуска по склонам
}
// Выбор текущей скорости в зависимости от состояния приседа
float currentSpeed = isCrouching ? crouchSpeed : moveSpeed;
// Движение относительно локальных координат игрока
Vector3 move = transform.right * input.x + transform.forward * input.y;
controller.Move(move * (currentSpeed * Time.deltaTime));
// Применение гравитации
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}