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>
318 lines
9.5 KiB
C#
318 lines
9.5 KiB
C#
// ==============================================
|
|
// GameManager.cs - Zentrale Spielsteuerung
|
|
// ==============================================
|
|
// Verwaltet Spielzustand, Score, Leben und
|
|
// koordiniert alle anderen Manager.
|
|
|
|
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace BreakpilotDrive
|
|
{
|
|
public enum GameState
|
|
{
|
|
MainMenu,
|
|
Playing,
|
|
Paused,
|
|
QuizActive,
|
|
GameOver
|
|
}
|
|
|
|
public class GameManager : MonoBehaviour
|
|
{
|
|
public static GameManager Instance { get; private set; }
|
|
|
|
[Header("Spieleinstellungen")]
|
|
[SerializeField] private int startLives = 3;
|
|
[SerializeField] private float pauseQuestionInterval = 500f; // Alle X Meter
|
|
|
|
[Header("UI Referenzen")]
|
|
[SerializeField] private GameObject gameOverPanel;
|
|
[SerializeField] private GameObject pausePanel;
|
|
|
|
// Spielzustand
|
|
private GameState currentState = GameState.MainMenu;
|
|
private int score = 0;
|
|
private int lives;
|
|
private float distanceTraveled = 0f;
|
|
private float playTime = 0f;
|
|
private float nextPauseQuestionDistance;
|
|
|
|
// Schwierigkeit (von API geladen)
|
|
private int currentDifficulty = 3;
|
|
private GameDifficulty difficultySettings;
|
|
|
|
// Events
|
|
public event Action<int> OnScoreChanged;
|
|
public event Action<int> OnLivesChanged;
|
|
public event Action<float> OnDistanceChanged;
|
|
public event Action<GameState> OnStateChanged;
|
|
|
|
// Properties
|
|
public GameState CurrentState => currentState;
|
|
public int Score => score;
|
|
public int Lives => lives;
|
|
public float DistanceTraveled => distanceTraveled;
|
|
public float PlayTime => playTime;
|
|
public int CurrentDifficulty => currentDifficulty;
|
|
public GameDifficulty DifficultySettings => difficultySettings;
|
|
|
|
void Awake()
|
|
{
|
|
if (Instance == null)
|
|
{
|
|
Instance = this;
|
|
DontDestroyOnLoad(gameObject);
|
|
}
|
|
else
|
|
{
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
// UI initial verstecken
|
|
if (gameOverPanel) gameOverPanel.SetActive(false);
|
|
if (pausePanel) pausePanel.SetActive(false);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (currentState == GameState.Playing)
|
|
{
|
|
// Spielzeit zaehlen
|
|
playTime += Time.deltaTime;
|
|
|
|
// Pause-Fragen pruefen
|
|
if (distanceTraveled >= nextPauseQuestionDistance)
|
|
{
|
|
TriggerPauseQuestion();
|
|
}
|
|
|
|
// Escape fuer Pause
|
|
if (Input.GetKeyDown(KeyCode.Escape))
|
|
{
|
|
PauseGame();
|
|
}
|
|
}
|
|
else if (currentState == GameState.Paused)
|
|
{
|
|
if (Input.GetKeyDown(KeyCode.Escape))
|
|
{
|
|
ResumeGame();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Spiel starten
|
|
// ==============================================
|
|
public void StartGame(string userId = "guest")
|
|
{
|
|
// Werte zuruecksetzen
|
|
score = 0;
|
|
lives = startLives;
|
|
distanceTraveled = 0f;
|
|
playTime = 0f;
|
|
nextPauseQuestionDistance = pauseQuestionInterval;
|
|
|
|
// Events ausloesen
|
|
OnScoreChanged?.Invoke(score);
|
|
OnLivesChanged?.Invoke(lives);
|
|
|
|
// Schwierigkeit laden
|
|
if (BreakpilotAPI.Instance != null)
|
|
{
|
|
StartCoroutine(BreakpilotAPI.Instance.GetLearningLevel(userId,
|
|
onSuccess: (level) =>
|
|
{
|
|
currentDifficulty = level.overall_level;
|
|
LoadDifficultySettings();
|
|
}
|
|
));
|
|
}
|
|
else
|
|
{
|
|
LoadDifficultySettings();
|
|
}
|
|
|
|
// Quiz-Statistik zuruecksetzen
|
|
if (QuizManager.Instance != null)
|
|
{
|
|
QuizManager.Instance.ResetStatistics();
|
|
}
|
|
|
|
SetState(GameState.Playing);
|
|
}
|
|
|
|
private void LoadDifficultySettings()
|
|
{
|
|
if (BreakpilotAPI.Instance != null)
|
|
{
|
|
StartCoroutine(BreakpilotAPI.Instance.GetDifficulty(currentDifficulty,
|
|
onSuccess: (settings) =>
|
|
{
|
|
difficultySettings = settings;
|
|
Debug.Log($"Schwierigkeit {currentDifficulty} geladen: Speed={settings.lane_speed}");
|
|
}
|
|
));
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Score-System
|
|
// ==============================================
|
|
public void AddScore(int points)
|
|
{
|
|
score = Mathf.Max(0, score + points);
|
|
OnScoreChanged?.Invoke(score);
|
|
}
|
|
|
|
public void AddDistance(float distance)
|
|
{
|
|
distanceTraveled += distance;
|
|
OnDistanceChanged?.Invoke(distanceTraveled);
|
|
}
|
|
|
|
// ==============================================
|
|
// Leben-System
|
|
// ==============================================
|
|
public void LoseLife()
|
|
{
|
|
lives--;
|
|
OnLivesChanged?.Invoke(lives);
|
|
|
|
if (lives <= 0)
|
|
{
|
|
GameOver();
|
|
}
|
|
}
|
|
|
|
public void GainLife()
|
|
{
|
|
lives++;
|
|
OnLivesChanged?.Invoke(lives);
|
|
}
|
|
|
|
// ==============================================
|
|
// Pause-Fragen
|
|
// ==============================================
|
|
private void TriggerPauseQuestion()
|
|
{
|
|
nextPauseQuestionDistance += pauseQuestionInterval;
|
|
|
|
if (BreakpilotAPI.Instance != null && QuizManager.Instance != null)
|
|
{
|
|
// Pause-Frage aus Cache holen
|
|
var questions = BreakpilotAPI.Instance.GetCachedQuestions();
|
|
var pauseQuestions = questions.FindAll(q => q.quiz_mode == "pause");
|
|
|
|
if (pauseQuestions.Count > 0)
|
|
{
|
|
int index = UnityEngine.Random.Range(0, pauseQuestions.Count);
|
|
QuizManager.Instance.ShowPauseQuestion(pauseQuestions[index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Spielzustand
|
|
// ==============================================
|
|
public void SetState(GameState newState)
|
|
{
|
|
currentState = newState;
|
|
OnStateChanged?.Invoke(newState);
|
|
|
|
switch (newState)
|
|
{
|
|
case GameState.Playing:
|
|
Time.timeScale = 1f;
|
|
break;
|
|
case GameState.Paused:
|
|
case GameState.QuizActive:
|
|
Time.timeScale = 0f;
|
|
break;
|
|
case GameState.GameOver:
|
|
Time.timeScale = 0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void PauseGame()
|
|
{
|
|
if (currentState == GameState.Playing)
|
|
{
|
|
SetState(GameState.Paused);
|
|
if (pausePanel) pausePanel.SetActive(true);
|
|
}
|
|
}
|
|
|
|
public void ResumeGame()
|
|
{
|
|
if (currentState == GameState.Paused)
|
|
{
|
|
SetState(GameState.Playing);
|
|
if (pausePanel) pausePanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// ==============================================
|
|
// Spiel beenden
|
|
// ==============================================
|
|
public void GameOver()
|
|
{
|
|
SetState(GameState.GameOver);
|
|
|
|
if (gameOverPanel) gameOverPanel.SetActive(true);
|
|
|
|
// Session speichern
|
|
SaveSession();
|
|
}
|
|
|
|
private void SaveSession()
|
|
{
|
|
if (BreakpilotAPI.Instance == null) return;
|
|
|
|
GameSession session = new GameSession
|
|
{
|
|
user_id = "guest", // TODO: Echte User-ID
|
|
game_mode = "video",
|
|
duration_seconds = Mathf.RoundToInt(playTime),
|
|
distance_traveled = distanceTraveled,
|
|
score = score,
|
|
questions_answered = QuizManager.Instance?.GetQuestionsAnswered() ?? 0,
|
|
questions_correct = QuizManager.Instance?.GetQuestionsCorrect() ?? 0,
|
|
difficulty_level = currentDifficulty
|
|
};
|
|
|
|
StartCoroutine(BreakpilotAPI.Instance.SaveGameSession(session,
|
|
onSuccess: (response) =>
|
|
{
|
|
Debug.Log($"Session gespeichert: {response.session_id}");
|
|
if (response.new_level.HasValue)
|
|
{
|
|
Debug.Log($"Level Up! Neues Level: {response.new_level}");
|
|
}
|
|
}
|
|
));
|
|
}
|
|
|
|
// ==============================================
|
|
// Neustart
|
|
// ==============================================
|
|
public void RestartGame()
|
|
{
|
|
if (gameOverPanel) gameOverPanel.SetActive(false);
|
|
StartGame();
|
|
}
|
|
|
|
public void LoadMainMenu()
|
|
{
|
|
Time.timeScale = 1f;
|
|
SceneManager.LoadScene("MainMenu");
|
|
}
|
|
}
|
|
}
|