import { _decorator, AudioClip, AudioSource } from 'cc'; interface ISoundOptions { volume?: number; loop?: boolean; playbackRate?: number; } export class SoundSource { private _source: AudioSource; public get playing() { return this._source.playing; } public get loop() { return this._source.loop; } public set loop(value: boolean) { this._source.loop = value; } private _volume = 1; public get volume() { return this._volume; } public set volume(value: number) { this._volume = value; if (!this.mute) { this._source.volume = value; } } private _mute = false; public get mute() { return this._mute; } public set mute(value: boolean) { if (value) { this._source.volume = 0; } else { this._source.volume = this.volume; } this._mute = value; } public get clip() { return this._source.clip; } public set clip(value: AudioClip) { this._source.clip = value; } public get playbackRate() { return this._source.getPlaybackRate(); } public set playbackRate(value: number) { this._source.setPlaybackRate(value); } constructor(audioClip: AudioClip) { this._source = new AudioSource(); this._source.playOnAwake = false; this._source.clip = audioClip; } public play() { if (!this.loop) { if (this.playing) { this._source.playOneShot(this._source.clip, this.mute ? 0 : this.volume); return; } this._source.play(); } else { if (!this.playing) this._source.play(); } } public stop() { this._source.stop(); } } export default class AudioManager { private static readonly storageKey = 'gad-game-galaxy-seeker-mute'; private static _audioSourcesSfx: Map = new Map(); private static _audioSourceBgm: SoundSource; private static _isMute: boolean = false; public static get mute() { return this._isMute; } public static toggleMute(): boolean { this._isMute = !this._isMute; this.setMute(this._isMute); return this._isMute; } public static setMute(mute: boolean) { this._audioSourceBgm.mute = mute; this._audioSourcesSfx.forEach((source) => { source.mute = mute; }); this._isMute = mute; } public static playBGM(audio: AudioClip, opts?: ISoundOptions) { const config: ISoundOptions = { volume: 1, loop: true, playbackRate: 1, ...opts, }; if (this._audioSourceBgm) { this._audioSourceBgm.stop(); this._audioSourceBgm.clip = audio; } else { this._audioSourceBgm = new SoundSource(audio); } this._audioSourceBgm.loop = config.loop; this._audioSourceBgm.volume = config.volume; this._audioSourceBgm.playbackRate = config.playbackRate; this._audioSourceBgm.mute = this._isMute; this._audioSourceBgm.play(); } public static setPlayRateBGM(rate: number) { this._audioSourceBgm.playbackRate = rate; } public static playSfx(audioClip: AudioClip, opts?: ISoundOptions) { let soundSource = this._audioSourcesSfx.get(audioClip); const config: ISoundOptions = { volume: 1, loop: false, playbackRate: 1, ...opts, }; if (soundSource) { soundSource.volume = config.volume; soundSource.loop = config.loop; soundSource.mute = this._isMute; soundSource.play(); return; } soundSource = new SoundSource(audioClip); soundSource.loop = config.loop; soundSource.volume = config.volume; soundSource.mute = this._isMute; this._audioSourcesSfx.set(audioClip, soundSource); soundSource.play(); } public static stopBgm() { this._audioSourceBgm.stop(); } public static stopSfx(audioClip: AudioClip) { this._audioSourcesSfx.get(audioClip).stop(); } public static stopAllSfxLoop() { this._audioSourcesSfx.forEach((sfx) => sfx.stop()); } public static findAudioSourcesSfx(audioClip: AudioClip): SoundSource { return this._audioSourcesSfx.get(audioClip); } }