// ============================================== // AudioManager.cs - Audio-Verwaltung // ============================================== // Verwaltet Musik, Sound-Effekte und // Text-to-Speech fuer das Spiel. using System.Collections.Generic; using UnityEngine; namespace BreakpilotDrive { [System.Serializable] public class SoundEffect { public string name; public AudioClip clip; [Range(0f, 1f)] public float volume = 1f; [Range(0.5f, 1.5f)] public float pitch = 1f; public bool loop = false; } public class AudioManager : MonoBehaviour { public static AudioManager Instance { get; private set; } [Header("Audio Sources")] [SerializeField] private AudioSource musicSource; [SerializeField] private AudioSource sfxSource; [SerializeField] private AudioSource voiceSource; [Header("Musik")] [SerializeField] private AudioClip menuMusic; [SerializeField] private AudioClip gameMusic; [Header("Sound-Effekte")] [SerializeField] private SoundEffect[] soundEffects; [Header("Lautstaerke")] [Range(0f, 1f)] [SerializeField] private float masterVolume = 1f; [Range(0f, 1f)] [SerializeField] private float musicVolume = 0.5f; [Range(0f, 1f)] [SerializeField] private float sfxVolume = 1f; [Range(0f, 1f)] [SerializeField] private float voiceVolume = 1f; // Sound-Dictionary fuer schnellen Zugriff private Dictionary soundDict = new Dictionary(); void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); InitializeSounds(); LoadVolumeSettings(); } else { Destroy(gameObject); } } private void InitializeSounds() { soundDict.Clear(); foreach (var sound in soundEffects) { if (!string.IsNullOrEmpty(sound.name) && sound.clip != null) { soundDict[sound.name.ToLower()] = sound; } } } // ============================================== // Musik // ============================================== public void PlayMenuMusic() { PlayMusic(menuMusic); } public void PlayGameMusic() { PlayMusic(gameMusic); } public void PlayMusic(AudioClip clip) { if (musicSource == null || clip == null) return; if (musicSource.clip == clip && musicSource.isPlaying) return; musicSource.clip = clip; musicSource.volume = musicVolume * masterVolume; musicSource.loop = true; musicSource.Play(); } public void StopMusic() { if (musicSource != null) { musicSource.Stop(); } } public void PauseMusic() { if (musicSource != null) { musicSource.Pause(); } } public void ResumeMusic() { if (musicSource != null) { musicSource.UnPause(); } } // ============================================== // Sound-Effekte // ============================================== public void PlaySound(string soundName) { if (sfxSource == null) return; string key = soundName.ToLower(); if (soundDict.TryGetValue(key, out SoundEffect sound)) { sfxSource.pitch = sound.pitch; sfxSource.PlayOneShot(sound.clip, sound.volume * sfxVolume * masterVolume); } else { Debug.LogWarning($"Sound '{soundName}' nicht gefunden!"); } } public void PlaySound(AudioClip clip, float volume = 1f) { if (sfxSource == null || clip == null) return; sfxSource.PlayOneShot(clip, volume * sfxVolume * masterVolume); } // Vordefinierte Sound-Methoden public void PlayCoinSound() => PlaySound("coin"); public void PlayCrashSound() => PlaySound("crash"); public void PlayCorrectSound() => PlaySound("correct"); public void PlayWrongSound() => PlaySound("wrong"); public void PlayButtonSound() => PlaySound("button"); // ============================================== // Text-to-Speech (WebGL) // ============================================== public void Speak(string text) { if (string.IsNullOrEmpty(text)) return; #if UNITY_WEBGL && !UNITY_EDITOR SpeakWebGL(text); #else Debug.Log($"[TTS] {text}"); #endif } public void SpeakQuestion(QuizQuestion question) { if (question == null) return; Speak(question.question_text); // Optionen vorlesen (mit Verzoegerung) for (int i = 0; i < question.options.Length; i++) { string optionText = $"Option {i + 1}: {question.options[i]}"; // In WebGL: Verzoegerung ueber JavaScript #if UNITY_WEBGL && !UNITY_EDITOR SpeakDelayedWebGL(optionText, 1.5f + (i * 1.5f)); #else Debug.Log($"[TTS] {optionText}"); #endif } } public void SpeakFeedback(bool correct) { string message = correct ? "Richtig! Gut gemacht!" : "Nicht ganz. Versuch es nochmal!"; Speak(message); } public void StopSpeaking() { #if UNITY_WEBGL && !UNITY_EDITOR StopSpeakingWebGL(); #endif } // WebGL JavaScript Interop #if UNITY_WEBGL && !UNITY_EDITOR [System.Runtime.InteropServices.DllImport("__Internal")] private static extern void SpeakWebGL(string text); [System.Runtime.InteropServices.DllImport("__Internal")] private static extern void SpeakDelayedWebGL(string text, float delaySeconds); [System.Runtime.InteropServices.DllImport("__Internal")] private static extern void StopSpeakingWebGL(); #endif // ============================================== // Lautstaerke-Einstellungen // ============================================== public void SetMasterVolume(float volume) { masterVolume = Mathf.Clamp01(volume); UpdateAllVolumes(); SaveVolumeSettings(); } public void SetMusicVolume(float volume) { musicVolume = Mathf.Clamp01(volume); if (musicSource != null) { musicSource.volume = musicVolume * masterVolume; } SaveVolumeSettings(); } public void SetSFXVolume(float volume) { sfxVolume = Mathf.Clamp01(volume); SaveVolumeSettings(); } public void SetVoiceVolume(float volume) { voiceVolume = Mathf.Clamp01(volume); if (voiceSource != null) { voiceSource.volume = voiceVolume * masterVolume; } SaveVolumeSettings(); } private void UpdateAllVolumes() { if (musicSource != null) musicSource.volume = musicVolume * masterVolume; if (voiceSource != null) voiceSource.volume = voiceVolume * masterVolume; } private void SaveVolumeSettings() { PlayerPrefs.SetFloat("MasterVolume", masterVolume); PlayerPrefs.SetFloat("MusicVolume", musicVolume); PlayerPrefs.SetFloat("SFXVolume", sfxVolume); PlayerPrefs.SetFloat("VoiceVolume", voiceVolume); PlayerPrefs.Save(); } private void LoadVolumeSettings() { masterVolume = PlayerPrefs.GetFloat("MasterVolume", 1f); musicVolume = PlayerPrefs.GetFloat("MusicVolume", 0.5f); sfxVolume = PlayerPrefs.GetFloat("SFXVolume", 1f); voiceVolume = PlayerPrefs.GetFloat("VoiceVolume", 1f); UpdateAllVolumes(); } // Properties fuer UI-Sliders public float MasterVolume => masterVolume; public float MusicVolume => musicVolume; public float SFXVolume => sfxVolume; public float VoiceVolume => voiceVolume; } }