Gegnerpathing Logik

This commit is contained in:
2026-10-07 14:40:02 +02:00
parent 0a801ed82c
commit 583957d993
6 changed files with 1276 additions and 33 deletions
+45 -6
View File
@@ -15,9 +15,10 @@ public class Enemy : MonoBehaviour, IMovementDirection
// Wird von CharacterRotation verwendet.
public Vector2 MovementDirection { get; private set; }
private void Start()
private void Awake()
{
targetManager = FindFirstObjectByType<EnemyTargetManager>();
targetManager =
FindFirstObjectByType<EnemyTargetManager>();
if (targetManager == null)
{
@@ -25,9 +26,31 @@ public class Enemy : MonoBehaviour, IMovementDirection
"Enemy: Kein EnemyTargetManager gefunden!",
this
);
return;
}
}
private void OnEnable()
{
if (targetManager != null)
{
targetManager.OnTargetsChanged +=
SelectClosestTarget;
}
}
private void OnDisable()
{
if (targetManager != null)
{
targetManager.OnTargetsChanged -=
SelectClosestTarget;
}
}
private void Start()
{
if (targetManager == null)
return;
SelectClosestTarget();
}
@@ -37,22 +60,27 @@ public class Enemy : MonoBehaviour, IMovementDirection
if (targetManager == null)
return;
// Kein aktuelles Ziel vorhanden.
if (currentTarget == null)
{
MovementDirection = Vector2.zero;
SelectClosestTarget();
return;
}
// Falls das Ziel deaktiviert wurde:
// Das aktuelle Ziel wurde deaktiviert.
if (!currentTarget.gameObject.activeInHierarchy)
{
SelectClosestTarget();
return;
}
MoveTowardsTarget();
// Ziel erreicht.
if (HasReachedTarget())
{
SelectClosestTarget();
@@ -61,8 +89,13 @@ public class Enemy : MonoBehaviour, IMovementDirection
private void SelectClosestTarget()
{
if (targetManager == null)
return;
currentTarget =
targetManager.GetClosestActiveTarget(transform.position);
targetManager.GetClosestActiveTarget(
transform.position
);
if (currentTarget == null)
{
@@ -72,6 +105,9 @@ public class Enemy : MonoBehaviour, IMovementDirection
private void MoveTowardsTarget()
{
if (currentTarget == null)
return;
Vector3 direction =
currentTarget.position - transform.position;
@@ -89,6 +125,9 @@ public class Enemy : MonoBehaviour, IMovementDirection
private bool HasReachedTarget()
{
if (currentTarget == null)
return false;
return Vector3.Distance(
transform.position,
currentTarget.position
+1 -1
View File
@@ -46,7 +46,7 @@ public class EnemySpawner : MonoBehaviour
{
while (true)
{
float delay = Random.Range(
float delay = UnityEngine.Random.Range(
minSpawnDelay,
maxSpawnDelay
);
+157 -13
View File
@@ -1,45 +1,189 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyTargetManager : MonoBehaviour
{
[Header("Target Points")]
[SerializeField]
private List<Transform> targetPoints = new List<Transform>();
[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<Transform> availableTargets =
new List<Transform>();
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<Transform> closestTargets =
new List<Transform>();
float closestDistanceSqr = float.MaxValue;
float closestDistance = float.MaxValue;
foreach (Transform target in targetPoints)
{
if (target == null || !target.gameObject.activeInHierarchy)
continue;
float distanceSqr =
(target.position - position).sqrMagnitude;
if (distanceSqr < closestDistanceSqr)
if (target == null ||
!target.gameObject.activeInHierarchy)
{
closestDistanceSqr = distanceSqr;
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);
}
else if (Mathf.Approximately(
distanceSqr,
closestDistanceSqr))
// 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;
}
int randomIndex = Random.Range(
// Bei mehreren gleich nahen Targets zufällig wählen.
int randomIndex = UnityEngine.Random.Range(
0,
closestTargets.Count
);