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
+125
View File
@@ -0,0 +1,125 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1661225059413378572
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8583516111923390659}
m_Layer: 0
m_Name: TurretSlot
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8583516111923390659
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1661225059413378572}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8637190438261622777}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &6820201920342387708
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8637190438261622777}
- component: {fileID: 8572961899416546373}
m_Layer: 0
m_Name: Square
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8637190438261622777
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6820201920342387708}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.5, y: 0.5, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8583516111923390659}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!212 &8572961899416546373
SpriteRenderer:
serializedVersion: 2
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6820201920342387708}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 0
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 0
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_Sprite: {fileID: 7482667652216324306, guid: 311925a002f4447b3a28927169b83ea6, type: 3}
m_Color: {r: 0.6226415, g: 0.6226415, b: 0.6226415, a: 1}
m_FlipX: 0
m_FlipY: 0
m_DrawMode: 0
m_Size: {x: 1, y: 1}
m_AdaptiveModeThreshold: 0.5
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_SpriteSortPoint: 0
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d17580f0491ab844c9603e7ccfaecef3
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
+45 -6
View File
@@ -15,9 +15,10 @@ public class Enemy : MonoBehaviour, IMovementDirection
// Wird von CharacterRotation verwendet. // Wird von CharacterRotation verwendet.
public Vector2 MovementDirection { get; private set; } public Vector2 MovementDirection { get; private set; }
private void Start() private void Awake()
{ {
targetManager = FindFirstObjectByType<EnemyTargetManager>(); targetManager =
FindFirstObjectByType<EnemyTargetManager>();
if (targetManager == null) if (targetManager == null)
{ {
@@ -25,9 +26,31 @@ public class Enemy : MonoBehaviour, IMovementDirection
"Enemy: Kein EnemyTargetManager gefunden!", "Enemy: Kein EnemyTargetManager gefunden!",
this 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(); SelectClosestTarget();
} }
@@ -37,22 +60,27 @@ public class Enemy : MonoBehaviour, IMovementDirection
if (targetManager == null) if (targetManager == null)
return; return;
// Kein aktuelles Ziel vorhanden.
if (currentTarget == null) if (currentTarget == null)
{ {
MovementDirection = Vector2.zero; MovementDirection = Vector2.zero;
SelectClosestTarget(); SelectClosestTarget();
return; return;
} }
// Falls das Ziel deaktiviert wurde: // Das aktuelle Ziel wurde deaktiviert.
if (!currentTarget.gameObject.activeInHierarchy) if (!currentTarget.gameObject.activeInHierarchy)
{ {
SelectClosestTarget(); SelectClosestTarget();
return; return;
} }
MoveTowardsTarget(); MoveTowardsTarget();
// Ziel erreicht.
if (HasReachedTarget()) if (HasReachedTarget())
{ {
SelectClosestTarget(); SelectClosestTarget();
@@ -61,8 +89,13 @@ public class Enemy : MonoBehaviour, IMovementDirection
private void SelectClosestTarget() private void SelectClosestTarget()
{ {
if (targetManager == null)
return;
currentTarget = currentTarget =
targetManager.GetClosestActiveTarget(transform.position); targetManager.GetClosestActiveTarget(
transform.position
);
if (currentTarget == null) if (currentTarget == null)
{ {
@@ -72,6 +105,9 @@ public class Enemy : MonoBehaviour, IMovementDirection
private void MoveTowardsTarget() private void MoveTowardsTarget()
{ {
if (currentTarget == null)
return;
Vector3 direction = Vector3 direction =
currentTarget.position - transform.position; currentTarget.position - transform.position;
@@ -89,6 +125,9 @@ public class Enemy : MonoBehaviour, IMovementDirection
private bool HasReachedTarget() private bool HasReachedTarget()
{ {
if (currentTarget == null)
return false;
return Vector3.Distance( return Vector3.Distance(
transform.position, transform.position,
currentTarget.position currentTarget.position
+1 -1
View File
@@ -46,7 +46,7 @@ public class EnemySpawner : MonoBehaviour
{ {
while (true) while (true)
{ {
float delay = Random.Range( float delay = UnityEngine.Random.Range(
minSpawnDelay, minSpawnDelay,
maxSpawnDelay maxSpawnDelay
); );
+157 -13
View File
@@ -1,45 +1,189 @@
using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class EnemyTargetManager : MonoBehaviour public class EnemyTargetManager : MonoBehaviour
{ {
[Header("Target Points")]
[SerializeField] [SerializeField]
private List<Transform> targetPoints = new List<Transform>(); 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) public Transform GetClosestActiveTarget(Vector3 position)
{ {
List<Transform> closestTargets = List<Transform> closestTargets =
new List<Transform>(); new List<Transform>();
float closestDistanceSqr = float.MaxValue; float closestDistance = float.MaxValue;
foreach (Transform target in targetPoints) foreach (Transform target in targetPoints)
{ {
if (target == null || !target.gameObject.activeInHierarchy) if (target == null ||
continue; !target.gameObject.activeInHierarchy)
float distanceSqr =
(target.position - position).sqrMagnitude;
if (distanceSqr < closestDistanceSqr)
{ {
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.Clear();
closestTargets.Add(target); closestTargets.Add(target);
} }
else if (Mathf.Approximately( // Innerhalb der eingestellten Toleranz:
distanceSqr, // Dieses Target gilt als gleich nah.
closestDistanceSqr)) else if (Mathf.Abs(
distance - closestDistance
) <= equalDistanceTolerance)
{ {
closestTargets.Add(target); closestTargets.Add(target);
} }
} }
if (closestTargets.Count == 0) if (closestTargets.Count == 0)
{
return null; return null;
}
int randomIndex = Random.Range( // Bei mehreren gleich nahen Targets zufällig wählen.
int randomIndex = UnityEngine.Random.Range(
0, 0,
closestTargets.Count closestTargets.Count
); );