using UnityEngine; using System.Collections.Generic; public class SpawnManager : MonoBehaviour { private float[] spawnPositionsEnemiesOppositeZ = { 3.7f, 11f, 17.8f, 24.6f, 31.8f, 39f }; private float[] spawnPositionsEnemiesForwardsZ = { -3.7f, -11f, -17.8f, -24.6f, -31.8f, -39f }; private float[] spawnPositionsObstaclesZ = { 3.7f, 11f, 17.8f, 24.6f, 31.8f, 39f, -3.7f, -11f, -17.8f, -24.6f, -31.8f, -39f }; private float spawnPositionSafezoneZ = -39f; private float? safezoneZ = null; private float safezoneTime = 10f; private float safezoneStopX = 0f; public GameObject safezonePrefab; private List occupiedZPositions = new List(); public GameObject[] enemyPrefabs; public GameObject[] obstaclePrefabs; private List activeEnemies = new List(); private List activeObstacles = new List(); public float vehicleSpeed = 75f; public float despawnX = 50f; private PlayerController playerControllerScript; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { playerControllerScript = GameObject.Find("Player").GetComponent(); float spawnInterval = Random.Range(1.8f, 2.3f); float safezoneInterval = Random.Range(20f, 30f); InvokeRepeating("SpawnRandomObject", 10f, spawnInterval); InvokeRepeating("SpawnSafezone", 0f, safezoneInterval); } void SpawnRandomObject() { if (playerControllerScript.gameOver) return; occupiedZPositions.Clear(); // Wie viele Objekte gleichzeitig spawnen sollen (zufällig oder fix) int objectsToSpawn = Random.Range(1, 10); // 1 bis 9 pro Spawn-Aufruf for (int i = 0; i < objectsToSpawn; i++) { float rand = Random.value; if (rand < 0.6f) SpawnRandomEnemy(); else SpawnRandomObstacle(); } } void FixedUpdate() { if (!playerControllerScript.gameOver) { // Gegner bewegen for (int i = activeEnemies.Count - 1; i >= 0; i--) { Rigidbody rb = activeEnemies[i]; if (rb == null) { activeEnemies.RemoveAt(i); continue; } rb.AddForce(rb.gameObject.GetComponent().moveDir * 6, ForceMode.Force); if (Mathf.Abs(rb.position.x) > despawnX) { occupiedZPositions.Remove(rb.position.z); // Z wieder freigeben Destroy(rb.gameObject); activeEnemies.RemoveAt(i); } } // Hindernisse bewegen for (int i = activeObstacles.Count - 1; i >= 0; i--) { Rigidbody rb = activeObstacles[i]; if (rb == null) { activeObstacles.RemoveAt(i); continue; } rb.AddForce(rb.gameObject.GetComponent().moveDir * 6, ForceMode.Force); if (Mathf.Abs(rb.position.x) > despawnX) { occupiedZPositions.Remove(rb.position.z); Destroy(rb.gameObject); activeObstacles.RemoveAt(i); } } foreach (var safezone in GameObject.FindObjectsOfType()) { Rigidbody rb = safezone.GetComponent(); if (rb == null) continue; // Prüfen, ob Stop erreicht if (rb.position.x > safezone.stopX || safezone.playerOn) { rb.AddForce(safezone.moveDir * 2, ForceMode.Force); // bewegt sich } else { rb.linearVelocity = Vector3.zero; // stoppt safezone.waitTime -= Time.fixedDeltaTime; if (safezone.waitTime <= 0f) { // Player ist nicht drauf -> Game Over PlayerController pc = GameObject.Find("Player").GetComponent(); if (!safezone.playerHasBeenOn) pc.gameOver = true; Destroy(safezone.gameObject); // Safezone weg safezoneZ = null; } } } } } void SpawnRandomEnemy() { GameObject chosenPrefab = enemyPrefabs[Random.Range(0, enemyPrefabs.Length)]; bool spawnOpposite = Random.value > 0.5f; float[] possibleZ = spawnOpposite ? spawnPositionsEnemiesOppositeZ : spawnPositionsEnemiesForwardsZ; // Filtere belegte Z-Positionen heraus List availableZ = new List(); foreach (var z in possibleZ) if (!occupiedZPositions.Contains(z) && z != safezoneZ) availableZ.Add(z); if (availableZ.Count == 0) return; // keine freie Spur float chosenZ = availableZ[Random.Range(0, availableZ.Count)]; occupiedZPositions.Add(chosenZ); Vector3 spawnPos = spawnOpposite ? new Vector3(40f, 0.5f, chosenZ) : new Vector3(-40f, 0.5f, chosenZ); Vector3 moveForce = spawnOpposite ? Vector3.left * vehicleSpeed : Vector3.right * vehicleSpeed; GameObject enemy = Instantiate(chosenPrefab, spawnPos, chosenPrefab.transform.rotation); Rigidbody rb = enemy.GetComponent(); if (rb != null) { rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ; MoveData data = enemy.AddComponent(); data.moveDir = moveForce; activeEnemies.Add(rb); } } void SpawnRandomObstacle() { GameObject chosenPrefab = obstaclePrefabs[Random.Range(0, obstaclePrefabs.Length)]; // Filtere belegte Z-Positionen List availableZ = new List(); foreach (var z in spawnPositionsObstaclesZ) if (!occupiedZPositions.Contains(z) && z != safezoneZ) availableZ.Add(z); if (availableZ.Count == 0) return; // keine freie Spur float chosenZ = availableZ[Random.Range(0, availableZ.Count)]; occupiedZPositions.Add(chosenZ); Vector3 spawnPos = new Vector3(40f, 0.5f, chosenZ); GameObject obstacle = Instantiate(chosenPrefab, spawnPos, chosenPrefab.transform.rotation); Rigidbody rb = obstacle.GetComponent(); if (rb != null) { rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ; MoveData data = obstacle.AddComponent(); data.moveDir = Vector3.left * vehicleSpeed; activeObstacles.Add(rb); } } void SpawnSafezone() { if (safezonePrefab == null) return; Vector3 spawnPos = new Vector3(40f, 0.5f, spawnPositionSafezoneZ); GameObject safezone = Instantiate(safezonePrefab, spawnPos, safezonePrefab.transform.rotation); safezoneZ = spawnPositionSafezoneZ; Rigidbody rb = safezone.GetComponent(); if (rb != null) { rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ; SafezoneData data = safezone.AddComponent(); data.moveDir = Vector3.left * vehicleSpeed; // fährt nach -X data.stopX = safezoneStopX; data.waitTime = safezoneTime; } } } public class MoveData : MonoBehaviour { public Vector3 moveDir; }