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>
249 lines
8.7 KiB
C#
249 lines
8.7 KiB
C#
// ==============================================
|
|
// ObstacleSpawner.cs - Hindernis-Generator
|
|
// ==============================================
|
|
// Spawnt Hindernisse, Items und Quiz-Trigger
|
|
// basierend auf Schwierigkeitsgrad.
|
|
|
|
using UnityEngine;
|
|
|
|
namespace BreakpilotDrive
|
|
{
|
|
public class ObstacleSpawner : MonoBehaviour
|
|
{
|
|
public static ObstacleSpawner Instance { get; private set; }
|
|
|
|
[Header("Hindernis-Prefabs")]
|
|
[SerializeField] private GameObject[] obstaclePrefabs; // Verschiedene Hindernisse
|
|
[SerializeField] private GameObject[] largObstaclePrefabs; // Grosse Hindernisse (2 Spuren)
|
|
|
|
[Header("Item-Prefabs")]
|
|
[SerializeField] private GameObject coinPrefab;
|
|
[SerializeField] private GameObject starPrefab;
|
|
[SerializeField] private GameObject shieldPrefab;
|
|
|
|
[Header("Quiz-Trigger-Prefabs")]
|
|
[SerializeField] private GameObject bridgePrefab;
|
|
[SerializeField] private GameObject treePrefab;
|
|
[SerializeField] private GameObject housePrefab;
|
|
|
|
[Header("Spawn-Einstellungen")]
|
|
[SerializeField] private float laneDistance = 3f;
|
|
[SerializeField] private float minObstacleSpacing = 10f;
|
|
[SerializeField] private float maxObstacleSpacing = 30f;
|
|
|
|
[Header("Wahrscheinlichkeiten (0-1)")]
|
|
[SerializeField] private float obstacleChance = 0.6f;
|
|
[SerializeField] private float coinChance = 0.3f;
|
|
[SerializeField] private float starChance = 0.05f;
|
|
[SerializeField] private float shieldChance = 0.02f;
|
|
[SerializeField] private float quizTriggerChance = 0.1f;
|
|
|
|
// Interner Zustand
|
|
private float lastObstacleZ = 0f;
|
|
private int quizTriggerCount = 0;
|
|
|
|
void Awake()
|
|
{
|
|
if (Instance == null)
|
|
{
|
|
Instance = this;
|
|
}
|
|
else
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
// Wahrscheinlichkeiten von Difficulty laden
|
|
UpdateFromDifficulty();
|
|
}
|
|
|
|
private void UpdateFromDifficulty()
|
|
{
|
|
if (GameManager.Instance?.DifficultySettings != null)
|
|
{
|
|
var settings = GameManager.Instance.DifficultySettings;
|
|
obstacleChance = settings.obstacle_frequency;
|
|
// Power-Up Chance beeinflusst Items
|
|
float powerUpChance = settings.power_up_chance;
|
|
coinChance = powerUpChance * 0.8f;
|
|
starChance = powerUpChance * 0.15f;
|
|
shieldChance = powerUpChance * 0.05f;
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Spawning auf Segment
|
|
// ==============================================
|
|
public void SpawnOnSegment(GameObject segment, float segmentStartZ)
|
|
{
|
|
float segmentLength = 50f; // Sollte mit TrackGenerator uebereinstimmen
|
|
float currentZ = segmentStartZ + minObstacleSpacing;
|
|
|
|
while (currentZ < segmentStartZ + segmentLength - minObstacleSpacing)
|
|
{
|
|
// Zufaelliger Abstand zum naechsten Objekt
|
|
float spacing = Random.Range(minObstacleSpacing, maxObstacleSpacing);
|
|
|
|
// Was spawnen?
|
|
SpawnAtPosition(segment.transform, currentZ);
|
|
|
|
currentZ += spacing;
|
|
}
|
|
}
|
|
|
|
private void SpawnAtPosition(Transform parent, float zPosition)
|
|
{
|
|
float roll = Random.value;
|
|
|
|
// Quiz-Trigger (selten, aber wichtig)
|
|
if (roll < quizTriggerChance && quizTriggerCount < 3)
|
|
{
|
|
SpawnQuizTrigger(parent, zPosition);
|
|
quizTriggerCount++;
|
|
return;
|
|
}
|
|
|
|
// Hindernis
|
|
roll = Random.value;
|
|
if (roll < obstacleChance)
|
|
{
|
|
SpawnObstacle(parent, zPosition);
|
|
}
|
|
|
|
// Items (koennen neben Hindernissen sein)
|
|
roll = Random.value;
|
|
if (roll < coinChance)
|
|
{
|
|
SpawnCoinRow(parent, zPosition);
|
|
}
|
|
else if (roll < coinChance + starChance)
|
|
{
|
|
SpawnItem(starPrefab, parent, zPosition, GetRandomLane());
|
|
}
|
|
else if (roll < coinChance + starChance + shieldChance)
|
|
{
|
|
SpawnItem(shieldPrefab, parent, zPosition, GetRandomLane());
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Hindernisse
|
|
// ==============================================
|
|
private void SpawnObstacle(Transform parent, float zPosition)
|
|
{
|
|
if (obstaclePrefabs == null || obstaclePrefabs.Length == 0) return;
|
|
|
|
// Zufaelliges Hindernis und Spur waehlen
|
|
int prefabIndex = Random.Range(0, obstaclePrefabs.Length);
|
|
int lane = GetRandomLane();
|
|
|
|
// Manchmal grosses Hindernis (blockiert 2 Spuren)
|
|
if (largObstaclePrefabs != null && largObstaclePrefabs.Length > 0 && Random.value < 0.2f)
|
|
{
|
|
prefabIndex = Random.Range(0, largObstaclePrefabs.Length);
|
|
SpawnObstacleAtLane(largObstaclePrefabs[prefabIndex], parent, zPosition, lane);
|
|
}
|
|
else
|
|
{
|
|
SpawnObstacleAtLane(obstaclePrefabs[prefabIndex], parent, zPosition, lane);
|
|
}
|
|
}
|
|
|
|
private void SpawnObstacleAtLane(GameObject prefab, Transform parent, float zPosition, int lane)
|
|
{
|
|
float xPos = (lane - 1) * laneDistance;
|
|
Vector3 position = new Vector3(xPos, 0, zPosition);
|
|
|
|
GameObject obstacle = Instantiate(prefab, parent);
|
|
obstacle.transform.localPosition = position;
|
|
obstacle.tag = "Obstacle";
|
|
}
|
|
|
|
// ==============================================
|
|
// Items
|
|
// ==============================================
|
|
private void SpawnItem(GameObject prefab, Transform parent, float zPosition, int lane)
|
|
{
|
|
if (prefab == null) return;
|
|
|
|
float xPos = (lane - 1) * laneDistance;
|
|
Vector3 position = new Vector3(xPos, 0.5f, zPosition); // Leicht ueber dem Boden
|
|
|
|
GameObject item = Instantiate(prefab, parent);
|
|
item.transform.localPosition = position;
|
|
}
|
|
|
|
private void SpawnCoinRow(Transform parent, float zPosition)
|
|
{
|
|
if (coinPrefab == null) return;
|
|
|
|
int lane = GetRandomLane();
|
|
int coinCount = Random.Range(3, 6);
|
|
|
|
for (int i = 0; i < coinCount; i++)
|
|
{
|
|
SpawnItem(coinPrefab, parent, zPosition + (i * 2f), lane);
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Quiz-Trigger
|
|
// ==============================================
|
|
private void SpawnQuizTrigger(Transform parent, float zPosition)
|
|
{
|
|
GameObject prefab = GetRandomTriggerPrefab();
|
|
if (prefab == null) return;
|
|
|
|
// Trigger sind meist in der Mitte oder ueber der Strasse
|
|
Vector3 position = new Vector3(0, 0, zPosition);
|
|
|
|
GameObject trigger = Instantiate(prefab, parent);
|
|
trigger.transform.localPosition = position;
|
|
trigger.tag = "QuizTrigger";
|
|
|
|
// VisualTrigger-Komponente hinzufuegen falls nicht vorhanden
|
|
if (trigger.GetComponent<VisualTrigger>() == null)
|
|
{
|
|
VisualTrigger vt = trigger.AddComponent<VisualTrigger>();
|
|
vt.TriggerType = GetTriggerTypeFromPrefab(prefab);
|
|
}
|
|
}
|
|
|
|
private GameObject GetRandomTriggerPrefab()
|
|
{
|
|
GameObject[] triggers = new GameObject[] { bridgePrefab, treePrefab, housePrefab };
|
|
var validTriggers = System.Array.FindAll(triggers, t => t != null);
|
|
|
|
if (validTriggers.Length == 0) return null;
|
|
|
|
return validTriggers[Random.Range(0, validTriggers.Length)];
|
|
}
|
|
|
|
private string GetTriggerTypeFromPrefab(GameObject prefab)
|
|
{
|
|
if (prefab == bridgePrefab) return "bridge";
|
|
if (prefab == treePrefab) return "tree";
|
|
if (prefab == housePrefab) return "house";
|
|
return "unknown";
|
|
}
|
|
|
|
// ==============================================
|
|
// Helper
|
|
// ==============================================
|
|
private int GetRandomLane()
|
|
{
|
|
return Random.Range(0, 3); // 0, 1, oder 2
|
|
}
|
|
|
|
public void ResetSpawner()
|
|
{
|
|
lastObstacleZ = 0f;
|
|
quizTriggerCount = 0;
|
|
UpdateFromDifficulty();
|
|
}
|
|
}
|
|
}
|