Private
Public Access
1
0
Files
EscapeFromTeacher/cmd/client/audio.go
Sebastian Unterschütz 300d4b9086
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 8m22s
fix game
2026-03-21 20:46:47 +01:00

238 lines
5.3 KiB
Go

package main
import (
"bytes"
_ "embed"
"log"
"github.com/hajimehoshi/ebiten/v2/audio"
"github.com/hajimehoshi/ebiten/v2/audio/mp3"
"github.com/hajimehoshi/ebiten/v2/audio/wav"
)
const (
SampleRate = 44100
)
//go:embed web/assets/game.mp3
var gameMusicData []byte
//go:embed web/assets/jump.wav
var jumpSoundData []byte
//go:embed web/assets/pickupCoin.wav
var coinSoundData []byte
//go:embed web/assets/powerUp.wav
var powerUpSoundData []byte
// AudioSystem verwaltet Musik und Sound-Effekte
type AudioSystem struct {
audioContext *audio.Context
// Musik
musicPlayer *audio.Player
musicVolume float64
// Sound-Effekte
jumpSound []byte
coinSound []byte
powerUpSound []byte
sfxVolume float64
// Mute
muted bool
}
// NewAudioSystem erstellt ein neues Audio-System
func NewAudioSystem() *AudioSystem {
log.Println("🎵 Initialisiere Audio-System...")
ctx := audio.NewContext(SampleRate)
as := &AudioSystem{
audioContext: ctx,
musicVolume: 0.3, // 30% Standard-Lautstärke
sfxVolume: 0.5, // 50% Standard-Lautstärke
muted: false,
}
// Musik laden
log.Printf("📀 Lade Musik (%.2f MB)...", float64(len(gameMusicData))/(1024*1024))
as.loadMusic()
// Sound-Effekte dekodieren
log.Println("🔊 Lade Sound-Effekte...")
as.jumpSound = as.loadWav(jumpSoundData)
as.coinSound = as.loadWav(coinSoundData)
as.powerUpSound = as.loadWav(powerUpSoundData)
log.Println("✅ Audio-System bereit")
return as
}
// loadMusic lädt und startet die Hintergrundmusik
func (as *AudioSystem) loadMusic() {
// MP3 dekodieren
stream, err := mp3.DecodeWithSampleRate(SampleRate, bytes.NewReader(gameMusicData))
if err != nil {
log.Printf("❌ Fehler beim Laden der Musik: %v", err)
return
}
// Infinite Loop
loop := audio.NewInfiniteLoop(stream, stream.Length())
// Player erstellen
player, err := as.audioContext.NewPlayer(loop)
if err != nil {
log.Printf("❌ Fehler beim Erstellen des Music Players: %v", err)
return
}
as.musicPlayer = player
as.updateMusicVolume()
log.Println("🎵 Musik geladen")
}
// loadWav lädt eine WAV-Datei und gibt die dekodierten Bytes zurück
func (as *AudioSystem) loadWav(data []byte) []byte {
stream, err := wav.DecodeWithSampleRate(SampleRate, bytes.NewReader(data))
if err != nil {
log.Printf("❌ Fehler beim Laden von WAV: %v", err)
return nil
}
// Stream in Bytes lesen
decoded := bytes.NewBuffer(nil)
_, err = decoded.ReadFrom(stream)
if err != nil {
log.Printf("❌ Fehler beim Dekodieren von WAV: %v", err)
return nil
}
return decoded.Bytes()
}
// PlayMusic startet die Hintergrundmusik
func (as *AudioSystem) PlayMusic() {
if as.musicPlayer == nil {
log.Println("⚠️ Music Player ist nil - Musik kann nicht gestartet werden")
return
}
if as.musicPlayer.IsPlaying() {
log.Println("⚠️ Musik läuft bereits")
return
}
as.musicPlayer.Play()
log.Printf("▶️ Musik gestartet (Volume: %.2f, Muted: %v)", as.musicVolume, as.muted)
}
// StopMusic stoppt die Hintergrundmusik
func (as *AudioSystem) StopMusic() {
if as.musicPlayer != nil && as.musicPlayer.IsPlaying() {
as.musicPlayer.Pause()
log.Println("⏸️ Musik gestoppt")
}
}
// PlayJump spielt den Jump-Sound ab
func (as *AudioSystem) PlayJump() {
if as.muted {
return
}
as.playSoundEffect(as.jumpSound, as.sfxVolume)
}
// PlayCoin spielt den Coin-Pickup-Sound ab
func (as *AudioSystem) PlayCoin() {
if as.muted {
return
}
as.playSoundEffect(as.coinSound, as.sfxVolume)
}
// PlayPowerUp spielt den PowerUp-Sound ab
func (as *AudioSystem) PlayPowerUp() {
if as.muted {
return
}
as.playSoundEffect(as.powerUpSound, as.sfxVolume)
}
// playSoundEffect spielt einen Sound-Effekt ab
func (as *AudioSystem) playSoundEffect(soundData []byte, volume float64) {
if soundData == nil {
return
}
player := as.audioContext.NewPlayerFromBytes(soundData)
if player == nil {
return
}
player.SetVolume(volume)
player.Play()
}
// SetMusicVolume setzt die Musik-Lautstärke (0.0 - 1.0)
func (as *AudioSystem) SetMusicVolume(volume float64) {
as.musicVolume = clamp(volume, 0.0, 1.0)
as.updateMusicVolume()
}
// SetSFXVolume setzt die Sound-Effekt-Lautstärke (0.0 - 1.0)
func (as *AudioSystem) SetSFXVolume(volume float64) {
as.sfxVolume = clamp(volume, 0.0, 1.0)
}
// ToggleMute schaltet Mute an/aus
func (as *AudioSystem) ToggleMute() {
as.muted = !as.muted
as.updateMusicVolume()
log.Printf("🔇 Mute: %v", as.muted)
}
// SetMuted setzt Mute-Status
func (as *AudioSystem) SetMuted(muted bool) {
as.muted = muted
as.updateMusicVolume()
}
// IsMuted gibt zurück, ob der Sound gemutet ist
func (as *AudioSystem) IsMuted() bool {
return as.muted
}
// GetMusicVolume gibt die aktuelle Musik-Lautstärke zurück
func (as *AudioSystem) GetMusicVolume() float64 {
return as.musicVolume
}
// GetSFXVolume gibt die aktuelle SFX-Lautstärke zurück
func (as *AudioSystem) GetSFXVolume() float64 {
return as.sfxVolume
}
// updateMusicVolume aktualisiert die Musik-Lautstärke
func (as *AudioSystem) updateMusicVolume() {
if as.musicPlayer != nil {
if as.muted {
as.musicPlayer.SetVolume(0)
} else {
as.musicPlayer.SetVolume(as.musicVolume)
}
}
}
// clamp begrenzt einen Wert zwischen min und max
func clamp(value, min, max float64) float64 {
if value < min {
return min
}
if value > max {
return max
}
return value
}