sea-battle-vr/Assets/Scripts/Gameplay/UI/VrUI/ProjectileWarningView.cs

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