Gegnerpathing Logik
This commit is contained in:
+45
-6
@@ -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
|
||||
|
||||
@@ -46,7 +46,7 @@ public class EnemySpawner : MonoBehaviour
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
float delay = Random.Range(
|
||||
float delay = UnityEngine.Random.Range(
|
||||
minSpawnDelay,
|
||||
maxSpawnDelay
|
||||
);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user