using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyTargetManager : MonoBehaviour { [Header("Target Points")] [SerializeField] private List targetPoints = new List(); [Header("Active Target Chance")] [SerializeField] [Range(0f, 1f)] private float twoTargetsChance = 0.25f; [Header("Switch Timing")] [SerializeField] private float minSwitchDelay = 15f; [SerializeField] private float maxSwitchDelay = 25f; [Header("Target Selection")] [SerializeField] [Min(0f)] private float equalDistanceTolerance = 0.1f; //In Unity-Einheiten! // Wird ausgelöst, wenn sich die aktiven Ziele ändern. public event Action OnTargetsChanged; private void Start() { if (targetPoints.Count == 0) { Debug.LogError( "EnemyTargetManager: Keine Target Points zugewiesen!", this ); return; } if (targetPoints.Count < 2) { Debug.LogWarning( "EnemyTargetManager: Es sind weniger als 2 Target Points vorhanden. Zwei aktive Targets sind dadurch nicht möglich.", this ); } if (minSwitchDelay > maxSwitchDelay) { Debug.LogWarning( "EnemyTargetManager: minSwitchDelay ist größer als maxSwitchDelay. Werte werden getauscht.", this ); float temp = minSwitchDelay; minSwitchDelay = maxSwitchDelay; maxSwitchDelay = temp; } // Zu Beginn zufällig Targets aktivieren. SetRandomActiveTargets(); // Danach regelmäßig wechseln. StartCoroutine(TargetSwitchLoop()); } private IEnumerator TargetSwitchLoop() { while (true) { float delay = UnityEngine.Random.Range( minSwitchDelay, maxSwitchDelay ); yield return new WaitForSeconds(delay); SetRandomActiveTargets(); } } private void SetRandomActiveTargets() { // Zuerst alle Targets deaktivieren. foreach (Transform target in targetPoints) { if (target != null) { target.gameObject.SetActive(false); } } // Entscheiden, ob 1 oder 2 Targets aktiv sein sollen. int activeTargetCount = 1; if (targetPoints.Count >= 2 && UnityEngine.Random.value < twoTargetsChance) { activeTargetCount = 2; } // Alle gültigen Targets sammeln. List availableTargets = new List(); foreach (Transform target in targetPoints) { if (target != null) { availableTargets.Add(target); } } // Zufällige Targets aktivieren. for (int i = 0; i < activeTargetCount; i++) { int randomIndex = UnityEngine.Random.Range( 0, availableTargets.Count ); Transform target = availableTargets[randomIndex]; target.gameObject.SetActive(true); // Verhindert doppelte Auswahl. availableTargets.RemoveAt(randomIndex); } // Alle Gegner informieren. OnTargetsChanged?.Invoke(); } public Transform GetClosestActiveTarget(Vector3 position) { List closestTargets = new List(); float closestDistance = float.MaxValue; foreach (Transform target in targetPoints) { if (target == null || !target.gameObject.activeInHierarchy) { continue; } // Tatsächliche Entfernung in Unity-Einheiten. float distance = Vector3.Distance( position, target.position ); // Eindeutig näher als die bisher gefundenen Targets. if (distance < closestDistance - equalDistanceTolerance) { closestDistance = distance; closestTargets.Clear(); closestTargets.Add(target); } // Innerhalb der eingestellten Toleranz: // Dieses Target gilt als gleich nah. else if (Mathf.Abs( distance - closestDistance ) <= equalDistanceTolerance) { closestTargets.Add(target); } } if (closestTargets.Count == 0) { return null; } // Bei mehreren gleich nahen Targets zufällig wählen. int randomIndex = UnityEngine.Random.Range( 0, closestTargets.Count ); return closestTargets[randomIndex]; } }