using UnityEngine; using UnityEngine.InputSystem; public class CameraFollow : MonoBehaviour { [Header("За кем следить")] public Transform target; // Ссылка на персонажа (Player) [Header("Настройки дистанции и зума")] [Tooltip("Текущая дистанция камеры от игрока")] public float distance = 2.4f; // Было 4.0 -> теперь 2.4 (персонаж ближе и крупнее) [Tooltip("Минимальное приближение при зуме колесиком мыши")] public float minDistance = 1.6f; [Tooltip("Максимальное отдаление при зуме колесиком мыши")] public float maxDistance = 4.0f; [Tooltip("Скорость зума колесиком мыши")] public float zoomSpeed = 0.4f; [Header("Позиционирование")] [Tooltip("Высота камеры над игроком")] public float height = 1.35f; [Tooltip("Небольшое смещение вправо (плечевой вид от третьего лица)")] public float shoulderOffset = 0.25f; [Header("Настройки обзора (Мышь)")] public float mouseSensitivity = 10f; public float minPitch = -40f; public float maxPitch = 60f; [Header("Коллизия со стенами")] [Tooltip("Предотвращает прохождение камеры сквозь стены бункера")] public bool checkWallCollision = true; public LayerMask collisionLayers = ~0; public float collisionRadius = 0.2f; private float pitch = 0f; // Вращение вверх/вниз (X) private float yaw = 0f; // Вращение влево/вправо (Y) private float currentDistance; void Start() { Time.timeScale = 1f; Vector3 angles = transform.eulerAngles; pitch = angles.x; yaw = angles.y; currentDistance = distance; if (target == null) { var player = GameObject.FindWithTag("Player"); if (player != null) target = player.transform; } // Исключаем слой Ignore Raycast (слой 2) из проверки стен collisionLayers &= ~(1 << 2); if (target != null) { Quaternion rot = Quaternion.Euler(pitch, yaw, 0f); Vector3 targetFocus = target.position + (Vector3.up * height); Vector3 rightOffset = rot * Vector3.right * shoulderOffset; Vector3 desiredOrigin = targetFocus + rightOffset; Vector3 backDir = -(rot * Vector3.forward); transform.position = desiredOrigin + (backDir * distance); transform.rotation = rot; } } void LateUpdate() { if (target == null || Time.timeScale == 0f) return; var mouse = Mouse.current; if (mouse != null) { // Читаем дельту мыши (смещение курсора за один кадр) Vector2 mouseDelta = mouse.delta.ReadValue(); float sens = mouseSensitivity * GameSettings.GetMouseSensitivity(); yaw += mouseDelta.x * sens * Time.deltaTime; pitch -= mouseDelta.y * sens * Time.deltaTime; // Ограничиваем угол наклона камеры pitch = Mathf.Clamp(pitch, minPitch, maxPitch); // Плавный зум колесиком мыши: игрок может сам отдалять/приближать камеру float scroll = mouse.scroll.ReadValue().y; if (Mathf.Abs(scroll) > 0.01f) { distance = Mathf.Clamp(distance - Mathf.Sign(scroll) * zoomSpeed, minDistance, maxDistance); } } // Вращаем камеру Quaternion rotation = Quaternion.Euler(pitch, yaw, 0f); // Точка фокусировки над персонажем Vector3 targetFocus = target.position + (Vector3.up * height); // Плечевое смещение Vector3 rightOffset = rotation * Vector3.right * shoulderOffset; Vector3 desiredOrigin = targetFocus + rightOffset; // Направление назад Vector3 backDirection = -(rotation * Vector3.forward); float targetDist = distance; // Коллизия со стенами: не даем камере заглядывать сквозь стены if (checkWallCollision) { if (Physics.SphereCast(targetFocus, collisionRadius, backDirection, out RaycastHit hit, distance, collisionLayers, QueryTriggerInteraction.Ignore)) { targetDist = Mathf.Clamp(hit.distance - 0.1f, minDistance * 0.5f, distance); } } currentDistance = Mathf.Lerp(currentDistance, targetDist, Time.deltaTime * 15f); Vector3 position = desiredOrigin + (backDirection * currentDistance); transform.position = position; transform.rotation = rotation; } }