Загрузка данных


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()
    {
        lockedTargetOffsetAngles = Vector2.zero;
        PantsirRadarSystem.AimOffset = Vector2.zero;
    }

    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;
    }
}

using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class PantsirRadarSystem : MonoBehaviour
{
    [Header("Ссылки на объекты")]
    public Transform turret;          
    public Transform searchAntenna;  
    public Camera worldSpaceCamera;  
    public Transform gun;

    [Header("Настройки РЛС")]
    public float radarRange = 15000f;
    public float antennaRotationSpeed = 90f;
    public float scanHalfWidth = 5f;
    public float targetTimeout = 4f;

    [Header("Настройки Наведения")]
    public float turretMaxSpeed = 45f;
    public float gunMaxSpeed = 30f;
    
    [Header("Ограничения орудия")]
    public float minElevationAngle = 0f;
    public float maxElevationAngle = 85f;

    [Header("Интерфейс (UI)")]
    public RectTransform radarBlipPrefab;
    public RectTransform radarCenterPoint;
    public float radarUIRadius = 150f;
    public RectTransform lockFrameUI;
    public GameObject lockMarkerPrefab;
    public TextMeshProUGUI distanceText;
    public TextMeshProUGUI closureSpeedText;

    // Статическое свойство для камеры
    public static bool IsAnyTargetLocked { get; private set; }
    public static Vector3? LockedTargetPosition { get; private set; }
    public static Vector3 AimPoint { get; set; }
    public static Vector2 AimOffset { get; set; }

    // Логика и списки
    private float currentAntennaAngle = 0f;
    private List<RadarTargetData> detectedTargets = new List<RadarTargetData>();
    private int lockedTargetIndex = -1;
    private RadarTargetData lockedTarget = null;
    private GameObject currentLockMarkerInstance;
    private Rigidbody myRigidbody;

    // Для управления камерой
    private SoftVehicleCamera cameraScript;
    private bool isFirstFrameOfLock = false;
    
    // Список заблокированных целей
    private List<Transform> blockedTargets = new List<Transform>();
    public float targetBlockTime = 10f;

    public class RadarTargetData
    {
        public Transform targetTransform;
        public Rigidbody targetRigidbody;
        public RectTransform blipUI;
        public float lastDetectedTime;
        public float azimuth;
        public float distance;
    }

    void Start()
    {
        myRigidbody = GetComponentInParent<Rigidbody>();
        cameraScript = FindObjectOfType<SoftVehicleCamera>();
        
        AimOffset = Vector2.zero;
        IsAnyTargetLocked = false;
        LockedTargetPosition = null;
        AimPoint = Vector3.zero;
    }

    void FixedUpdate()
    {
        RotateSearchAntenna();
        ScanForAirEnemies();
        UpdateRadarUI();
        HandleTurretTracking();
        UpdateLockTexts();
        UpdateLockedTargetPosition();
    }

    void UpdateLockedTargetPosition()
    {
        if (lockedTarget != null && lockedTarget.targetTransform != null)
        {
            LockedTargetPosition = lockedTarget.targetTransform.position;
            IsAnyTargetLocked = true;
        }
        else
        {
            LockedTargetPosition = null;
            IsAnyTargetLocked = false;
        }
    }

    void RotateSearchAntenna()
    {
        currentAntennaAngle += antennaRotationSpeed * Time.fixedDeltaTime;
        currentAntennaAngle %= 360f;
        searchAntenna.rotation = Quaternion.Euler(0f, currentAntennaAngle, 0f);
    }

    void ScanForAirEnemies()
    {
        GameObject[] enemies = GameObject.FindGameObjectsWithTag("AirEnemy");
        Vector3 antennaForward = searchAntenna.forward;

        foreach (GameObject enemy in enemies)
        {
            if (IsTargetBlocked(enemy.transform)) continue;
        
            Vector3 toTarget = enemy.transform.position - searchAntenna.position;
            float distance = toTarget.magnitude;

            if (distance > radarRange) continue;

            Vector3 toTargetXZ = new Vector3(toTarget.x, 0f, toTarget.z).normalized;
            Vector3 antennaForwardXZ = new Vector3(antennaForward.x, 0f, antennaForward.z).normalized;

            float angleToTarget = Vector3.Angle(antennaForwardXZ, toTargetXZ);

            if (angleToTarget <= scanHalfWidth)
            {
                UpdateOrAddTarget(enemy, distance, toTargetXZ);
            }
        }

        CleanupOldTargets();
    }

    // Метод для срыва захвата с цели
    public void LoseTarget(Transform targetTransform)
    {
        if (targetTransform == null) return;
    
        // Если это текущая захваченная цель - сбрасываем захват
        if (lockedTarget != null && lockedTarget.targetTransform == targetTransform)
        {
            // Сбрасываем захват
            lockedTarget = null;
            lockedTargetIndex = -1;
            isFirstFrameOfLock = false;
            AimOffset = Vector2.zero;
        
            if (currentLockMarkerInstance != null)
            {
                Destroy(currentLockMarkerInstance);
                currentLockMarkerInstance = null;
            }
        
            // ВОЗВРАЩАЕМ КАМЕРУ В ОБЫЧНЫЙ РЕЖИМ
            if (cameraScript != null)
            {
                cameraScript.SetFollowMode(false);
                cameraScript.ResetAimOffset();
            }
        }
    
        // Добавляем цель в список заблокированных
        if (!blockedTargets.Contains(targetTransform))
        {
            blockedTargets.Add(targetTransform);
            StartCoroutine(UnblockTargetAfterDelay(targetTransform, targetBlockTime));
        }
    
        // Убираем цель из списка обнаруженных
        RadarTargetData targetToRemove = detectedTargets.Find(t => t.targetTransform == targetTransform);
        if (targetToRemove != null)
        {
            if (targetToRemove.blipUI != null) Destroy(targetToRemove.blipUI.gameObject);
            detectedTargets.Remove(targetToRemove);
        }
    }

    // Корутина для разблокировки цели
    private System.Collections.IEnumerator UnblockTargetAfterDelay(Transform targetTransform, float delay)
    {
        yield return new WaitForSeconds(delay);
        
        if (targetTransform != null)
        {
            blockedTargets.Remove(targetTransform);
            Debug.Log($"Цель {targetTransform.name} снова доступна для захвата");
        }
    }

    // Метод для проверки, заблокирована ли цель
    public bool IsTargetBlocked(Transform targetTransform)
    {
        return blockedTargets.Contains(targetTransform);
    }

    // Метод для мгновенной разблокировки всех целей
    public void UnblockAllTargets()
    {
        blockedTargets.Clear();
        Debug.Log("Все цели разблокированы");
    }

    void UpdateOrAddTarget(GameObject enemy, float distance, Vector3 toTargetXZ)
    {
        RadarTargetData existing = detectedTargets.Find(t => t.targetTransform == enemy.transform);
        
        float azimuth = Mathf.Atan2(toTargetXZ.x, toTargetXZ.z) * Mathf.Rad2Deg;
        if (azimuth < 0) azimuth += 360f;

        if (existing != null)
        {
            existing.lastDetectedTime = Time.time;
            existing.distance = distance;
            existing.azimuth = azimuth;
        }
        else
        {
            RadarTargetData newData = new RadarTargetData
            {
                targetTransform = enemy.transform,
                targetRigidbody = enemy.GetComponent<Rigidbody>(),
                lastDetectedTime = Time.time,
                distance = distance,
                azimuth = azimuth
            };

            if (radarBlipPrefab != null && radarCenterPoint != null)
            {
                newData.blipUI = Instantiate(radarBlipPrefab, radarCenterPoint);
            }
            detectedTargets.Add(newData);
        }
    }

    void UpdateRadarUI()
    {
        foreach (var target in detectedTargets)
        {
            if (target.blipUI == null) continue;

            float angleRad = (90f - target.azimuth) * Mathf.Deg2Rad;
            float normalizedDist = target.distance / radarRange;
            float currentRadius = normalizedDist * radarUIRadius;

            float x = Mathf.Cos(angleRad) * currentRadius;
            float y = Mathf.Sin(angleRad) * currentRadius;

            target.blipUI.localPosition = new Vector3(x, y, 0f);

            CanvasGroup cg = target.blipUI.GetComponent<CanvasGroup>();
            if (cg != null)
            {
                float timePassed = Time.time - target.lastDetectedTime;
                cg.alpha = Mathf.Clamp01(1f - (timePassed / targetTimeout));
            }
        }
    }

    void HandleTurretTracking()
    {
        Vector3 aimPoint;
        bool hasTarget = lockedTarget != null && lockedTarget.targetTransform != null;
        
        // Всегда следуем за камерой, независимо от захвата
        if (cameraScript != null)
        {
            aimPoint = cameraScript.GetAimPoint();
            AimPoint = aimPoint;
        }
        else
        {
            aimPoint = transform.position + transform.forward * 1000f;
            AimPoint = aimPoint;
        }

        // Вращаем башню к точке прицеливания камеры
        Vector3 directionToTargetLocal = turret.InverseTransformDirection(aimPoint - turret.position);
        float targetAzimuthAngle = Mathf.Atan2(directionToTargetLocal.x, directionToTargetLocal.z) * Mathf.Rad2Deg;
        
        Quaternion targetTurretLocalRotation = turret.localRotation * Quaternion.Euler(0f, targetAzimuthAngle, 0f);
        turret.localRotation = Quaternion.RotateTowards(
            turret.localRotation, 
            targetTurretLocalRotation, 
            turretMaxSpeed * Time.fixedDeltaTime
        );

        // Вращаем орудие к точке прицеливания камеры
        if (gun != null)
        {
            Vector3 directionToTargetTurretLocal = turret.InverseTransformDirection(aimPoint - gun.position);
            float targetElevationAngle = Mathf.Atan2(directionToTargetTurretLocal.y, directionToTargetTurretLocal.z) * Mathf.Rad2Deg;
            targetElevationAngle = Mathf.Clamp(targetElevationAngle, -minElevationAngle, maxElevationAngle);
            
            Quaternion targetGunLocalRotation = Quaternion.Euler(-targetElevationAngle, 0f, 0f);
            
            gun.localRotation = Quaternion.RotateTowards(
                gun.localRotation, 
                targetGunLocalRotation, 
                gunMaxSpeed * Time.fixedDeltaTime
            );
        }

        // Обновляем UI рамку захвата
        if (lockFrameUI != null)
        {
            if (hasTarget && worldSpaceCamera != null && lockedTarget.targetTransform != null)
            {
                Vector3 screenPoint = worldSpaceCamera.WorldToScreenPoint(lockedTarget.targetTransform.position);

                if (screenPoint.z > 0)
                {
                    lockFrameUI.gameObject.SetActive(true);
                    lockFrameUI.position = screenPoint;
                }
                else
                {
                    lockFrameUI.gameObject.SetActive(false);
                }
            }
            else
            {
                lockFrameUI.gameObject.SetActive(false);
            }
        }
    }

    void UpdateLockTexts()
    {
        if (lockedTarget == null || lockedTarget.targetTransform == null)
        {
            if (distanceText) distanceText.text = "РАДИУС: ИСК";
            if (closureSpeedText) closureSpeedText.text = "СБЛИЖЕНИЕ: ---";
            return;
        }

        float dist = Vector3.Distance(transform.position, lockedTarget.targetTransform.position);
        if (distanceText) distanceText.text = $"ДАЛЬНОСТЬ: {(dist / 1000f):F2} км";

        Vector3 myVelocity = myRigidbody != null ? myRigidbody.linearVelocity : Vector3.zero;
        Vector3 targetVelocity = lockedTarget.targetRigidbody != null ? lockedTarget.targetRigidbody.linearVelocity : Vector3.zero;
        
        Vector3 relativeVelocity = myVelocity - targetVelocity; 
        Vector3 directionToTarget = (lockedTarget.targetTransform.position - transform.position).normalized;

        float closureSpeed = Vector3.Dot(relativeVelocity, directionToTarget);

        if (closureSpeedText)
        {
            float closureSpeedKMH = closureSpeed * 3.6f;
            closureSpeedText.text = $"СБЛИЖЕНИЕ: {closureSpeedKMH:F0} км/ч";
        }
    }

    public void Button_LockTarget()
    {
        if (detectedTargets.Count == 0) return;
    
        RadarTargetData targetToLock = null;
        foreach (var target in detectedTargets)
        {
            if (!IsTargetBlocked(target.targetTransform))
            {
                targetToLock = target;
                break;
            }
        }
    
        if (targetToLock == null)
        {
            Debug.Log("Нет доступных целей для захвата");
            return;
        }
    
        lockedTargetIndex = detectedTargets.IndexOf(targetToLock);
        lockedTarget = targetToLock;
        isFirstFrameOfLock = false;
        AimOffset = Vector2.zero;
    
        if (cameraScript != null && lockedTarget.targetTransform != null)
        {
            cameraScript.RotateToTarget(lockedTarget.targetTransform.position);
            cameraScript.SetFollowMode(true);
        }
    }

    public void Button_NextTarget()
    {
        if (detectedTargets.Count <= 1) return;

        int startIndex = lockedTargetIndex;
        int nextIndex = (lockedTargetIndex + 1) % detectedTargets.Count;
    
        while (nextIndex != startIndex)
        {
            if (!IsTargetBlocked(detectedTargets[nextIndex].targetTransform))
            {
                if (currentLockMarkerInstance != null) Destroy(currentLockMarkerInstance);
            
                lockedTargetIndex = nextIndex;
                lockedTarget = detectedTargets[lockedTargetIndex];
                isFirstFrameOfLock = false;
                AimOffset = Vector2.zero;
            
                if (cameraScript != null && lockedTarget.targetTransform != null)
                {
                    cameraScript.RotateToTarget(lockedTarget.targetTransform.position);
                    cameraScript.SetFollowMode(true);
                }
                return;
            }
            nextIndex = (nextIndex + 1) % detectedTargets.Count;
        }
    
        Debug.Log("Нет других доступных целей");
    }
    
    public void Button_ClearLock()
    {
        lockedTarget = null;
        lockedTargetIndex = -1;
        isFirstFrameOfLock = false;
        
        if (currentLockMarkerInstance != null)
        {
            Destroy(currentLockMarkerInstance);
            currentLockMarkerInstance = null;
        }
        
        // НЕ ВЫЗЫВАЕМ SetFollowMode(false)!
        // Камера остаётся в текущем положении
    }

    void CleanupOldTargets()
    {
        // Очищаем заблокированные цели
        for (int i = blockedTargets.Count - 1; i >= 0; i--)
        {
            if (blockedTargets[i] == null)
            {
                blockedTargets.RemoveAt(i);
            }
        }
        
        for (int i = detectedTargets.Count - 1; i >= 0; i--)
        {
            var target = detectedTargets[i];
            if (target.targetTransform == null || (Time.time - target.lastDetectedTime) > targetTimeout)
            {
                if (target.blipUI != null) Destroy(target.blipUI.gameObject);
                if (lockedTarget == target)
                {
                    lockedTarget = null;
                    lockedTargetIndex = -1;
                    isFirstFrameOfLock = false;
                    if (currentLockMarkerInstance != null) Destroy(currentLockMarkerInstance);
                    // НЕ ВЫЗЫВАЕМ SetFollowMode(false)!
                }
                detectedTargets.RemoveAt(i);
            }
        }
    }
}