using UnityEngine; namespace _Project.Scripts.PlayerUtils { public class PlayerCamera : MonoBehaviour { [Header("Камера и Настройки")] [SerializeField] private Transform cameraPosition; [SerializeField] private float mouseSensitivity = 0.1f; [SerializeField] private float maxLookAngle = 80f; [Header("Высота камеры")] [SerializeField] private float standingCameraY = 1.6f; [SerializeField] private float crouchingCameraY = 0.8f; [SerializeField] private float crouchTransitionSpeed = 15f; [SerializeField] private float slideCameraTiltAngle = 4f; [Header("Тряска Камеры (Headbob)")] public bool enableHeadBob = true; [SerializeField] private float walkBobSpeed = 12f; [SerializeField] private float walkBobAmount = 0.04f; [SerializeField] private float sprintBobSpeed = 15f; [SerializeField] private float sprintBobAmount = 0.07f; [SerializeField] private float impactRecoverySpeed = 6f; public Transform CameraTransform => cameraPosition; private PlayerControls controls; private PlayerMovement movement; private float cameraPitch = 0f; private float yRotation = 0f; private float currentCameraTilt = 0f; private float baseCameraY; private float bobTimer = 0f; private Vector3 bobOffset = Vector3.zero; private float currentImpactOffset = 0f; private bool stepTaken = false; private void Start() { controls = Player.Instance.Controls; movement = Player.Instance.Movement; mouseSensitivity = PlayerPrefs.GetFloat("MouseSensitivity", mouseSensitivity); baseCameraY = standingCameraY; yRotation = transform.eulerAngles.y; } public void ApplyProfile(BodyProfile profile) { standingCameraY = profile.standingCameraY; crouchingCameraY = profile.crouchingCameraY; walkBobSpeed = profile.walkBobSpeed; sprintBobSpeed = profile.walkBobSpeed * 1.25f; walkBobAmount = profile.walkBobAmount; sprintBobAmount = profile.walkBobAmount * 1.6f; slideCameraTiltAngle = profile.slideTiltAngle; } public void SetYaw(float yaw) { yRotation = yaw; transform.rotation = Quaternion.Euler(0f, yRotation, 0f); } private void Update() { if (Time.timeScale == 0f) return; HandleMouseLook(); HandleCameraAndBobbing(); } private void HandleMouseLook() { Vector2 lookInput = controls.Player.Look.ReadValue(); float dt = Time.unscaledDeltaTime; cameraPitch -= lookInput.y * mouseSensitivity; cameraPitch = Mathf.Clamp(cameraPitch, -maxLookAngle, maxLookAngle); float targetTilt = movement.IsSliding ? -slideCameraTiltAngle : 0f; currentCameraTilt = Mathf.Lerp(currentCameraTilt, targetTilt, dt * 10f); cameraPosition.localRotation = Quaternion.Euler(cameraPitch, 0f, currentCameraTilt); yRotation += lookInput.x * mouseSensitivity; transform.rotation = Quaternion.Euler(0f, yRotation, 0f); } private void HandleCameraAndBobbing() { float dt = Time.unscaledDeltaTime; bool isLowered = movement.IsCrouching || movement.IsSliding; float targetCamY = isLowered ? crouchingCameraY : standingCameraY; baseCameraY = Mathf.Lerp(baseCameraY, targetCamY, dt * crouchTransitionSpeed); bool isMoving = movement.MoveInput.sqrMagnitude > 0.01f && movement.IsGrounded && !movement.IsSliding; if (isMoving && enableHeadBob) { float speed = movement.IsSprinting ? sprintBobSpeed : walkBobSpeed; float amount = movement.IsSprinting ? sprintBobAmount : walkBobAmount; bobTimer += dt * speed; bobOffset.x = Mathf.Cos(bobTimer * 0.5f) * amount; bobOffset.y = Mathf.Sin(bobTimer) * amount; if (Mathf.Sin(bobTimer) <= -0.9f && !stepTaken) { Player.Instance.Sound.PlayFootstep(movement.IsSprinting); stepTaken = true; } else if (Mathf.Sin(bobTimer) > -0.2f) stepTaken = false; } else { bobTimer = 0f; stepTaken = false; bobOffset = Vector3.Lerp(bobOffset, Vector3.zero, dt * 10f); } currentImpactOffset = Mathf.Lerp(currentImpactOffset, 0f, dt * impactRecoverySpeed); cameraPosition.localPosition = new Vector3(bobOffset.x, baseCameraY + bobOffset.y - currentImpactOffset, 0f); } public void ApplyRecoil(float amount) { cameraPitch -= amount; } public void TriggerJumpImpact() { if (enableHeadBob) currentImpactOffset = 0.1f; } } }