Basis festgelegt

This commit is contained in:
2026-10-06 09:31:55 +02:00
parent 9e5822a37c
commit 0a801ed82c
17 changed files with 1243 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
using UnityEngine;
public class CharacterRotation : MonoBehaviour
{
[Header("Visual")]
[SerializeField]
private Transform visual;
[Header("Rotation")]
[SerializeField]
private float rotationSpeed = 540f;
[Tooltip("In welche lokale Richtung zeigt die Grafik standardm??ig?")]
[SerializeField]
private SpriteForwardDirection spriteForward =
SpriteForwardDirection.Up;
private IMovementDirection movement;
private enum SpriteForwardDirection
{
Up,
Right
}
private void Awake()
{
movement =
GetComponent<IMovementDirection>();
if (movement == null)
{
Debug.LogError(
"CharacterRotation ben?tigt eine Komponente, " +
"die IMovementDirection implementiert.",
this
);
}
if (visual == null)
{
Debug.LogError(
"CharacterRotation: Kein Visual zugewiesen.",
this
);
}
}
private void Update()
{
if (movement == null || visual == null)
return;
Vector2 direction =
movement.MovementDirection;
// Keine Bewegung -> aktuelle Rotation behalten.
if (direction.sqrMagnitude < 0.001f)
return;
RotateTowards(direction);
}
private void RotateTowards(Vector2 direction)
{
float targetAngle =
Mathf.Atan2(
direction.y,
direction.x
) * Mathf.Rad2Deg;
if (spriteForward ==
SpriteForwardDirection.Up)
{
targetAngle -= 90f;
}
Quaternion targetRotation =
Quaternion.Euler(
0f,
0f,
targetAngle
);
visual.rotation =
Quaternion.RotateTowards(
visual.rotation,
targetRotation,
rotationSpeed * Time.deltaTime
);
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bea87a19f3a99294c9d065a24307484c
+97
View File
@@ -0,0 +1,97 @@
using UnityEngine;
public class Enemy : MonoBehaviour, IMovementDirection
{
[Header("Movement")]
[SerializeField]
private float moveSpeed = 2f;
[SerializeField]
private float targetReachedDistance = 0.1f;
private EnemyTargetManager targetManager;
private Transform currentTarget;
// Wird von CharacterRotation verwendet.
public Vector2 MovementDirection { get; private set; }
private void Start()
{
targetManager = FindFirstObjectByType<EnemyTargetManager>();
if (targetManager == null)
{
Debug.LogError(
"Enemy: Kein EnemyTargetManager gefunden!",
this
);
return;
}
SelectClosestTarget();
}
private void Update()
{
if (targetManager == null)
return;
if (currentTarget == null)
{
MovementDirection = Vector2.zero;
SelectClosestTarget();
return;
}
// Falls das Ziel deaktiviert wurde:
if (!currentTarget.gameObject.activeInHierarchy)
{
SelectClosestTarget();
return;
}
MoveTowardsTarget();
if (HasReachedTarget())
{
SelectClosestTarget();
}
}
private void SelectClosestTarget()
{
currentTarget =
targetManager.GetClosestActiveTarget(transform.position);
if (currentTarget == null)
{
MovementDirection = Vector2.zero;
}
}
private void MoveTowardsTarget()
{
Vector3 direction =
currentTarget.position - transform.position;
MovementDirection = new Vector2(
direction.x,
direction.y
).normalized;
transform.position = Vector3.MoveTowards(
transform.position,
currentTarget.position,
moveSpeed * Time.deltaTime
);
}
private bool HasReachedTarget()
{
return Vector3.Distance(
transform.position,
currentTarget.position
) <= targetReachedDistance;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 544fe3d5f687b6b4bbe68d79ffb11bd8
+68
View File
@@ -0,0 +1,68 @@
using System.Collections;
using UnityEngine;
public class EnemySpawner : MonoBehaviour
{
[Header("Enemy")]
[SerializeField]
private GameObject enemyPrefab;
[Header("Spawn")]
[SerializeField]
private Transform spawnPoint;
[SerializeField]
private float minSpawnDelay = 0.5f;
[SerializeField]
private float maxSpawnDelay = 2f;
private void Start()
{
if (enemyPrefab == null)
{
Debug.LogError(
"EnemySpawner: Kein Enemy-Prefab zugewiesen!",
this
);
return;
}
if (spawnPoint == null)
{
Debug.LogError(
"EnemySpawner: Kein SpawnPoint zugewiesen!",
this
);
return;
}
StartCoroutine(SpawnLoop());
}
private IEnumerator SpawnLoop()
{
while (true)
{
float delay = Random.Range(
minSpawnDelay,
maxSpawnDelay
);
yield return new WaitForSeconds(delay);
SpawnEnemy();
}
}
private void SpawnEnemy()
{
Instantiate(
enemyPrefab,
spawnPoint.position,
spawnPoint.rotation
);
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: eed070947de809f4d9fd7c87e1d9b1c3
+49
View File
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using UnityEngine;
public class EnemyTargetManager : MonoBehaviour
{
[SerializeField]
private List<Transform> targetPoints = new List<Transform>();
public Transform GetClosestActiveTarget(Vector3 position)
{
List<Transform> closestTargets =
new List<Transform>();
float closestDistanceSqr = float.MaxValue;
foreach (Transform target in targetPoints)
{
if (target == null || !target.gameObject.activeInHierarchy)
continue;
float distanceSqr =
(target.position - position).sqrMagnitude;
if (distanceSqr < closestDistanceSqr)
{
closestDistanceSqr = distanceSqr;
closestTargets.Clear();
closestTargets.Add(target);
}
else if (Mathf.Approximately(
distanceSqr,
closestDistanceSqr))
{
closestTargets.Add(target);
}
}
if (closestTargets.Count == 0)
return null;
int randomIndex = Random.Range(
0,
closestTargets.Count
);
return closestTargets[randomIndex];
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6ac3932d87de0d64180930ddb4e2f576
+6
View File
@@ -0,0 +1,6 @@
using UnityEngine;
public interface IMovementDirection
{
Vector2 MovementDirection { get; }
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 649a0945a4204564187826046e548805