Загрузка данных
using UnityEngine;
using UnityEngine.UI;
public class GunSightUI : MonoBehaviour
{
[Header("Ссылки")]
[SerializeField] private Camera worldSpaceCamera;
[SerializeField] private Transform gunMuzzle; // Точка стрельбы (дуло орудия)
[SerializeField] private RectTransform sightUI; // UI элемент прицела (крестик)
[SerializeField] private Canvas parentCanvas; // Canvas, на котором находится прицел
[Header("Настройки")]
[SerializeField] private float maxRaycastDistance = 2000f; // Максимальная дистанция (2 км)
[SerializeField] private LayerMask raycastLayerMask = ~0; // Слои для райкаста
[SerializeField] private float projectileSpeed = 1000f; // Скорость снаряда м/с
[Header("Настройки отображения")]
[SerializeField] private float sightScale = 1.0f;
// Компоненты
private RectTransform rectTransform;
private Image sightImage;
// Данные о текущей точке прицеливания
private Vector3 currentAimPointWorld = Vector3.zero;
private float currentAimDistance = 0f;
void Start()
{
// Получаем компоненты
if (sightUI != null)
rectTransform = sightUI;
else
rectTransform = GetComponent<RectTransform>();
sightImage = GetComponent<Image>();
if (worldSpaceCamera == null)
worldSpaceCamera = Camera.main;
if (parentCanvas == null)
parentCanvas = GetComponentInParent<Canvas>();
if (gunMuzzle == null)
{
// Пытаемся найти точку стрельбы автоматически
PantsirRadarSystem radarSystem = FindObjectOfType<PantsirRadarSystem>();
if (radarSystem != null && radarSystem.gun != null)
{
gunMuzzle = radarSystem.gun;
}
}
}
void Update()
{
UpdateSightPosition();
}
void UpdateSightPosition()
{
if (worldSpaceCamera == null || rectTransform == null || gunMuzzle == null)
return;
// Получаем расстояние до точки прицеливания
float aimDistance = CalculateAimDistance();
// Направление от точки выстрела через центр экрана
Vector3 rayDirection = worldSpaceCamera.transform.forward;
Vector3 rayOrigin = gunMuzzle.position;
// Точка прицеливания на рассчитанной дистанции
Vector3 aimPoint = rayOrigin + rayDirection * aimDistance;
// Преобразуем мировую точку в экранные координаты
Vector3 screenPoint = worldSpaceCamera.WorldToScreenPoint(aimPoint);
// Проверяем, находится ли точка перед камерой
if (screenPoint.z > 0)
{
// Преобразуем экранные координаты в координаты канваса
Vector2 canvasPosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
parentCanvas.transform as RectTransform,
screenPoint,
parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : worldSpaceCamera,
out canvasPosition
);
// Устанавливаем позицию прицела
rectTransform.localPosition = canvasPosition;
// Показываем прицел
if (sightImage != null)
sightImage.enabled = true;
currentAimPointWorld = aimPoint;
currentAimDistance = aimDistance;
}
else
{
// Скрываем прицел, если точка позади камеры
if (sightImage != null)
sightImage.enabled = false;
}
}
float CalculateAimDistance()
{
Vector3 rayOrigin = gunMuzzle.position;
Vector3 rayDirection = worldSpaceCamera.transform.forward;
// Проверяем, есть ли захваченная цель
if (PantsirRadarSystem.IsAnyTargetLocked && PantsirRadarSystem.LockedTargetPosition.HasValue)
{
Vector3 lockedTargetPos = PantsirRadarSystem.LockedTargetPosition.Value;
// Рассчитываем точку упреждения
Vector3 leadPoint = CalculateLeadPoint(lockedTargetPos);
// Возвращаем расстояние до точки упреждения
float distanceToLeadPoint = Vector3.Distance(rayOrigin, leadPoint);
// Ограничиваем максимальной дистанцией
return Mathf.Min(distanceToLeadPoint, maxRaycastDistance);
}
// Если нет захваченной цели - делаем райкаст
RaycastHit hit;
if (Physics.Raycast(rayOrigin, rayDirection, out hit, maxRaycastDistance, raycastLayerMask))
{
// Если луч уперся - возвращаем расстояние до точки попадания
return hit.distance;
}
else
{
// Если луч не уперся - возвращаем максимальную дистанцию
return maxRaycastDistance;
}
}
Vector3 CalculateLeadPoint(Vector3 targetPosition)
{
// Получаем цель и её скорость
GameObject[] enemies = GameObject.FindGameObjectsWithTag("AirEnemy");
Rigidbody targetRigidbody = null;
foreach (GameObject enemy in enemies)
{
if (Vector3.Distance(enemy.transform.position, targetPosition) < 10f)
{
targetRigidbody = enemy.GetComponent<Rigidbody>();
break;
}
}
if (targetRigidbody == null)
return targetPosition;
// Получаем скорость цели
Vector3 targetVelocity = targetRigidbody.linearVelocity;
// Рассчитываем дистанцию до цели
float distanceToTarget = Vector3.Distance(gunMuzzle.position, targetPosition);
// Время полета снаряда
float timeToTarget = distanceToTarget / projectileSpeed;
// Точка упреждения = позиция цели + скорость цели * время полета
Vector3 leadPoint = targetPosition + targetVelocity * timeToTarget;
return leadPoint;
}
// Публичный метод для получения текущей точки прицеливания
public Vector3 GetCurrentAimPoint()
{
return currentAimPointWorld;
}
// Публичный метод для получения дистанции до точки прицеливания
public float GetCurrentAimDistance()
{
return currentAimDistance;
}
// Метод для настройки масштаба прицела
public void SetSightScale(float scale)
{
sightScale = scale;
if (rectTransform != null)
{
rectTransform.localScale = Vector3.one * sightScale;
}
}
// Метод для отображения/скрытия прицела
public void SetSightVisible(bool visible)
{
if (sightImage != null)
{
sightImage.enabled = visible;
}
}
}