112 lines
4.1 KiB
C#
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);
|
|
}
|
|
} |