Загрузка данных
using UnityEngine;
public class SoftVehicleCamera : MonoBehaviour
{
[Header("Ссылки")]
[SerializeField] private Transform target;
[SerializeField] private Rigidbody vehicleRigidbody;
[SerializeField] private Transform gun;
[Header("Дистанция и Позиция")]
[SerializeField] private float distance = 5.0f;
[SerializeField] private float height = 1.5f;
[Header("Мягкость и Сглаживание")]
[SerializeField] private float rotationSmoothTime = 0.3f;
[SerializeField] private float angleThreshold = 15.0f;
[Header("Вращение мыши")]
[SerializeField] private float mouseSensitivity = 3.0f;
[SerializeField] private float minPitch = -30f;
[SerializeField] private float maxPitch = 60f;
[Header("Смещение прицела")]
[SerializeField] private float aimOffsetSensitivity = 3.0f;
[SerializeField] private float maxAimOffsetDegrees = 10f;
private float horizontalAngle = 0f;
private float verticalAngle = 15f;
private float currentDistance = 5f;
private float smoothHorizontalVelocity;
private Vector3 smoothPositionVelocity;
private bool followGunMode = false;
private Vector2 lockedTargetOffsetAngles = Vector2.zero;
private float baseHorizontalAngle = 0f;
private float baseVerticalAngle = 0f;
void Start()
{
if (target == null) return;
Vector3 direction = (transform.position - target.position).normalized;
horizontalAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
verticalAngle = Mathf.Asin(direction.y) * Mathf.Rad2Deg;
verticalAngle = Mathf.Clamp(verticalAngle, minPitch, maxPitch);
currentDistance = Vector3.Distance(transform.position, target.position);
}
void LateUpdate()
{
if (!target) return;
if (followGunMode && gun != null)
{
HandleFollowGunMode();
// Сохраняем текущие углы камеры
UpdateCameraAnglesFromPosition();
}
else
{
HandleManualMode();
}
}
void HandleManualMode()
{
// Ввод с мыши
if (Input.GetMouseButton(0))
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * 10f;
horizontalAngle += mouseX;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * 10f;
verticalAngle = Mathf.Clamp(verticalAngle - mouseY, minPitch, maxPitch);
}
// УБРАНО: Автоматическое следование за машиной при движении
// Камера больше не поворачивается автоматически
// Позиция камеры
Quaternion rotation = Quaternion.Euler(verticalAngle, horizontalAngle, 0f);
Vector3 direction = rotation * Vector3.back;
Vector3 desiredPosition = target.position + direction * currentDistance;
desiredPosition.y = target.position.y + height + Mathf.Sin(verticalAngle * Mathf.Deg2Rad) * currentDistance * 0.3f;
transform.position = Vector3.SmoothDamp(transform.position, desiredPosition, ref smoothPositionVelocity, 0.08f);
transform.LookAt(target.position + Vector3.up * 0.5f);
}
void HandleFollowGunMode()
{
Vector3 gunForward = gun.forward;
Vector3 gunPosition = gun.position;
if (PantsirRadarSystem.IsAnyTargetLocked && PantsirRadarSystem.LockedTargetPosition.HasValue)
{
Vector3 lockedTargetPos = PantsirRadarSystem.LockedTargetPosition.Value;
Vector3 directionToTarget = (lockedTargetPos - gunPosition).normalized;
baseHorizontalAngle = Mathf.Atan2(directionToTarget.x, directionToTarget.z) * Mathf.Rad2Deg;
baseVerticalAngle = Mathf.Asin(directionToTarget.y) * Mathf.Rad2Deg;
baseVerticalAngle = Mathf.Clamp(baseVerticalAngle, minPitch, maxPitch);
if (Input.GetMouseButton(0))
{
float mouseX = Input.GetAxis("Mouse X") * aimOffsetSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * aimOffsetSensitivity;
lockedTargetOffsetAngles += new Vector2(mouseX, mouseY);
lockedTargetOffsetAngles = Vector2.ClampMagnitude(lockedTargetOffsetAngles, maxAimOffsetDegrees);
}
float finalHorizontalAngle = baseHorizontalAngle + lockedTargetOffsetAngles.x;
float finalVerticalAngle = Mathf.Clamp(
baseVerticalAngle + lockedTargetOffsetAngles.y,
minPitch,
maxPitch
);
PantsirRadarSystem.AimOffset = lockedTargetOffsetAngles;
Quaternion gunRotation = Quaternion.Euler(finalVerticalAngle, finalHorizontalAngle, 0f);
Vector3 cameraDirection = gunRotation * Vector3.back;
Vector3 desiredPosition = gunPosition + cameraDirection * distance;
desiredPosition.y = gunPosition.y + height + Mathf.Sin(finalVerticalAngle * Mathf.Deg2Rad) * distance * 0.3f;
transform.position = Vector3.SmoothDamp(transform.position, desiredPosition, ref smoothPositionVelocity, 0.08f);
Vector3 aimPoint = lockedTargetPos;
Quaternion offsetRotation = Quaternion.Euler(
lockedTargetOffsetAngles.y,
lockedTargetOffsetAngles.x,
0f
);
Vector3 offsetDirection = offsetRotation * directionToTarget;
aimPoint = gunPosition + offsetDirection * Vector3.Distance(gunPosition, lockedTargetPos);
transform.LookAt(aimPoint);
PantsirRadarSystem.AimPoint = aimPoint;
}
else
{
if (Input.GetMouseButton(0))
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * 10f;
horizontalAngle += mouseX;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * 10f;
verticalAngle = Mathf.Clamp(verticalAngle - mouseY, minPitch, maxPitch);
}
Vector3 desiredPosition = gunPosition - gunForward * distance + Vector3.up * height;
transform.position = Vector3.SmoothDamp(transform.position, desiredPosition, ref smoothPositionVelocity, 0.08f);
transform.LookAt(gunPosition + gunForward * 1000f);
}
}
// Метод для сохранения текущих углов камеры
private void UpdateCameraAnglesFromPosition()
{
Vector3 directionFromTarget = (transform.position - target.position).normalized;
horizontalAngle = Mathf.Atan2(directionFromTarget.x, directionFromTarget.z) * Mathf.Rad2Deg;
verticalAngle = Mathf.Asin(directionFromTarget.y) * Mathf.Rad2Deg;
verticalAngle = Mathf.Clamp(verticalAngle, minPitch, maxPitch);
currentDistance = Vector3.Distance(transform.position, target.position);
}
public void SetFollowMode(bool enable)
{
followGunMode = enable;
lockedTargetOffsetAngles = Vector2.zero;
PantsirRadarSystem.AimOffset = Vector2.zero;
}
public void RotateToTarget(Vector3 targetPosition)
{
lockedTargetOffsetAngles = Vector2.zero;
if (gun != null)
{
Vector3 directionToTarget = (targetPosition - gun.position).normalized;
baseHorizontalAngle = Mathf.Atan2(directionToTarget.x, directionToTarget.z) * Mathf.Rad2Deg;
baseVerticalAngle = Mathf.Asin(directionToTarget.y) * Mathf.Rad2Deg;
baseVerticalAngle = Mathf.Clamp(baseVerticalAngle, minPitch, maxPitch);
Vector3 gunPosition = gun.position;
Quaternion rotation = Quaternion.Euler(baseVerticalAngle, baseHorizontalAngle, 0f);
Vector3 cameraDirection = rotation * Vector3.back;
transform.position = gunPosition + cameraDirection * distance;
transform.position += Vector3.up * height;
transform.LookAt(targetPosition);
}
else
{
transform.LookAt(targetPosition);
}
PantsirRadarSystem.AimOffset = Vector2.zero;
}
public void ResetAimOffset()
{
followGunMode = false;
lockedTargetOffsetAngles = Vector2.zero;
PantsirRadarSystem.AimOffset = Vector2.zero;
// Считаем углы напрямую из НАПРАВЛЕНИЯ ВЗГЛЯДА камеры, а не из её позиции
Vector3 forwardDir = transform.forward;
// Рассчитываем горизонтальный угол (куда смотрим по горизонтали)
horizontalAngle = Mathf.Atan2(forwardDir.x, forwardDir.z) * Mathf.Rad2Deg;
// Рассчитываем вертикальный угол (наклон)
// Инвертируем знак, так как forwardDir.y направлен вверх, а в HandleManualMode угол вычитается
verticalAngle = -Mathf.Asin(forwardDir.y) * Mathf.Rad2Deg;
verticalAngle = Mathf.Clamp(verticalAngle, minPitch, maxPitch);
if (target != null)
{
// Фиксируем текущую дистанцию до цели
currentDistance = Vector3.Distance(transform.position, target.position);
}
}
public Vector3 GetAimPoint()
{
Ray ray = new Ray(transform.position, transform.forward);
float maxDistance = 10000f;
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxDistance))
{
return hit.point;
}
return transform.position + transform.forward * maxDistance;
}
public bool IsInFollowMode()
{
return followGunMode;
}
}