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.
|
||||
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