A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
234 lines
7.0 KiB
C#
234 lines
7.0 KiB
C#
// ==============================================
|
|
// TrackGenerator.cs - Endlose Streckengenerierung
|
|
// ==============================================
|
|
// Erzeugt endlose Streckenabschnitte durch
|
|
// Object-Pooling und Recycling.
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace BreakpilotDrive
|
|
{
|
|
public class TrackGenerator : MonoBehaviour
|
|
{
|
|
public static TrackGenerator Instance { get; private set; }
|
|
|
|
[Header("Track Prefabs")]
|
|
[SerializeField] private GameObject[] trackSegmentPrefabs; // Verschiedene Streckenabschnitte
|
|
[SerializeField] private GameObject startSegmentPrefab; // Start-Segment
|
|
|
|
[Header("Generierung")]
|
|
[SerializeField] private float segmentLength = 50f; // Laenge eines Segments
|
|
[SerializeField] private int visibleSegments = 5; // Anzahl sichtbarer Segmente
|
|
[SerializeField] private float despawnDistance = -20f; // Wann Segment recycelt wird
|
|
|
|
[Header("Bewegung")]
|
|
[SerializeField] private float baseSpeed = 10f; // Basis-Geschwindigkeit
|
|
private float currentSpeed;
|
|
|
|
// Object Pool
|
|
private List<GameObject> activeSegments = new List<GameObject>();
|
|
private Queue<GameObject> segmentPool = new Queue<GameObject>();
|
|
|
|
// Position
|
|
private float nextSpawnZ = 0f;
|
|
|
|
void Awake()
|
|
{
|
|
if (Instance == null)
|
|
{
|
|
Instance = this;
|
|
}
|
|
else
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
currentSpeed = baseSpeed;
|
|
|
|
// Geschwindigkeit von Difficulty laden
|
|
if (GameManager.Instance?.DifficultySettings != null)
|
|
{
|
|
currentSpeed = GameManager.Instance.DifficultySettings.lane_speed;
|
|
}
|
|
|
|
// Initiale Segmente erstellen
|
|
InitializeTrack();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (GameManager.Instance?.CurrentState != GameState.Playing)
|
|
return;
|
|
|
|
// Segmente bewegen
|
|
MoveSegments();
|
|
|
|
// Alte Segmente recyceln
|
|
RecycleSegments();
|
|
|
|
// Neue Segmente spawnen
|
|
SpawnSegmentsIfNeeded();
|
|
}
|
|
|
|
// ==============================================
|
|
// Initialisierung
|
|
// ==============================================
|
|
private void InitializeTrack()
|
|
{
|
|
nextSpawnZ = 0f;
|
|
|
|
// Start-Segment
|
|
if (startSegmentPrefab != null)
|
|
{
|
|
SpawnSegment(startSegmentPrefab);
|
|
}
|
|
|
|
// Weitere Segmente fuer sichtbaren Bereich
|
|
for (int i = 0; i < visibleSegments; i++)
|
|
{
|
|
SpawnRandomSegment();
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Segment-Spawning
|
|
// ==============================================
|
|
private void SpawnRandomSegment()
|
|
{
|
|
if (trackSegmentPrefabs == null || trackSegmentPrefabs.Length == 0)
|
|
{
|
|
Debug.LogWarning("Keine Track-Segment-Prefabs zugewiesen!");
|
|
return;
|
|
}
|
|
|
|
int index = Random.Range(0, trackSegmentPrefabs.Length);
|
|
SpawnSegment(trackSegmentPrefabs[index]);
|
|
}
|
|
|
|
private void SpawnSegment(GameObject prefab)
|
|
{
|
|
GameObject segment;
|
|
|
|
// Aus Pool holen oder neu erstellen
|
|
if (segmentPool.Count > 0)
|
|
{
|
|
segment = segmentPool.Dequeue();
|
|
segment.SetActive(true);
|
|
}
|
|
else
|
|
{
|
|
segment = Instantiate(prefab, transform);
|
|
}
|
|
|
|
// Position setzen
|
|
segment.transform.position = new Vector3(0, 0, nextSpawnZ);
|
|
nextSpawnZ += segmentLength;
|
|
|
|
activeSegments.Add(segment);
|
|
|
|
// Hindernisse und Items auf Segment spawnen
|
|
ObstacleSpawner.Instance?.SpawnOnSegment(segment, nextSpawnZ - segmentLength);
|
|
}
|
|
|
|
private void SpawnSegmentsIfNeeded()
|
|
{
|
|
// Pruefe ob wir mehr Segmente brauchen
|
|
float playerZ = 0; // Spieler ist bei Z=0, Welt bewegt sich
|
|
float maxVisibleZ = playerZ + (visibleSegments * segmentLength);
|
|
|
|
while (nextSpawnZ < maxVisibleZ)
|
|
{
|
|
SpawnRandomSegment();
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Bewegung
|
|
// ==============================================
|
|
private void MoveSegments()
|
|
{
|
|
Vector3 movement = Vector3.back * currentSpeed * Time.deltaTime;
|
|
|
|
foreach (var segment in activeSegments)
|
|
{
|
|
segment.transform.position += movement;
|
|
}
|
|
|
|
// Auch nextSpawnZ anpassen
|
|
nextSpawnZ -= currentSpeed * Time.deltaTime;
|
|
}
|
|
|
|
// ==============================================
|
|
// Recycling
|
|
// ==============================================
|
|
private void RecycleSegments()
|
|
{
|
|
for (int i = activeSegments.Count - 1; i >= 0; i--)
|
|
{
|
|
if (activeSegments[i].transform.position.z < despawnDistance)
|
|
{
|
|
RecycleSegment(activeSegments[i]);
|
|
activeSegments.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RecycleSegment(GameObject segment)
|
|
{
|
|
// Kinder-Objekte (Hindernisse, Items) entfernen
|
|
foreach (Transform child in segment.transform)
|
|
{
|
|
if (child.CompareTag("Obstacle") || child.CompareTag("Coin") ||
|
|
child.CompareTag("Star") || child.CompareTag("QuizTrigger"))
|
|
{
|
|
Destroy(child.gameObject);
|
|
}
|
|
}
|
|
|
|
// Segment deaktivieren und zurueck in Pool
|
|
segment.SetActive(false);
|
|
segmentPool.Enqueue(segment);
|
|
}
|
|
|
|
// ==============================================
|
|
// Geschwindigkeit
|
|
// ==============================================
|
|
public void SetSpeed(float speed)
|
|
{
|
|
currentSpeed = speed;
|
|
}
|
|
|
|
public float GetSpeed()
|
|
{
|
|
return currentSpeed;
|
|
}
|
|
|
|
public void IncreaseSpeed(float amount)
|
|
{
|
|
currentSpeed += amount;
|
|
}
|
|
|
|
// ==============================================
|
|
// Reset
|
|
// ==============================================
|
|
public void ResetTrack()
|
|
{
|
|
// Alle aktiven Segmente recyceln
|
|
foreach (var segment in activeSegments)
|
|
{
|
|
RecycleSegment(segment);
|
|
}
|
|
activeSegments.Clear();
|
|
|
|
// Neu initialisieren
|
|
nextSpawnZ = 0f;
|
|
currentSpeed = baseSpeed;
|
|
InitializeTrack();
|
|
}
|
|
}
|
|
}
|