消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
11 KiB

1 week ago
//*********************
// create by 流云
// time: 2022年2月15日
// desc: 音频管理器
//*********************
import { _decorator, Node, AudioSource, AudioClip, game, Game, assetManager, director, Asset, AssetManager, sys } from 'cc';
import { BattlePerformance } from '../../../script/ui/BattleGame/BattlePerformance';
/**
*
*/
export class SoundManager {
private static _ins: SoundManager = null;
public static get Ins() {
if (!this._ins) this._ins = new SoundManager();
return this._ins;
}
private _node: Node = null;
private _music: AudioSource = null;
private _effect: AudioSource = null;
private _game_id = "default_game";
private _user_name = "default_user";
private _click_name = "";
private _bundle = "";
private _path = "";
private _curent_music = "";
private _isPause = false;
MusicVolume = 1;
EffectVolume = 1;
MuteMusic = false;
MuteEffect = false;
private _clip_map: Map<string, AudioRecord> = new Map<string, AudioRecord>();
private _clip_loading: Map<string, Promise<AudioClip | null>> = new Map();
init({
gameid = "default_game",
userName = "default_user",
bundle = "resources",
path = "sound/",
clickEffname = ``,
music_volume = 1,
effect_volume = 1,
mute_music = false,
mute_effect = false
}) {
this._game_id = gameid;
this._user_name = userName;
this._click_name = clickEffname;
this._bundle = bundle;
this._path = path;
this.MusicVolume = music_volume;
this.EffectVolume = effect_volume;
this.MuteMusic = mute_music;
this.MuteEffect = mute_effect;
if (!this._node) {
this._node = new Node("soundNode");
director.addPersistRootNode(this._node);
}
this._music = this._node.addComponent(AudioSource);
this._effect = this._node.addComponent(AudioSource);
game.on(Game.EVENT_HIDE, this.onHide, this);
game.on(Game.EVENT_SHOW, this.onShow, this);
this._node.off(AudioSource.EventType.ENDED, this.onAudioEnded, this);
this._node.on(AudioSource.EventType.ENDED, this.onAudioEnded, this);
this.getStatus();
}
clear() {
this._clip_map.clear();
director.removePersistRootNode(this._node);
this._node = null;
}
onHide() {
this.pause();
}
onShow() {
this.resume();
}
/**
*
*/
pause() {
this._isPause = true;
if (this._music.playing) this._music.pause();
if (this._effect.playing) this._effect.pause();
}
/**
*
*/
resume() {
this._isPause = false;
this.updateStatus();
}
updateStatus() {
this._music.volume = this._isPause || this.MuteMusic ? 0 : this.MusicVolume;
this._effect.volume = this._isPause || this.MuteEffect ? 0 : this.EffectVolume;
if (this._music) this._music.play();
}
/**
*
*/
private getStatus() {
let temp = sys.localStorage.getItem(`${this._game_id + this._user_name}_music_volume`);
if (temp) this.MusicVolume = Number(temp);
temp = sys.localStorage.getItem(`${this._game_id + this._user_name}_music_mute`);
if (temp) this.MuteMusic = Boolean(temp);
temp = sys.localStorage.getItem(`${this._game_id + this._user_name}_effect_volume`);
if (temp) this.EffectVolume = Number(temp);
temp = sys.localStorage.getItem(`${this._game_id + this._user_name}_effect_mute`);
if (temp) this.MuteEffect = Boolean(temp);
}
/**
*
*/
saveStatus() {
sys.localStorage.setItem(`${this._game_id + this._user_name}_music_volume`, this.MusicVolume + ``);
sys.localStorage.setItem(`${this._game_id + this._user_name}_music_mute`, this.MuteMusic + ``);
sys.localStorage.setItem(`${this._game_id + this._user_name}_effect_volume`, this.EffectVolume + ``);
sys.localStorage.setItem(`${this._game_id + this._user_name}_effect_mute`, this.MuteEffect + ``);
}
/**
*
*/
release() {
this._clip_map.forEach((v, k) => {
if (v.isRelease && v.clip) {
v.clip.decRef();
v.clip = null;
}
})
}
/**
*
* @param param
* @returns
*/
async playMusic({ name, path = ``, bundle = ``, loop = true, isRelease = false, onEnd = null, clip = null }) {
//console.log("开始播放音乐:" + name, this._curent_music, this._isPause);
if (this._isPause || this.MuteMusic) return;
if (this._music && this._music.playing && name == this._curent_music) return;
this.stopMusic();
this._curent_music = name;
if (clip != null)
this._music.clip = clip;
else {
const rec = await this.getClip(bundle, path, name, isRelease);
if (!rec?.clip) return;
this._music.clip = rec.clip;
}
this._music.loop = loop;
this._music.volume = this.MusicVolume;
this._music.play();
}
stopMusic() {
this._curent_music = "";
if (this._music) {
this._music.stop();
this._music.clip = null;
}
}
private _PlayingEffects: AudioRecord[] = [];
/**
*
* @param param
*/
async playEffect({ name, path = ``, bundle = ``, isRelease = true, onEnd = null, clip = null, finishRelease = false, stopBefore = false }) {
if (this._isPause || this.MuteEffect) {
let t = 2;
if (clip != null) t = clip.getDuration();
if (onEnd) setTimeout(() => { onEnd(); }, t * 1000);
return;
}
if (!BattlePerformance.shouldPlayWeaponSfx(path, name)) {
if (onEnd) setTimeout(() => { onEnd(); }, 0);
return;
}
let a: AudioRecord = null;
if (clip == null) {
a = await this.getClip(bundle, path, name, isRelease);
} else {
a = new AudioRecord();
a.clip = clip;
a.bundle = bundle;
a.path = path;
a.name = name;
a.key = `${bundle}_${path}_${name}`;
a.isRelease = isRelease;
}
if (stopBefore) {
let arr = this._PlayingEffects.filter(v => v.key == a.key);
for (let i = 0; i < arr.length; i++) {
arr[i].isPlaying = false;
let index = this._PlayingEffects.indexOf(arr[i])
if (index > -1 && arr[i] != a) {
this._PlayingEffects.splice(index, 1);
if (arr[i].clip) {
arr[i].clip.decRef();
arr[i].clip.destroy();
arr[i].clip = null;
}
}
}
}
if (!a.clip) {
if (onEnd) {
setTimeout(() => { onEnd(); }, 2 * 1000);
}
return a;
}
this._effect.playOneShot(a.clip, this.EffectVolume);
let len = a.clip.getDuration();
a.isPlaying = true;
this._PlayingEffects.push(a);
setTimeout(() => {
a.isPlaying = false;
let index = this._PlayingEffects.indexOf(a);
if (index > -1) {
this._PlayingEffects.splice(index, 1);
}
if (finishRelease) {
if (a && a.clip) {
a.clip.decRef();
a.clip = null;
}
if (this._clip_map.has(a.key))
this._clip_map.delete(a.key);
}
if (onEnd) onEnd();
}, len * 1000);
return a;
}
/**
*
*/
playClick() {
if (this._click_name != "")
this.playEffect({ name: this._click_name });
}
/**
*
* @param e
*/
onAudioEnded(e) {
if (e["onSoundEnd"]) {
e.onSoundEnd();
e.onSoundEnd = null;
}
}
private async getClip(bundle, path, audioName, isRelease) {
let b = bundle == `` ? this._bundle : bundle;
let p = path == `` ? this._path : path;
let k = `${b}_${p}_${audioName}`;
let a: AudioRecord = this._clip_map.get(k);
if (!a) {
a = new AudioRecord();
this._clip_map.set(k, a);
}
a.bundle = b;
a.path = p;
a.name = audioName;
a.key = k;
a.isRelease = isRelease;
if (!a.clip) {
let loading = this._clip_loading.get(k);
if (!loading) {
loading = this.loadClip(b, p + audioName);
this._clip_loading.set(k, loading);
loading.finally(() => this._clip_loading.delete(k));
}
a.clip = await loading;
if (!a.clip) {
console.warn(`[Sound] 音效加载失败: ${k}`);
return a;
}
a.clip.addRef();
}
return a;
}
private async loadClip(bundleName, assetPath): Promise<AudioClip | null> {
let bundle = assetManager.getBundle(bundleName);
if (!bundle) bundle = await this.loadBundle(bundleName);
if (!bundle) return null;
return (await this.loadRes(bundle, assetPath)) as AudioClip | null;
}
private async loadBundle(bundleName) {
return new Promise<AssetManager.Bundle>((resolve, reject) => {
assetManager.loadBundle(bundleName, (err, bundle) => {
if (err) {
console.log(`加载Bundle:${bundleName}错误`, err);
resolve(null);
} else {
resolve(bundle);
}
})
})
}
private async loadRes(bundle: AssetManager.Bundle, assetPath) {
return new Promise<Asset>((resolve, reject) => {
bundle.load(assetPath, AudioClip, (err, asset) => {
if (err) {
console.log(`加载Bundle:${bundle.name},path:${assetPath}资源错误`, err);
resolve(null);
} else {
//asset.addRef();
resolve(asset);
}
})
})
}
}
class AudioRecord {
bundle: string = ``;
path: string = ``;
name: string = ``;
key: string = ``;
clip: AudioClip = null;
isRelease: boolean = true;
isPlaying: boolean = false;
}