import { _decorator, Component, AudioClip, AudioSource, resources, Node } from 'cc'; const { ccclass, property } = _decorator; /** * 音频管理器 * 统一管理游戏中的音乐和音效播放 */ @ccclass('AudioManager') export class AudioManager extends Component { // 音频源组件 @property({ type: AudioSource, tooltip: '背景音乐播放器' }) public musicAudioSource: AudioSource = null; @property({ type: AudioSource, tooltip: 'UI音效播放器' }) public uiSoundAudioSource: AudioSource = null; @property({ type: AudioSource, tooltip: '敌人音效播放器' }) public enemySoundAudioSource: AudioSource = null; @property({ type: AudioSource, tooltip: '环境音效播放器' }) public environmentSoundAudioSource: AudioSource = null; @property({ type: AudioSource, tooltip: '武器音效播放器' }) public weaponSoundAudioSource: AudioSource = null; // 音量设置 private musicVolume: number = 0.8; private uiSoundVolume: number = 0.8; private enemySoundVolume: number = 0.8; private environmentSoundVolume: number = 0.8; private weaponSoundVolume: number = 0.8; // 主音效音量(向后兼容) private soundEffectVolume: number = 0.8; // 当前播放的音乐 private currentMusicClip: AudioClip = null; // 单例实例 private static _instance: AudioManager = null; onLoad() { // 设置单例 if (AudioManager._instance === null) { AudioManager._instance = this; // 防止场景切换时被销毁 // this.node.parent = null; // director.addPersistRootNode(this.node); } else { this.node.destroy(); return; } this.initializeAudioSources(); } /** * 获取单例实例 */ public static getInstance(): AudioManager { return AudioManager._instance; } /** * 初始化音频源 */ private initializeAudioSources() { // 如果没有指定音频源,尝试自动创建 if (!this.musicAudioSource) { const musicNode = new Node('MusicAudioSource'); musicNode.parent = this.node; this.musicAudioSource = musicNode.addComponent(AudioSource); this.musicAudioSource.loop = true; } if (!this.uiSoundAudioSource) { const uiSfxNode = new Node('UISoundAudioSource'); uiSfxNode.parent = this.node; this.uiSoundAudioSource = uiSfxNode.addComponent(AudioSource); this.uiSoundAudioSource.loop = false; } if (!this.enemySoundAudioSource) { const enemySfxNode = new Node('EnemySoundAudioSource'); enemySfxNode.parent = this.node; this.enemySoundAudioSource = enemySfxNode.addComponent(AudioSource); this.enemySoundAudioSource.loop = false; } if (!this.environmentSoundAudioSource) { const envSfxNode = new Node('EnvironmentSoundAudioSource'); envSfxNode.parent = this.node; this.environmentSoundAudioSource = envSfxNode.addComponent(AudioSource); this.environmentSoundAudioSource.loop = false; } if (!this.weaponSoundAudioSource) { const weaponSfxNode = new Node('WeaponSoundAudioSource'); weaponSfxNode.parent = this.node; this.weaponSoundAudioSource = weaponSfxNode.addComponent(AudioSource); this.weaponSoundAudioSource.loop = false; } // 设置初始音量 this.updateAllVolumes(); } /** * 播放背景音乐 * @param musicPath 音乐资源路径 * @param loop 是否循环播放 */ public playMusic(musicPath: string, loop: boolean = true) { if (!this.musicAudioSource) { console.warn('[AudioManager] 音乐播放器未初始化'); return; } resources.load(musicPath, AudioClip, (err, clip) => { if (err) { console.error(`[AudioManager] 加载音乐失败: ${musicPath}`, err); return; } this.currentMusicClip = clip; this.musicAudioSource.clip = clip; this.musicAudioSource.loop = loop; this.musicAudioSource.play(); console.log(`[AudioManager] 播放音乐: ${musicPath}`); }); } /** * 停止背景音乐 */ public stopMusic() { if (this.musicAudioSource && this.musicAudioSource.playing) { this.musicAudioSource.stop(); console.log('[AudioManager] 停止音乐播放'); } } /** * 暂停背景音乐 */ public pauseMusic() { if (this.musicAudioSource && this.musicAudioSource.playing) { this.musicAudioSource.pause(); console.log('[AudioManager] 暂停音乐播放'); } } /** * 恢复背景音乐 */ public resumeMusic() { if (this.musicAudioSource && this.currentMusicClip) { this.musicAudioSource.play(); console.log('[AudioManager] 恢复音乐播放'); } } /** * 播放音效(向后兼容) * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) */ public playSoundEffect(sfxPath: string, volume?: number) { this.playUISound(sfxPath, volume); } /** * 播放UI音效 * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) */ public playUISound(sfxPath: string, volume?: number) { this.playSound(this.uiSoundAudioSource, sfxPath, volume, this.uiSoundVolume, 'UI音效'); } /** * 播放敌人音效 * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) */ public playEnemySound(sfxPath: string, volume?: number) { this.playSound(this.enemySoundAudioSource, sfxPath, volume, this.enemySoundVolume, '敌人音效'); } /** * 播放环境音效 * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) */ public playEnvironmentSound(sfxPath: string, volume?: number) { this.playSound(this.environmentSoundAudioSource, sfxPath, volume, this.environmentSoundVolume, '环境音效'); } /** * 播放武器音效 * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) */ public playWeaponSound(sfxPath: string, volume?: number) { this.playSound(this.weaponSoundAudioSource, sfxPath, volume, this.weaponSoundVolume, '武器音效'); } /** * 通用音效播放方法 * @param audioSource 音频源 * @param sfxPath 音效资源路径 * @param volume 音量(可选,0-1) * @param baseVolume 基础音量 * @param soundType 音效类型(用于日志) */ private playSound(audioSource: AudioSource, sfxPath: string, volume: number | undefined, baseVolume: number, soundType: string) { if (!audioSource) { console.warn(`[AudioManager] ${soundType}播放器未初始化`); return; } // 去掉.mp3后缀(如果存在) const cleanPath = sfxPath.endsWith('.mp3') ? sfxPath.slice(0, -4) : sfxPath; resources.load(cleanPath, AudioClip, (err, clip) => { if (err) { console.error(`[AudioManager] 加载${soundType}失败: ${cleanPath}`, err); return; } // 设置临时音量(如果指定) const originalVolume = audioSource.volume; if (volume !== undefined) { audioSource.volume = volume * baseVolume; } audioSource.playOneShot(clip); // 恢复原始音量 if (volume !== undefined) { audioSource.volume = originalVolume; } console.log(`[AudioManager] 播放${soundType}: ${cleanPath}`); }); } /** * 设置音乐音量 * @param volume 音量值(0-1) */ public setMusicVolume(volume: number) { this.musicVolume = Math.max(0, Math.min(1, volume)); this.updateMusicVolume(); //console.log(`[AudioManager] 设置音乐音量: ${this.musicVolume}`); } /** * 设置音效音量(向后兼容) * @param volume 音量值(0-1) */ public setSoundEffectVolume(volume: number) { this.soundEffectVolume = Math.max(0, Math.min(1, volume)); this.setUISoundVolume(volume); //console.log(`[AudioManager] 设置音效音量: ${this.soundEffectVolume}`); } /** * 设置UI音效音量 * @param volume 音量值(0-1) */ public setUISoundVolume(volume: number) { this.uiSoundVolume = Math.max(0, Math.min(1, volume)); this.updateUISoundVolume(); } /** * 设置敌人音效音量 * @param volume 音量值(0-1) */ public setEnemySoundVolume(volume: number) { this.enemySoundVolume = Math.max(0, Math.min(1, volume)); this.updateEnemySoundVolume(); } /** * 设置环境音效音量 * @param volume 音量值(0-1) */ public setEnvironmentSoundVolume(volume: number) { this.environmentSoundVolume = Math.max(0, Math.min(1, volume)); this.updateEnvironmentSoundVolume(); } /** * 设置武器音效音量 * @param volume 音量值(0-1) */ public setWeaponSoundVolume(volume: number) { this.weaponSoundVolume = Math.max(0, Math.min(1, volume)); this.updateWeaponSoundVolume(); } /** * 设置所有音效音量 * @param volume 音量值(0-1) */ public setAllSoundVolume(volume: number) { this.setUISoundVolume(volume); this.setEnemySoundVolume(volume); this.setEnvironmentSoundVolume(volume); this.setWeaponSoundVolume(volume); this.setSoundEffectVolume(volume); } /** * 获取音乐音量 */ public getMusicVolume(): number { return this.musicVolume; } /** * 获取音效音量(向后兼容) */ public getSoundEffectVolume(): number { return this.soundEffectVolume; } /** * 获取UI音效音量 */ public getUISoundVolume(): number { return this.uiSoundVolume; } /** * 获取敌人音效音量 */ public getEnemySoundVolume(): number { return this.enemySoundVolume; } /** * 获取环境音效音量 */ public getEnvironmentSoundVolume(): number { return this.environmentSoundVolume; } /** * 获取武器音效音量 */ public getWeaponSoundVolume(): number { return this.weaponSoundVolume; } /** * 更新音乐音量 */ private updateMusicVolume() { if (this.musicAudioSource) { this.musicAudioSource.volume = this.musicVolume; } } /** * 更新UI音效音量 */ private updateUISoundVolume() { if (this.uiSoundAudioSource) { this.uiSoundAudioSource.volume = this.uiSoundVolume; } } /** * 更新敌人音效音量 */ private updateEnemySoundVolume() { if (this.enemySoundAudioSource) { this.enemySoundAudioSource.volume = this.enemySoundVolume; } } /** * 更新环境音效音量 */ private updateEnvironmentSoundVolume() { if (this.environmentSoundAudioSource) { this.environmentSoundAudioSource.volume = this.environmentSoundVolume; } } /** * 更新武器音效音量 */ private updateWeaponSoundVolume() { if (this.weaponSoundAudioSource) { this.weaponSoundAudioSource.volume = this.weaponSoundVolume; } } /** * 更新所有音量 */ private updateAllVolumes() { this.updateMusicVolume(); this.updateUISoundVolume(); this.updateEnemySoundVolume(); this.updateEnvironmentSoundVolume(); this.updateWeaponSoundVolume(); } /** * 静音所有音频 */ public muteAll() { this.setMusicVolume(0); this.setAllSoundVolume(0); } /** * 恢复所有音频音量 */ public unmuteAll() { this.setMusicVolume(0.8); this.setAllSoundVolume(0.8); } /** * 静音所有音效(保留音乐) */ public muteAllSounds() { this.setAllSoundVolume(0); } /** * 恢复所有音效音量(保留音乐) */ public unmuteAllSounds() { this.setAllSoundVolume(0.8); } /** * 检查音乐是否正在播放 */ public isMusicPlaying(): boolean { return this.musicAudioSource && this.musicAudioSource.playing; } onDestroy() { if (AudioManager._instance === this) { AudioManager._instance = null; } } } /** * 音频管理器的静态接口 * 提供便捷的全局访问方法 */ export class Audio { /** * 播放背景音乐 */ static playMusic(musicPath: string, loop: boolean = true) { const manager = AudioManager.getInstance(); if (manager) { manager.playMusic(musicPath, loop); } } /** * 播放音效(向后兼容) */ static playSFX(sfxPath: string, volume?: number) { const manager = AudioManager.getInstance(); if (manager) { manager.playSoundEffect(sfxPath, volume); } } /** * 播放UI音效 */ static playUISound(sfxPath: string, volume?: number) { const manager = AudioManager.getInstance(); if (manager) { manager.playUISound(sfxPath, volume); } } /** * 播放敌人音效 */ static playEnemySound(sfxPath: string, volume?: number) { const manager = AudioManager.getInstance(); if (manager) { manager.playEnemySound(sfxPath, volume); } } /** * 播放环境音效 */ static playEnvironmentSound(sfxPath: string, volume?: number) { const manager = AudioManager.getInstance(); if (manager) { manager.playEnvironmentSound(sfxPath, volume); } } /** * 播放武器音效 */ static playWeaponSound(sfxPath: string, volume?: number) { const manager = AudioManager.getInstance(); if (manager) { manager.playWeaponSound(sfxPath, volume); } } /** * 设置音乐音量 */ static setMusicVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setMusicVolume(volume); } } /** * 设置音效音量(向后兼容) */ static setSFXVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setSoundEffectVolume(volume); } } /** * 设置UI音效音量 */ static setUISoundVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setUISoundVolume(volume); } } /** * 设置敌人音效音量 */ static setEnemySoundVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setEnemySoundVolume(volume); } } /** * 设置环境音效音量 */ static setEnvironmentSoundVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setEnvironmentSoundVolume(volume); } } /** * 设置武器音效音量 */ static setWeaponSoundVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setWeaponSoundVolume(volume); } } /** * 设置所有音效音量 */ static setAllSoundVolume(volume: number) { const manager = AudioManager.getInstance(); if (manager) { manager.setAllSoundVolume(volume); } } /** * 停止音乐 */ static stopMusic() { const manager = AudioManager.getInstance(); if (manager) { manager.stopMusic(); } } /** * 暂停音乐 */ static pauseMusic() { const manager = AudioManager.getInstance(); if (manager) { manager.pauseMusic(); } } /** * 恢复音乐 */ static resumeMusic() { const manager = AudioManager.getInstance(); if (manager) { manager.resumeMusic(); } } /** * 静音所有音频 */ static muteAll() { const manager = AudioManager.getInstance(); if (manager) { manager.muteAll(); } } /** * 恢复所有音频 */ static unmuteAll() { const manager = AudioManager.getInstance(); if (manager) { manager.unmuteAll(); } } /** * 静音所有音效(保留音乐) */ static muteAllSounds() { const manager = AudioManager.getInstance(); if (manager) { manager.muteAllSounds(); } } /** * 恢复所有音效(保留音乐) */ static unmuteAllSounds() { const manager = AudioManager.getInstance(); if (manager) { manager.unmuteAllSounds(); } } }