// ============================================== // 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 OnDifficultyChanged; public event Action 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; } } }