123 lines
5.1 KiB
C#
123 lines
5.1 KiB
C#
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;
|
||
}
|
||
} |