Add platform-specific implementations for assets, audio, WebSocket, and rendering on Desktop and WebAssembly platforms. Introduce embedded assets for WebAssembly and native file handling for Desktop. Add platform-specific chunk loading and game state synchronization.
This commit is contained in:
237
cmd/client/audio.go
Normal file
237
cmd/client/audio.go
Normal file
@@ -0,0 +1,237 @@
|
||||
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 // Muss mit der MP3 Sample-Rate übereinstimmen
|
||||
)
|
||||
|
||||
//go:embed assets/game.mp3
|
||||
var gameMusicData []byte
|
||||
|
||||
//go:embed assets/jump.wav
|
||||
var jumpSoundData []byte
|
||||
|
||||
//go:embed assets/pickupCoin.wav
|
||||
var coinSoundData []byte
|
||||
|
||||
//go:embed 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
|
||||
}
|
||||
Reference in New Issue
Block a user