using System; using System.Collections.Generic; using UnityEngine; namespace RR.Game2D.Behaviour { [RequireComponent(typeof(Collider2D))] [DisallowMultipleComponent] public sealed class EntitySpawnerZone : MonoBehaviour { [Header("Override Prefabs")] [Tooltip("Список префабов, которые будут спавниться вместо оригинальных префабов спавнера внутри этой зоны.")] [SerializeField] private EntitySpawner.SpawnPrefabEntry[] prefabs; [Header("Targeting")] [Tooltip("Фильтр по имени GameObject спавнера. Если не пусто, зона будет переопределять только те спавнеры, чье имя содержит этот текст (без учета регистра).")] [SerializeField] private string spawnerNameFilter = "Enemy"; private Collider2D _collider; // Статический список всех активных зон на сцене для быстрого поиска public static readonly List ActiveZones = new(); public EntitySpawner.SpawnPrefabEntry[] Prefabs => prefabs; private void Awake() { _collider = GetComponent(); // Убеждаемся, что коллайдер является триггером, чтобы не вызывать физических коллизий с персонажами if (_collider != null) { _collider.isTrigger = true; } } private void OnEnable() { ActiveZones.Add(this); } private void OnDisable() { ActiveZones.Remove(this); } /// /// Проверяет, подходит ли данный спавнер под критерии фильтрации зоны. /// public bool MatchesSpawner(EntitySpawner spawner) { if (spawner == null) return false; if (string.IsNullOrEmpty(spawnerNameFilter)) return true; return spawner.gameObject.name.IndexOf(spawnerNameFilter, StringComparison.OrdinalIgnoreCase) >= 0; } /// /// Проверяет, находится ли мировая точка внутри коллайдера зоны. /// public bool IsPointInside(Vector3 point) { if (_collider == null) { _collider = GetComponent(); } if (_collider == null) return false; // Если это BoxCollider2D, выполняем точную математическую проверку в локальных координатах. // Это работает надежно в любой момент (даже до первого физического обновления) и не зависит от Z-координаты. if (_collider is BoxCollider2D box) { Vector3 localPoint = transform.InverseTransformPoint(point); return Mathf.Abs(localPoint.x - box.offset.x) <= box.size.x * 0.5f && Mathf.Abs(localPoint.y - box.offset.y) <= box.size.y * 0.5f; } return _collider.OverlapPoint(point); } private void OnDrawGizmos() { if (_collider == null) { _collider = GetComponent(); } if (_collider == null) return; // Рисуем оранжевую рамку зоны замены в редакторе Gizmos.color = new Color(1f, 0.5f, 0f, 0.2f); if (_collider is BoxCollider2D box) { Vector3 position = transform.TransformPoint(box.offset); Vector3 size = Vector3.Scale(box.size, transform.lossyScale); Gizmos.DrawCube(position, size); Gizmos.color = new Color(1f, 0.5f, 0f, 0.8f); Gizmos.DrawWireCube(position, size); } else { // Для других типов коллайдеров рисуем сферу в центре объекта Gizmos.DrawSphere(transform.position, 0.5f); } } } }