using System.Collections.Generic; using UnityEngine; [DisallowMultipleComponent] public sealed class MapTargetController : MonoBehaviour { [Header("Random Wave Settings")] [SerializeField, Min(0)] private int targetsPerWave = 5; [SerializeField] private TargetConfig[] randomTargetConfigs = System.Array.Empty(); [Header("Current Wave (Runtime)")] [SerializeField, Min(0)] private int currentWave; [SerializeField] private List currentWaveTargets = new(); private readonly List pooledTargets = new(); private MapCoordinateSystem coordinateSystem; private Transform targetParent; private MapPlayer player; private bool isConfigured; public IReadOnlyList Targets => currentWaveTargets; public int CurrentWave => currentWave; public int TargetsPerWave => targetsPerWave; private void Start() { if (currentWave == 0) StartNextWave(); } private void OnValidate() { targetsPerWave = Mathf.Max(0, targetsPerWave); currentWave = Mathf.Max(0, currentWave); } public void Configure( MapCoordinateSystem newCoordinateSystem, Transform newTargetParent, MapPlayer newPlayer) { coordinateSystem = newCoordinateSystem; targetParent = newTargetParent != null ? newTargetParent : transform; player = newPlayer; isConfigured = coordinateSystem != null && coordinateSystem.HasValidCorners(); pooledTargets.Clear(); foreach (MapTarget existingTarget in targetParent.GetComponentsInChildren(true)) { existingTarget.SetVisualsVisible(false); existingTarget.gameObject.SetActive(false); pooledTargets.Add(existingTarget); } } public bool StartNextWave() { if (!isConfigured || !HasValidTargetConfig()) { Debug.LogWarning("Target controller has no coordinate system or valid TargetConfig.", this); return false; } RetireCurrentWave(); currentWave++; for (int index = 0; index < targetsPerWave; index++) { TargetConfig config = GetRandomValidConfig(); if (config == null) break; MapTarget target = GetPooledTarget(config); if (target == null) target = Instantiate(config.TargetPrefab, targetParent); target.name = $"Wave {currentWave} - {config.name} - {index + 1}"; target.Configure(config, coordinateSystem, GetRandomCoordinates(), player); target.SetVisualsVisible(false); target.gameObject.SetActive(true); currentWaveTargets.Add(target); } return currentWaveTargets.Count > 0 || targetsPerWave == 0; } public void CreateAndPlaceTargets() { StartNextWave(); } public void SetTargetVisualsVisible(bool isVisible) { foreach (MapTarget target in currentWaveTargets) { if (target != null) target.SetVisualsVisible(isVisible); } } public MapTarget GetTarget(int index) { return index >= 0 && index < currentWaveTargets.Count ? currentWaveTargets[index] : null; } private void RetireCurrentWave() { foreach (MapTarget target in currentWaveTargets) { if (target == null) continue; target.SetVisualsVisible(false); target.gameObject.SetActive(false); if (!pooledTargets.Contains(target)) pooledTargets.Add(target); } currentWaveTargets.Clear(); } private MapTarget GetPooledTarget(TargetConfig config) { for (int index = pooledTargets.Count - 1; index >= 0; index--) { MapTarget candidate = pooledTargets[index]; if (candidate == null) { pooledTargets.RemoveAt(index); continue; } if (candidate.GetType() != config.TargetPrefab.GetType()) continue; pooledTargets.RemoveAt(index); return candidate; } return null; } private bool HasValidTargetConfig() { return GetRandomValidConfig() != null; } private TargetConfig GetRandomValidConfig() { if (randomTargetConfigs == null || randomTargetConfigs.Length == 0) return null; int startIndex = Random.Range(0, randomTargetConfigs.Length); for (int offset = 0; offset < randomTargetConfigs.Length; offset++) { TargetConfig config = randomTargetConfigs[(startIndex + offset) % randomTargetConfigs.Length]; if (config != null && config.TargetPrefab != null) return config; } return null; } private static Vector2 GetRandomCoordinates() { float maximum = MapCoordinateSystem.CoordinateMaximum; return new Vector2(Random.Range(0f, maximum), Random.Range(0f, maximum)); } }