This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/breakpilot-drive/UnityScripts/Core/DifficultyManager.cs
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
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>
2026-02-09 09:51:32 +01:00

293 lines
9.5 KiB
C#

// ==============================================
// DifficultyManager.cs - Schwierigkeits-Steuerung
// ==============================================
// Passt die Spielschwierigkeit dynamisch an
// basierend auf Lernniveau und Spielerleistung.
using System;
using UnityEngine;
namespace BreakpilotDrive
{
public class DifficultyManager : MonoBehaviour
{
public static DifficultyManager Instance { get; private set; }
[Header("Schwierigkeits-Bereich")]
[SerializeField] private int minDifficulty = 1;
[SerializeField] private int maxDifficulty = 5;
[Header("Dynamische Anpassung")]
[SerializeField] private bool enableDynamicDifficulty = true;
[SerializeField] private int questionsForEvaluation = 5;
[SerializeField] private float accuracyToIncrease = 0.8f; // 80% richtig = schwerer
[SerializeField] private float accuracyToDecrease = 0.4f; // 40% richtig = leichter
[Header("Geschwindigkeits-Steigerung")]
[SerializeField] private bool enableSpeedIncrease = true;
[SerializeField] private float speedIncreaseInterval = 30f; // Alle X Sekunden
[SerializeField] private float speedIncreaseAmount = 0.5f; // Um X erhoehen
// Aktueller Zustand
private int currentDifficulty = 3;
private GameDifficulty currentSettings;
private float timeSinceLastSpeedIncrease = 0f;
// Statistik fuer dynamische Anpassung
private int recentQuestionsAnswered = 0;
private int recentQuestionsCorrect = 0;
// Events
public event Action<int> OnDifficultyChanged;
public event Action<GameDifficulty> OnSettingsUpdated;
// Properties
public int CurrentDifficulty => currentDifficulty;
public GameDifficulty CurrentSettings => currentSettings;
void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
void Start()
{
// Quiz-Events abonnieren
if (QuizManager.Instance != null)
{
QuizManager.Instance.OnQuestionAnswered += OnQuestionAnswered;
}
// Initiale Schwierigkeit laden
LoadDifficulty(currentDifficulty);
}
void OnDestroy()
{
if (QuizManager.Instance != null)
{
QuizManager.Instance.OnQuestionAnswered -= OnQuestionAnswered;
}
}
void Update()
{
if (GameManager.Instance?.CurrentState != GameState.Playing)
return;
// Geschwindigkeit graduell erhoehen
if (enableSpeedIncrease)
{
timeSinceLastSpeedIncrease += Time.deltaTime;
if (timeSinceLastSpeedIncrease >= speedIncreaseInterval)
{
timeSinceLastSpeedIncrease = 0f;
IncreaseSpeed();
}
}
}
// ==============================================
// Schwierigkeit laden
// ==============================================
public void LoadDifficulty(int level)
{
currentDifficulty = Mathf.Clamp(level, minDifficulty, maxDifficulty);
if (BreakpilotAPI.Instance != null)
{
StartCoroutine(BreakpilotAPI.Instance.GetDifficulty(currentDifficulty,
onSuccess: (settings) =>
{
currentSettings = settings;
ApplySettings(settings);
OnSettingsUpdated?.Invoke(settings);
Debug.Log($"Schwierigkeit {currentDifficulty} geladen");
},
onError: (error) =>
{
Debug.LogWarning($"Konnte Schwierigkeit nicht laden: {error}");
// Fallback zu Default-Werten
currentSettings = GetDefaultSettings(currentDifficulty);
ApplySettings(currentSettings);
}
));
}
else
{
currentSettings = GetDefaultSettings(currentDifficulty);
ApplySettings(currentSettings);
}
OnDifficultyChanged?.Invoke(currentDifficulty);
}
private void ApplySettings(GameDifficulty settings)
{
// Geschwindigkeit anwenden
if (TrackGenerator.Instance != null)
{
TrackGenerator.Instance.SetSpeed(settings.lane_speed);
}
if (PlayerController.Instance != null)
{
PlayerController.Instance.SetSpeed(settings.lane_speed);
}
// Hindernis-Frequenz anwenden
// ObstacleSpawner liest die Settings direkt aus GameManager
Debug.Log($"Settings angewendet: Speed={settings.lane_speed}, " +
$"Obstacles={settings.obstacle_frequency}, " +
$"Hints={settings.hints_enabled}");
}
// ==============================================
// Dynamische Anpassung
// ==============================================
private void OnQuestionAnswered(bool correct, int points)
{
if (!enableDynamicDifficulty) return;
recentQuestionsAnswered++;
if (correct) recentQuestionsCorrect++;
// Evaluation nach X Fragen
if (recentQuestionsAnswered >= questionsForEvaluation)
{
EvaluateAndAdjust();
}
}
private void EvaluateAndAdjust()
{
float accuracy = (float)recentQuestionsCorrect / recentQuestionsAnswered;
Debug.Log($"Quiz-Evaluation: {recentQuestionsCorrect}/{recentQuestionsAnswered} " +
$"= {accuracy:P0}");
if (accuracy >= accuracyToIncrease && currentDifficulty < maxDifficulty)
{
// Spieler ist gut - Schwierigkeit erhoehen
IncreaseDifficulty();
}
else if (accuracy <= accuracyToDecrease && currentDifficulty > minDifficulty)
{
// Spieler hat Probleme - Schwierigkeit verringern
DecreaseDifficulty();
}
// Reset fuer naechste Evaluation
recentQuestionsAnswered = 0;
recentQuestionsCorrect = 0;
}
public void IncreaseDifficulty()
{
if (currentDifficulty < maxDifficulty)
{
LoadDifficulty(currentDifficulty + 1);
Debug.Log($"Schwierigkeit erhoeht auf {currentDifficulty}");
}
}
public void DecreaseDifficulty()
{
if (currentDifficulty > minDifficulty)
{
LoadDifficulty(currentDifficulty - 1);
Debug.Log($"Schwierigkeit verringert auf {currentDifficulty}");
}
}
// ==============================================
// Geschwindigkeits-Steigerung
// ==============================================
private void IncreaseSpeed()
{
if (currentSettings == null) return;
float newSpeed = currentSettings.lane_speed + speedIncreaseAmount;
// Maximal-Geschwindigkeit basierend auf Difficulty
float maxSpeed = 5f + (currentDifficulty * 2f);
newSpeed = Mathf.Min(newSpeed, maxSpeed);
currentSettings.lane_speed = newSpeed;
if (TrackGenerator.Instance != null)
{
TrackGenerator.Instance.SetSpeed(newSpeed);
}
Debug.Log($"Geschwindigkeit erhoeht auf {newSpeed:F1}");
}
// ==============================================
// Default-Werte (Fallback)
// ==============================================
private GameDifficulty GetDefaultSettings(int level)
{
return new GameDifficulty
{
lane_speed = 4f + level,
obstacle_frequency = 0.3f + (level * 0.1f),
power_up_chance = 0.4f - (level * 0.05f),
question_complexity = level,
answer_time = 15 - (level * 2),
hints_enabled = level <= 2,
speech_speed = 0.8f + (level * 0.1f)
};
}
// ==============================================
// Oeffentliche Methoden
// ==============================================
public void SetDifficulty(int level)
{
LoadDifficulty(level);
}
public void ResetForNewGame()
{
recentQuestionsAnswered = 0;
recentQuestionsCorrect = 0;
timeSinceLastSpeedIncrease = 0f;
// Schwierigkeit von User-Level laden
if (BreakpilotAPI.Instance != null)
{
var cachedLevel = BreakpilotAPI.Instance.GetCachedLevel();
if (cachedLevel != null)
{
LoadDifficulty(cachedLevel.overall_level);
}
}
}
public float GetCurrentSpeed()
{
return currentSettings?.lane_speed ?? 5f;
}
public bool AreHintsEnabled()
{
return currentSettings?.hints_enabled ?? false;
}
public int GetAnswerTime()
{
return currentSettings?.answer_time ?? 10;
}
}
}