| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- import { _decorator, Component, AudioSource, AudioClip, Node, sys } from 'cc';
- const { ccclass, property, menu } = _decorator;
- @ccclass
- @menu('Audio/SoundManager')
- export class SoundManager extends Component {
- // ==================== 播放器通道 ====================
- @property(AudioSource)
- bgmSource: AudioSource = null!; // 背景音乐
- @property(AudioSource)
- normalSource: AudioSource = null!; // 常规音效(playOneShot)
- @property(AudioSource)
- stopableSource: AudioSource = null!; // 可停止音效(如技能)优先使用此音效,多个音效要一起播时使用下面两个备用
- @property(AudioSource)
- stopableSource2: AudioSource = null!; // 可停止音效(如技能)
- @property(AudioSource)
- stopableSource3: AudioSource = null!; // 可停止音效(如技能)
- @property(AudioSource)
- loopSource: AudioSource = null!; // 循环音效(游戏中)
- @property(AudioSource)
- resultLoopSource: AudioSource = null!; // 循环音效(结果界面)
- // ==================== 音效资源(可选预览) ====================
- @property(AudioClip)
- bgmClip: AudioClip = null!;
- @property(AudioClip)
- clickClip: AudioClip = null!;
- // ==================== 开关状态 ====================
- private _musicEnabled: boolean = true;
- private _soundEnabled: boolean = true;
- private static readonly KEY_MUSIC = 'SoundManager_Music';
- private static readonly KEY_SOUND = 'SoundManager_Sound';
- // ==================== 生命周期 ====================
- start() {
- // this.initAudioSources();
- this.loadSettings();
- this.applyVolume();
- // 开关开启时自动播放 BGM
- // if (this._musicEnabled && this.bgmClip) {
- // this.playBGM();
- // }
- }
- private initAudioSources() {
- // 自动创建缺失的 AudioSource
- const createSource = (name: string): AudioSource => {
- const node = new Node(name);
- node.parent = this.node;
- const source = node.addComponent(AudioSource);
- source.playOnAwake = false;
- return source;
- };
- if (!this.bgmSource) this.bgmSource = createSource('BGM_Source');
- if (!this.normalSource) this.normalSource = createSource('Normal_Source');
- if (!this.stopableSource) this.stopableSource = createSource('Stopable_Source');
- if (!this.loopSource) this.loopSource = createSource('Loop_Source');
- }
- // ==================== 本地设置 ====================
- private loadSettings() {
- const m = sys.localStorage.getItem(SoundManager.KEY_MUSIC);
- const s = sys.localStorage.getItem(SoundManager.KEY_SOUND);
- this._musicEnabled = m === null ? true : m === 'true';
- this._soundEnabled = s === null ? true : s === 'true';
- }
- private saveSettings() {
- sys.localStorage.setItem(SoundManager.KEY_MUSIC, this._musicEnabled.toString());
- sys.localStorage.setItem(SoundManager.KEY_SOUND, this._soundEnabled.toString());
- }
- private applyVolume() {
- this.bgmSource.volume = this._musicEnabled ? 1 : 0;
- // 其他 source 播放时动态控制
- }
- // ==================== 背景音乐 ====================
- public playBGM(clip?: AudioClip) {
- if (!this._musicEnabled) return;
- const target = clip || this.bgmClip;
- if (!target) return;
- this.bgmSource.stop();
- this.bgmSource.clip = target;
- this.bgmSource.loop = true;
- this.bgmSource.play();
- }
- public stopBGM() {
- this.bgmSource.stop();
- }
- public pauseBGM() {
- this.bgmSource.pause();
- }
- public resumeBGM() {
- if (this._musicEnabled) this.bgmSource.play();
- }
- // ==================== 按钮点击常规音效 ====================
- public playClick(clip?: AudioClip) {
- if (!this._soundEnabled) return;
- const target = clip || this.clickClip;
- if (target) {
- this.normalSource.playOneShot(target, 1.0);
- }
- }
- // ==================== 可停止音效 ====================
- public playEffect1(clip?: AudioClip, volume: number = 1) {
- if (!this._soundEnabled) return;
- const target = clip;
- if (!target) return;
- this.stopableSource.clip = target;
- this.stopableSource.loop = false;
- this.stopableSource.volume = volume;
- this.stopableSource.play();
- }
- public stopEffect1() {
- this.stopableSource.stop();
- }
- // ==================== 播放可停止音效 ====================
- public playEffect2(clip?: AudioClip, volume: number = 1) {
- if (!this._soundEnabled) return;
- const target = clip;
- if (!target) return;
- this.stopableSource2.clip = target;
- this.stopableSource2.loop = false;
- this.stopableSource.volume = volume;
- this.stopableSource2.play();
- }
- public stopEffect2() {
- this.stopableSource2.stop();
- }
- // ==================== 播放可停止音效 ====================
- public playEffect3(clip?: AudioClip, volume: number = 1) {
- if (!this._soundEnabled) return;
- const target = clip;
- if (!target) return;
- this.stopableSource3.clip = target;
- this.stopableSource3.loop = false;
- this.stopableSource.volume = volume;
- this.stopableSource3.play();
- }
- public stopEffect3() {
- this.stopableSource3.stop();
- }
- // ==================== 游戏中循环音效 ====================
- public playLoopEffect(clip?: AudioClip, volume?: number) {
- if (!this._soundEnabled) return;
- const target = clip;
- if (!target) return;
- this.loopSource.clip = target;
- this.loopSource.loop = true;
- this.loopSource.volume = volume;
- this.loopSource.play();
- }
- public stopLoopEffect() {
- this.loopSource.stop();
- }
- public setLoopEffectVolume(volume?: number) {
- if (!this._soundEnabled) return;
- this.loopSource.volume = volume;
- }
- // ==================== 结果循环音效 ====================
- public playResultLoopEffect(clip?: AudioClip, volume?: number) {
- if (!this._soundEnabled) return;
- const target = clip;
- if (!target) return;
- this.resultLoopSource.clip = target;
- this.resultLoopSource.loop = true;
- this.resultLoopSource.volume = volume;
- this.resultLoopSource.play();
- }
- public stopResultLoopEffect() {
- this.resultLoopSource.stop();
- }
- public setResultLoopEffectVolume(volume?: number) {
- this.resultLoopSource.volume = volume;
- }
- // ==================== 全局开关 ====================
- public setMusicEnabled(enabled: boolean) {
- this._musicEnabled = enabled;
- this.bgmSource.volume = enabled ? 1 : 0;
- if (!enabled) this.pauseBGM();
- else if (this.bgmSource.clip) this.resumeBGM();
- this.saveSettings();
- }
- public setSoundEnabled(enabled: boolean) {
- this._soundEnabled = enabled;
- if (!enabled) {
- this.stopEffect1();
- this.stopEffect2();
- this.stopEffect3();
- this.stopLoopEffect();
- }
- this.saveSettings();
- }
- public toggleMusic() { this.setMusicEnabled(!this._musicEnabled); }
- public toggleSound() { this.setSoundEnabled(!this._soundEnabled); }
- public get musicEnabled() { return this._musicEnabled; }
- public get soundEnabled() { return this._soundEnabled; }
- // ==================== 生命周期结束 ====================
- onDestroy() {
- this.stopBGM();
- this.stopEffect1();
- this.stopEffect2();
- this.stopEffect3();
- this.stopLoopEffect();
- }
- }
|