119 lines
4.8 KiB
C#
119 lines
4.8 KiB
C#
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
public class ProjectileWarningView : MonoBehaviour
|
|
{
|
|
[SerializeField] private ProjectileWarning warningPrefab;
|
|
[SerializeField] private Transform uiCircleCenter; // Центр круга UI
|
|
[SerializeField] private float warningRadius = 200f; // Радиус круга на UI
|
|
[SerializeField] private float maxWarningDistance = 1000f; // Максимальная дистанция для отображения
|
|
|
|
private GameObject player;
|
|
|
|
private Dictionary<AbstractProjectile, ProjectileWarning> activeWarnings = new Dictionary<AbstractProjectile, ProjectileWarning>();
|
|
|
|
public void Initialize()
|
|
{
|
|
G.DangersModel.OnProjectileSpawned += OnProjectileSpawned;
|
|
player = G.PlayerStateModel.PlayerComponent.gameObject;
|
|
}
|
|
|
|
private void OnProjectileSpawned(AbstractProjectile projectile)
|
|
{
|
|
if (projectile == null) return;
|
|
if (projectile.Owner == player) return;
|
|
|
|
|
|
// Создаем предупреждение для снаряда
|
|
ProjectileWarning warning = Instantiate(warningPrefab, transform);
|
|
activeWarnings.Add(projectile, warning);
|
|
|
|
// Устанавливаем начальную дистанцию
|
|
float distance = Vector3.Distance(projectile.transform.position, CamerasManager.VR_Camera.transform.position);
|
|
warning.SetDistance(distance);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (G.DangersModel != null)
|
|
{
|
|
G.DangersModel.OnProjectileSpawned -= OnProjectileSpawned;
|
|
}
|
|
}
|
|
|
|
void LateUpdate()
|
|
{
|
|
Vector3 cameraPosition = CamerasManager.VR_Camera.transform.position;
|
|
Vector3 cameraDirection = CamerasManager.VR_Camera.transform.forward;
|
|
|
|
List<AbstractProjectile> projectilesToRemove = new List<AbstractProjectile>();
|
|
|
|
foreach (var warningPair in activeWarnings)
|
|
{
|
|
AbstractProjectile projectile = warningPair.Key;
|
|
ProjectileWarning warning = warningPair.Value;
|
|
|
|
// Проверяем, существует ли еще снаряд
|
|
if (projectile == null)
|
|
{
|
|
projectilesToRemove.Add(projectile);
|
|
Destroy(warning.gameObject);
|
|
continue;
|
|
}
|
|
|
|
// Обновляем дистанцию
|
|
float distance = Vector3.Distance(projectile.transform.position, cameraPosition);
|
|
|
|
// Вычисляем направление от игрока к снаряду
|
|
Vector3 directionToProjectile = (projectile.transform.position - G.PlayerStateModel.PlayerComponent.transform.position).normalized;
|
|
|
|
// Проверяем, находится ли снаряд позади игрока (dot < 0)
|
|
float dotProduct = Vector3.Dot(Vector3.forward, directionToProjectile);
|
|
bool isBehindPlayer = dotProduct < 0;
|
|
|
|
// Показываем предупреждение только если снаряд впереди и в пределах дистанции
|
|
if (!isBehindPlayer && distance <= maxWarningDistance)
|
|
{
|
|
warning.gameObject.SetActive(true);
|
|
warning.SetDistance(Mathf.RoundToInt(distance));
|
|
|
|
// Рассчитываем угол и позицию на UI
|
|
float angle = CalculateAngle(projectile.transform.position, cameraPosition, cameraDirection);
|
|
Vector2 uiPosition = GetUIPositionFromAngle(angle);
|
|
warning.GetComponent<RectTransform>().anchoredPosition = uiPosition;
|
|
warning.SetAngle(angle);
|
|
}
|
|
else
|
|
{
|
|
// Снаряд позади или слишком далеко - скрываем предупреждение
|
|
warning.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// Удаляем уничтоженные снаряды
|
|
foreach (var projectile in projectilesToRemove)
|
|
{
|
|
activeWarnings.Remove(projectile);
|
|
}
|
|
}
|
|
|
|
float CalculateAngle(Vector3 projectilePosition, Vector3 cameraPosition, Vector3 cameraDirection)
|
|
{
|
|
Vector3 dirToProjectile = projectilePosition - cameraPosition;
|
|
dirToProjectile.y = 0; // Игнорируем вертикальную составляющую
|
|
cameraDirection.y = 0;
|
|
|
|
return Vector3.SignedAngle(dirToProjectile, cameraDirection, Vector3.up);
|
|
}
|
|
|
|
Vector2 GetUIPositionFromAngle(float angle)
|
|
{
|
|
float radians = -angle * Mathf.Deg2Rad;
|
|
|
|
// Вычисляем позицию на круге
|
|
float x = Mathf.Sin(radians) * warningRadius;
|
|
float y = Mathf.Cos(radians) * warningRadius;
|
|
|
|
return new Vector2(x, y);
|
|
}
|
|
} |