All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 38s
175 lines
5.3 KiB
TypeScript
175 lines
5.3 KiB
TypeScript
import { _decorator, AudioClip, AudioSource, Node, resources, director } from 'cc';
|
||
|
||
export class AudioManager {
|
||
private static _instance: AudioManager = null;
|
||
private _audioNode: Node = null;
|
||
private _bgmAudioSource: AudioSource = null; // 专门用于背景音乐
|
||
private _sfxAudioSources: AudioSource[] = []; // 用于音效的多个AudioSource
|
||
private _bgmVolume: number = 0.5;
|
||
private _bgmClip: AudioClip = null;
|
||
private _audioClips: Map<string, AudioClip> = new Map();
|
||
private _isMuted: boolean = false;
|
||
private _isPaused: boolean = false;
|
||
|
||
static get instance(): AudioManager {
|
||
if (!this._instance) {
|
||
this._instance = new AudioManager();
|
||
}
|
||
return this._instance;
|
||
}
|
||
|
||
init() {
|
||
// 创建根节点
|
||
this._audioNode = new Node('AudioManager');
|
||
director.getScene().addChild(this._audioNode);
|
||
|
||
// 创建BGM节点
|
||
let bgmNode = new Node('BGM');
|
||
this._audioNode.addChild(bgmNode);
|
||
this._bgmAudioSource = bgmNode.addComponent(AudioSource);
|
||
this._bgmAudioSource.playOnAwake = false;
|
||
|
||
// 创建多个音效节点
|
||
for (let i = 0; i < 3; i++) {
|
||
let sfxNode = new Node(`SFX_${i}`);
|
||
this._audioNode.addChild(sfxNode);
|
||
let sfxAudioSource = sfxNode.addComponent(AudioSource);
|
||
sfxAudioSource.playOnAwake = false;
|
||
this._sfxAudioSources.push(sfxAudioSource);
|
||
}
|
||
|
||
// 加载音频资源
|
||
this.loadAudioClips();
|
||
}
|
||
|
||
private loadAudioClips() {
|
||
resources.loadDir("audio", AudioClip, (err, clips) => {
|
||
if (err) {
|
||
console.error("加载音频资源失败:", err);
|
||
return;
|
||
}
|
||
clips.forEach(clip => {
|
||
this._audioClips.set(clip.name, clip);
|
||
});
|
||
});
|
||
}
|
||
|
||
playBGM(name: string, loop: boolean = true) {
|
||
if (this._isMuted || !this._bgmAudioSource) return;
|
||
this._bgmAudioSource.stop();
|
||
let clip = this._audioClips.get(name);
|
||
if (!clip) {
|
||
console.warn(`BGM ${name} 不存在`);
|
||
return;
|
||
}
|
||
this._bgmClip = clip;
|
||
this._bgmAudioSource.clip = clip;
|
||
this._bgmAudioSource.loop = loop;
|
||
this._bgmAudioSource.volume = this._bgmVolume;
|
||
this._bgmAudioSource.play();
|
||
this._isPaused = false;
|
||
}
|
||
|
||
playSFX(name: string, volume: number = 1.0, loop: boolean = false) {
|
||
if (this._isMuted) return;
|
||
|
||
let clip = this._audioClips.get(name);
|
||
if (!clip) {
|
||
console.warn(`音效 ${name} 不存在`);
|
||
return;
|
||
}
|
||
|
||
// 找到一个空闲的AudioSource
|
||
let availableSource = this._sfxAudioSources.find(source => !source.playing);
|
||
if (availableSource) {
|
||
// 确保音量正确
|
||
availableSource.volume = volume;
|
||
availableSource.loop = loop;
|
||
availableSource.clip = clip;
|
||
// 播放新音效
|
||
availableSource.play()
|
||
} else {
|
||
// 如果没有空闲的AudioSource,创建一个新的
|
||
let sfxNode = new Node(`SFX_${this._sfxAudioSources.length}`);
|
||
this._audioNode.addChild(sfxNode);
|
||
let newSource = sfxNode.addComponent(AudioSource);
|
||
newSource.playOnAwake = false;
|
||
newSource.volume = volume;
|
||
newSource.loop = loop;
|
||
newSource.clip = clip;
|
||
this._sfxAudioSources.push(newSource);
|
||
newSource.play()
|
||
}
|
||
}
|
||
|
||
async stopAllSFX(): Promise<void> {
|
||
let promises = this._sfxAudioSources.map(source => {
|
||
return new Promise<void>((resolve) => {
|
||
source.stop();
|
||
// 使用 setTimeout 确保音效停止
|
||
setTimeout(resolve, 100);
|
||
});
|
||
});
|
||
|
||
await Promise.all(promises);
|
||
}
|
||
|
||
stopBGM() {
|
||
if (this._bgmAudioSource) {
|
||
this._bgmAudioSource.stop();
|
||
this._isPaused = false;
|
||
}
|
||
}
|
||
|
||
pauseBGM() {
|
||
if (this._bgmAudioSource && !this._isPaused) {
|
||
this._bgmAudioSource.pause();
|
||
this._isPaused = true;
|
||
}
|
||
}
|
||
|
||
resumeBGM() {
|
||
if (!this._isMuted && this._bgmAudioSource && this._isPaused) {
|
||
this._bgmAudioSource.play();
|
||
this._isPaused = false;
|
||
}
|
||
}
|
||
|
||
setBGMVolume(volume: number) {
|
||
this._bgmVolume = Math.max(0, Math.min(1, volume));
|
||
if (this._bgmAudioSource) {
|
||
this._bgmAudioSource.volume = this._bgmVolume;
|
||
}
|
||
}
|
||
|
||
setSFXVolume(volume: number) {
|
||
// this._sfxVolume = Math.max(0, Math.min(1, volume));
|
||
// this._sfxAudioSources.forEach(source => {
|
||
// source.volume = this._sfxVolume;
|
||
// });
|
||
}
|
||
|
||
setMute(muted: boolean) {
|
||
this._isMuted = muted;
|
||
if (muted) {
|
||
this.stopBGM();
|
||
} else if (this._bgmClip) {
|
||
this.playBGM(this._bgmClip.name);
|
||
}
|
||
}
|
||
|
||
getMuted() {
|
||
return this._isMuted;
|
||
}
|
||
|
||
// 清理资源
|
||
destroy() {
|
||
if (this._audioNode) {
|
||
this._audioNode.destroy();
|
||
}
|
||
this._audioNode = null;
|
||
this._bgmAudioSource = null;
|
||
this._sfxAudioSources = [];
|
||
this._audioClips.clear();
|
||
}
|
||
} |