import { assetManager, AudioClip, AudioSource, director, Node, sys } from 'cc'; import { LocalStorageMgr } from './game/LocalStorageMgr'; export class AudioManager { /** 单例模式 */ private static _ins: AudioManager; constructor() { const audioMgr = new Node(); audioMgr.name = '__audioMgr__'; AudioManager._ins = this; director.getScene().addChild(audioMgr); director.addPersistRootNode(audioMgr); // 创建一个 AudioSource 用于背景音乐 this._bgmAudioSource = audioMgr.addComponent(AudioSource); // 创建一个 AudioSource 用于effect音效 this._effectAudioSource = audioMgr.addComponent(AudioSource); // 创建一个 AudioSource 用于可在随意时间停止的音效 this._effectDiAudioSource = audioMgr.addComponent(AudioSource); // 从本地存储恢复静音状态 const effectMuteState: boolean = LocalStorageMgr.getItem('audio_effectMute'); const bgmMuteState: boolean = LocalStorageMgr.getItem('audio_bgmMute'); this.effectMute = effectMuteState ?? false; this.bgmMute = bgmMuteState ?? false; this._updateBGMVolume(); } public static get ins(): AudioManager { if (!AudioManager._ins) { AudioManager._ins = new AudioManager(); } return AudioManager._ins; } private _bgmAudioSource: AudioSource; private _effectAudioSource: AudioSource; private _effectDiAudioSource: AudioSource; private bgmVolume = 1.0; private soundVolume = 1.0; private _isEffectMuted: boolean = false; private _isBGMMuted: boolean = false; private _activeOneShotSources: Map = new Map(); public get effectMute() { if (this._isEffectMuted === undefined) { this.effectMute = LocalStorageMgr.getItem('audio_effectMute') ?? false; } return this._isEffectMuted; } public set effectMute(muted: boolean) { this._isEffectMuted = muted; LocalStorageMgr.setItem('audio_effectMute', muted); } public get bgmMute() { if (this._isBGMMuted === undefined) { this.bgmMute = LocalStorageMgr.getItem('audio_bgmMute') ?? false; } return this._isBGMMuted; } public set bgmMute(muted: boolean) { this._isBGMMuted = muted; LocalStorageMgr.setItem('audio_bgmMute', muted); this._updateBGMVolume(muted); } private _updateBGMVolume(mute?: boolean) { mute = mute ?? this.bgmMute; this._bgmAudioSource.volume = mute ? 0 : 1; } playOneShot(sound: AudioClip | string, volume: number = 1.0, bundleName: string = 'resources') { if (this._isEffectMuted) return; // 如果音效静音,直接返回 if (sound instanceof AudioClip) { this._effectAudioSource.playOneShot(sound, volume); } else { let bundle = assetManager.getBundle(bundleName); bundle.load(sound, (err, clip: AudioClip) => { if (err) { console.log(err); } else { this._effectAudioSource.playOneShot(clip, volume); } }); } } /** 播放一个短音效,可以控制停止暂停 */ playEff(sound: AudioClip | string, bundleName: string = 'resources') { if (this._isEffectMuted) return; // 如果音效静音,直接返回 if (sound instanceof AudioClip) { this._effectDiAudioSource.stop(); this._effectDiAudioSource.clip = sound; this._effectDiAudioSource.loop = false; // 不循环播放 this._effectDiAudioSource.play(); } else { let bundle = assetManager.getBundle(bundleName); bundle.load(sound, (err, clip: AudioClip) => { if (err) { console.log(err); } else { this._effectDiAudioSource.stop(); this._effectDiAudioSource.clip = clip; this._effectDiAudioSource.loop = false; // 不循环播放 this._effectDiAudioSource.play(); } }); } } /** * 停止播放playEff指定的短音效 */ stopPlayEff(sound: AudioClip | string) { const audioSource = this._effectDiAudioSource; if (audioSource) { audioSource.stop(); } else { console.log(`Sound ${sound} is not currently playing.`); } } play(sound: AudioClip | string, loop: boolean = true, bundleName: string = 'resources') { if (this.bgmMute) { this.bgmVolume = 0 } else { this.bgmVolume = 1; } if (sound instanceof AudioClip) { this._bgmAudioSource.stop(); this._bgmAudioSource.clip = sound; this._bgmAudioSource.loop = loop; this._bgmAudioSource.play(); this._updateBGMVolume(); } else { const bundle = assetManager.getBundle(bundleName); if (!bundle) { // console.error(`Bundle ${bundleName} not found.`); return; } bundle.load(sound, (err, clip: AudioClip) => { if (err) { // console.error(`Failed to load sound ${sound}: ${err}`); } else if (clip) { this._bgmAudioSource.stop(); this._bgmAudioSource.clip = clip; this._bgmAudioSource.loop = loop; this._bgmAudioSource.play(); this._updateBGMVolume(); } }); } } stopBgm() { this._bgmAudioSource.stop(); } pauseBgm() { this._bgmAudioSource.pause(); } resumeBgm() { this._bgmAudioSource.play(); } }