Gegnerpathing Logik
This commit is contained in:
@@ -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
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d17580f0491ab844c9603e7ccfaecef3
|
||||||
|
PrefabImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
+941
-13
File diff suppressed because it is too large
Load Diff
+45
-6
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user