mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-20 13:50:46 +00:00
286 lines
10 KiB
JavaScript
286 lines
10 KiB
JavaScript
/**
|
|
* Sound Manager
|
|
* Centralized system for managing audio playback in Break Escape
|
|
*
|
|
* Uses Phaser's sound system for playback, caching, and effects.
|
|
* Provides convenient methods for playing common game sounds.
|
|
*/
|
|
|
|
class SoundManager {
|
|
constructor(phaserScene) {
|
|
this.scene = phaserScene;
|
|
this.sounds = {};
|
|
this.enabled = true;
|
|
this.masterVolume = 1.0;
|
|
|
|
// Sound volume categories (0-1)
|
|
this.volumeSettings = {
|
|
ui: 0.7,
|
|
interactions: 0.8,
|
|
notifications: 0.6,
|
|
effects: 0.85,
|
|
music: 0.5
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Load all sound assets into Phaser
|
|
* Called during the preload phase
|
|
*/
|
|
preloadSounds() {
|
|
// Lockpicking mini-game sounds
|
|
this.scene.load.audio('lockpick_binding', 'assets/sounds/lockpick_binding.mp3');
|
|
this.scene.load.audio('lockpick_click', 'assets/sounds/lockpick_click.mp3');
|
|
this.scene.load.audio('lockpick_overtension', 'assets/sounds/lockpick_overtension.mp3');
|
|
this.scene.load.audio('lockpick_reset', 'assets/sounds/lockpick_reset.mp3');
|
|
this.scene.load.audio('lockpick_set', 'assets/sounds/lockpick_set.mp3');
|
|
this.scene.load.audio('lockpick_success', 'assets/sounds/lockpick_success.mp3');
|
|
this.scene.load.audio('lockpick_tension', 'assets/sounds/lockpick_tension.mp3');
|
|
this.scene.load.audio('lockpick_wrong', 'assets/sounds/lockpick_wrong.mp3');
|
|
|
|
// GASP door sounds
|
|
this.scene.load.audio('door_knock', 'assets/sounds/GASP_Door Knock.mp3');
|
|
|
|
// GASP interaction sounds
|
|
this.scene.load.audio('item_interact_1', 'assets/sounds/GASP_Item Interact_1.mp3');
|
|
this.scene.load.audio('item_interact_2', 'assets/sounds/GASP_Item Interact_2.mp3');
|
|
this.scene.load.audio('item_interact_3', 'assets/sounds/GASP_Item Interact_3.mp3');
|
|
|
|
// GASP lock interaction sounds
|
|
this.scene.load.audio('lock_interact_1', 'assets/sounds/GASP_Lock Interact_1.mp3');
|
|
this.scene.load.audio('lock_interact_2', 'assets/sounds/GASP_Lock Interact_2.mp3');
|
|
this.scene.load.audio('lock_interact_3', 'assets/sounds/GASP_Lock Interact_3.mp3');
|
|
this.scene.load.audio('lock_interact_4', 'assets/sounds/GASP_Lock Interact_4.mp3');
|
|
this.scene.load.audio('lock_and_load', 'assets/sounds/GASP_Lock and Load.mp3');
|
|
|
|
// GASP UI click sounds
|
|
this.scene.load.audio('ui_click_1', 'assets/sounds/GASP_UI_Clicks_1.mp3');
|
|
this.scene.load.audio('ui_click_2', 'assets/sounds/GASP_UI_Clicks_2.mp3');
|
|
this.scene.load.audio('ui_click_3', 'assets/sounds/GASP_UI_Clicks_3.mp3');
|
|
this.scene.load.audio('ui_click_4', 'assets/sounds/GASP_UI_Clicks_4.mp3');
|
|
this.scene.load.audio('ui_click_6', 'assets/sounds/GASP_UI_Clicks_6.mp3');
|
|
|
|
// GASP UI alert sounds
|
|
this.scene.load.audio('ui_alert_1', 'assets/sounds/GASP_UI_Alert_1.mp3');
|
|
this.scene.load.audio('ui_alert_2', 'assets/sounds/GASP_UI_Alert_2.mp3');
|
|
|
|
// GASP UI confirm sound
|
|
this.scene.load.audio('ui_confirm', 'assets/sounds/GASP_UI_Confirm.mp3');
|
|
|
|
// GASP UI notification sounds
|
|
this.scene.load.audio('ui_notification_1', 'assets/sounds/GASP_UI_Notification_1.mp3');
|
|
this.scene.load.audio('ui_notification_2', 'assets/sounds/GASP_UI_Notification_2.mp3');
|
|
this.scene.load.audio('ui_notification_3', 'assets/sounds/GASP_UI_Notification_3.mp3');
|
|
this.scene.load.audio('ui_notification_4', 'assets/sounds/GASP_UI_Notification_4.mp3');
|
|
this.scene.load.audio('ui_notification_5', 'assets/sounds/GASP_UI_Notification_5.mp3');
|
|
this.scene.load.audio('ui_notification_6', 'assets/sounds/GASP_UI_Notification_6.mp3');
|
|
|
|
// GASP UI reject sound
|
|
this.scene.load.audio('ui_reject', 'assets/sounds/GASP_UI_Reject.mp3');
|
|
|
|
// Game-specific sounds
|
|
this.scene.load.audio('chair_roll', 'assets/sounds/chair_roll.mp3');
|
|
this.scene.load.audio('message_received', 'assets/sounds/message_received.mp3');
|
|
}
|
|
|
|
/**
|
|
* Initialize sound objects after preload
|
|
* Called during scene creation
|
|
*/
|
|
initializeSounds() {
|
|
// Create all sound objects
|
|
const soundNames = [
|
|
// Lockpicking
|
|
'lockpick_binding', 'lockpick_click', 'lockpick_overtension',
|
|
'lockpick_reset', 'lockpick_set', 'lockpick_success',
|
|
'lockpick_tension', 'lockpick_wrong',
|
|
// Door
|
|
'door_knock',
|
|
// Interactions
|
|
'item_interact_1', 'item_interact_2', 'item_interact_3',
|
|
'lock_interact_1', 'lock_interact_2', 'lock_interact_3', 'lock_interact_4', 'lock_and_load',
|
|
// UI clicks
|
|
'ui_click_1', 'ui_click_2', 'ui_click_3', 'ui_click_4', 'ui_click_6',
|
|
// UI alerts
|
|
'ui_alert_1', 'ui_alert_2',
|
|
// UI confirm
|
|
'ui_confirm',
|
|
// UI notifications
|
|
'ui_notification_1', 'ui_notification_2', 'ui_notification_3',
|
|
'ui_notification_4', 'ui_notification_5', 'ui_notification_6',
|
|
// UI reject
|
|
'ui_reject',
|
|
// Game sounds
|
|
'chair_roll', 'message_received'
|
|
];
|
|
|
|
for (const soundName of soundNames) {
|
|
try {
|
|
this.sounds[soundName] = this.scene.sound.add(soundName, {
|
|
volume: this.getVolumeForSound(soundName)
|
|
});
|
|
} catch (error) {
|
|
console.warn(`Failed to initialize sound: ${soundName}`, error);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine volume level based on sound category
|
|
*/
|
|
getVolumeForSound(soundName) {
|
|
let category = 'effects';
|
|
if (soundName.includes('ui_click') || soundName.includes('ui_confirm')) category = 'ui';
|
|
else if (soundName.includes('ui_alert') || soundName.includes('ui_notification') || soundName.includes('ui_reject')) category = 'notifications';
|
|
else if (soundName.includes('lockpick') || soundName.includes('chair')) category = 'effects';
|
|
else if (soundName.includes('item_interact') || soundName.includes('lock_interact') || soundName.includes('door_knock')) category = 'interactions';
|
|
else if (soundName.includes('message_received')) category = 'notifications';
|
|
|
|
return this.volumeSettings[category] * this.masterVolume;
|
|
}
|
|
|
|
/**
|
|
* Play a sound by name
|
|
* @param {string} soundName - Name of the sound to play
|
|
* @param {Object} options - Optional: { volume, loop, delay }
|
|
*/
|
|
play(soundName, options = {}) {
|
|
if (!this.enabled) return;
|
|
|
|
// console log
|
|
console.log(`🔊 Playing sound: ${soundName}`);
|
|
|
|
const sound = this.sounds[soundName];
|
|
if (!sound) {
|
|
console.warn(`Sound not found: ${soundName}`);
|
|
return;
|
|
}
|
|
|
|
// Set volume if specified
|
|
if (options.volume !== undefined) {
|
|
sound.setVolume(options.volume * this.masterVolume);
|
|
} else {
|
|
sound.setVolume(this.getVolumeForSound(soundName));
|
|
}
|
|
|
|
// Set loop if specified
|
|
if (options.loop !== undefined) {
|
|
sound.setLoop(options.loop);
|
|
}
|
|
|
|
// Set delay if specified
|
|
if (options.delay !== undefined) {
|
|
this.scene.time.delayedCall(options.delay, () => {
|
|
if (sound && !sound.isPlaying) {
|
|
sound.play();
|
|
}
|
|
});
|
|
} else {
|
|
sound.play();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop a sound by name
|
|
*/
|
|
stop(soundName) {
|
|
const sound = this.sounds[soundName];
|
|
if (sound) {
|
|
sound.stop();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop all sounds
|
|
*/
|
|
stopAll() {
|
|
for (const sound of Object.values(this.sounds)) {
|
|
if (sound && sound.isPlaying) {
|
|
sound.stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Play a random UI click sound
|
|
*/
|
|
playUIClick() {
|
|
const clicks = ['ui_click_1', 'ui_click_2', 'ui_click_3', 'ui_click_4', 'ui_click_6'];
|
|
const randomClick = clicks[Math.floor(Math.random() * clicks.length)];
|
|
this.play(randomClick);
|
|
}
|
|
|
|
/**
|
|
* Play a random UI notification sound
|
|
*/
|
|
playUINotification() {
|
|
const notifications = ['ui_notification_1', 'ui_notification_2', 'ui_notification_3', 'ui_notification_4', 'ui_notification_5', 'ui_notification_6'];
|
|
const randomNotification = notifications[Math.floor(Math.random() * notifications.length)];
|
|
this.play(randomNotification);
|
|
}
|
|
|
|
/**
|
|
* Play a random item interaction sound
|
|
*/
|
|
playItemInteract() {
|
|
const sounds = ['item_interact_1', 'item_interact_2', 'item_interact_3'];
|
|
const randomSound = sounds[Math.floor(Math.random() * sounds.length)];
|
|
this.play(randomSound);
|
|
}
|
|
|
|
/**
|
|
* Play a random lock interaction sound
|
|
*/
|
|
playLockInteract() {
|
|
const sounds = ['lock_interact_1', 'lock_interact_2', 'lock_interact_3', 'lock_interact_4'];
|
|
const randomSound = sounds[Math.floor(Math.random() * sounds.length)];
|
|
this.play(randomSound);
|
|
}
|
|
|
|
/**
|
|
* Set master volume (0-1)
|
|
*/
|
|
setMasterVolume(volume) {
|
|
this.masterVolume = Math.max(0, Math.min(1, volume));
|
|
// Update all active sounds
|
|
for (const sound of Object.values(this.sounds)) {
|
|
if (sound) {
|
|
sound.setVolume(this.getVolumeForSound(sound.key));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set category volume
|
|
*/
|
|
setCategoryVolume(category, volume) {
|
|
if (this.volumeSettings[category] !== undefined) {
|
|
this.volumeSettings[category] = Math.max(0, Math.min(1, volume));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Toggle sound on/off
|
|
*/
|
|
toggle() {
|
|
this.enabled = !this.enabled;
|
|
return this.enabled;
|
|
}
|
|
|
|
/**
|
|
* Set enabled/disabled
|
|
*/
|
|
setEnabled(enabled) {
|
|
this.enabled = enabled;
|
|
}
|
|
|
|
/**
|
|
* Check if sounds are enabled
|
|
*/
|
|
isEnabled() {
|
|
return this.enabled;
|
|
}
|
|
}
|
|
|
|
export default SoundManager;
|