/** * Neon Ping-Pong Audio Manager * Copyright (c) 2026 Wspólnie - wspolpraca@togethere.cloud * All rights reserved. Unauthorized copying, distribution, or modification is prohibited. * * Menedżer dźwięków dla gry Ping-Pong * Obsługuje wszystkie efekty dźwiękowe */ (function() { 'use strict'; class AudioManager { constructor(soundsPath = '/disciplines/ping-pong/sounds/') { this.soundsPath = soundsPath; this.enabled = true; this.volume = { effects: 0.3, music: 0.8 }; // Plik dźwiękowy dla zderzeń this.collisionSound = 'kick.mp3'; // Muzyka tła this.bgMusic = null; this.bgMusicVolume = 0.35; // Preload audio (opcjonalnie) this.audioCache = {}; this.preloadSounds(); } /** * Preloaduje dźwięki do cache (opcjonalnie) */ preloadSounds() { // Można odkomentować gdy pliki dźwiękowe będą dostępne /* const audio = new Audio(this.soundsPath + this.collisionSound); audio.preload = 'auto'; this.audioCache[this.collisionSound] = audio; */ } /** * Odtwarza dźwięk zderzenia */ playRandomSound() { if (!this.enabled) return; try { this.playSound(this.collisionSound, this.volume.effects); } catch(e) { console.log('Audio play failed:', e); } } /** * Odtwarza dźwięk wygranej */ playWinSound() { if (!this.enabled) return; try { this.playSound('won.mp3', this.volume.music); } catch(e) { console.log('Win sound failed:', e); } } /** * Odtwarza dźwięk przegranej */ playLoseSound() { if (!this.enabled) return; try { this.playSound('gameOver.mp3', this.volume.music); } catch(e) { console.log('Lose sound failed:', e); } } /** * Uniwersalna metoda do odtwarzania dźwięku * @param {String} soundFile - Nazwa pliku dźwiękowego * @param {Number} volume - Głośność (0-1) */ playSound(soundFile, volume = 0.3) { if (!this.enabled) return; try { // Sprawdź cache let audio; if (this.audioCache[soundFile]) { audio = this.audioCache[soundFile].cloneNode(); } else { audio = new Audio(this.soundsPath + soundFile); } audio.volume = volume; audio.play().catch(e => { console.log('Audio playback error:', e); }); } catch(e) { console.log('Audio error:', e); } } /** * Startuje muzykę tła odpowiednią dla trybu/trudności * @param {String} mode - 'bot' lub 'online' * @param {String} difficulty - 'easy', 'medium', 'hard', 'extreme' */ startBgMusic(mode, difficulty) { this.stopBgMusic(); if (!this.enabled) return; let file; if (mode === 'online') { const idx = Math.floor(Math.random() * 3) + 1; file = `onlinePingPong${idx}.mp3`; } else { const map = { easy: 'easyPingPong.mp3', medium: 'mediumPingPong.mp3', hard: 'hardPingPong.mp3', extreme: 'extremePingPong.mp3', }; file = map[difficulty] || 'easyPingPong.mp3'; } const volumeMap = { easy: 0.35, medium: 0.50, hard: 0.80, extreme: 1.00, }; if (mode === 'bot') { this.bgMusicVolume = volumeMap[difficulty] ?? 0.35; } else { this.bgMusicVolume = 0.50; } try { const audio = new Audio(this.soundsPath + file); audio.loop = true; audio.volume = this.bgMusicVolume; audio.play().catch(() => {}); this.bgMusic = audio; } catch (e) { console.log('BG music error:', e); } } /** * Zatrzymuje muzykę tła */ stopBgMusic() { if (this.bgMusic) { this.bgMusic.pause(); this.bgMusic.currentTime = 0; this.bgMusic = null; } } /** * Włącza/wyłącza dźwięki * @param {Boolean} enabled - Czy dźwięki mają być włączone */ setEnabled(enabled) { this.enabled = enabled; if (!enabled) this.stopBgMusic(); } /** * Ustawia głośność * @param {String} type - 'effects' lub 'music' * @param {Number} volume - Głośność (0-1) */ setVolume(type, volume) { if (this.volume.hasOwnProperty(type)) { this.volume[type] = Math.max(0, Math.min(1, volume)); } } /** * Pobiera aktualną głośność * @param {String} type - 'effects' lub 'music' * @returns {Number} Głośność (0-1) */ getVolume(type) { return this.volume[type] || 0; } /** * Zmienia ścieżkę do plików dźwiękowych * @param {String} path - Nowa ścieżka */ setSoundsPath(path) { this.soundsPath = path.endsWith('/') ? path : path + '/'; this.audioCache = {}; this.preloadSounds(); } } // Eksportuj klasę i utwórz instancję if (typeof window !== 'undefined') { window.AudioManager = AudioManager; window.audioManager = new AudioManager(); } })(); // End of IIFE