123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- import { _decorator,AudioClip, AudioSource} from 'cc';
- import { Singleton } from './Singleton';
- import { bundleMgr } from './BundleManager';
- import { Constants } from '../../data/Constants';
- import { settingData } from '../../data/SettingData';
- import { Logger } from '../../extend/Logger';
- import { Utils } from '../../utils/Utils';
- const { ccclass, property } = _decorator;
- /**音乐播放数据结构*/
- export interface IAudioData {
- clip: AudioClip;//音乐片段
- audioSource: AudioSource;//音乐具柄
- path: string //音乐名称路径
- playStatus: boolean //播放状态
- totalTime: number;//音乐总长度时间
- time_id: number;//定时器句柄
- t: number;//统计记时
- }
- @ccclass('AudioManager')
- class AudioManager extends Singleton{
- //缓存的音乐
- private cachedAudioArr: Array<IAudioData> = [];
- /**
- * 预加载音乐
- * 这儿前面 bundleManager资源包已经 loadLaunchBundles加载过了
- * 可以直接 再次
- */
- public async initialize(): Promise<void> {
- const audioAssets = Object.entries(Constants.audios)
- .map(([key, path]) => ({
- path: path,
- type: AudioClip
- }))
- .filter(asset => !!asset.path);
- await bundleMgr.loadMultipleAssets(Constants.bundleName.audios,
- audioAssets,
- (progress) => {/*进度条0~1*/},
- (err:Error, clip: AudioClip, path) => {
- if(err) {
- Logger.error("加载资源失败:", err);
- }else{
- this.cachedAudioArr.push({
- clip: clip,
- audioSource: null,
- path: path,
- playStatus: false,
- totalTime: clip.getDuration(),
- time_id: -1,
- t: 0
- });
- }
- }
- );
- }
- /**
- * 播放音效 不会两个相同的音乐重复播放 可以停止
- * @param path 播放音乐的路径
- * @param loop 是否循环播放
- * @param s 如果为-1则最大音量立即播放 如果为其他则慢慢音量递增起来播放
- * @returns
- */
- private bgVolumeMax: number = 0.8;
- public async play(path: string,loop: boolean = false,s: number = -1): Promise<void> {
- if(Utils.isNull(path)
- ||!settingData.data.bgMusic)return;
- const fun = (audio:IAudioData)=>{
- if(audio.audioSource == null){
- audio.audioSource = this.audioSourceLoop(loop);
- }
- if(audio.playStatus)return;
- audio.audioSource.clip = audio.clip;
- if(audio.time_id){
- clearInterval(audio.time_id);
- if(audio.audioSource.playing){
- audio.audioSource.pause();
- }
- }
- audio.audioSource.play();
- if(s == -1){
- audio.audioSource.volume = this.bgVolumeMax;
- }else{
- audio.t = 0;
- audio.audioSource.volume = 0;
- let interval: number = ((1 / s) / 10);
- audio.time_id = setInterval(()=>{
- audio.t += interval;
- let volume: number = audio.t / s;
- if(volume >= this.bgVolumeMax){
- clearInterval(audio.time_id);
- }else{
- audio.audioSource.volume = volume;
- }
- },interval * 1000);
- }
- audio.playStatus = true;
- }
- let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
- if(a){
- fun(a);
- }else{
- await bundleMgr.loadAsset(Constants.bundleName.audios,path,
- AudioClip,(err: Error, clip: AudioClip) => {
- if(err) {
- Logger.error("加载资源失败:", err);
- }else{
- let data:IAudioData = {
- path: path,
- clip: clip,
- audioSource: null,
- playStatus: false,
- totalTime: clip.getDuration(),
- time_id: -1,
- t: 0
- };
- this.cachedAudioArr.push(data);
- fun(data);
- }
- });
- }
- }
- /**
- * 单次播放一次的音效 可以停止
- * @param path 音乐路径
- * @param overlap 是否可以重复两个同一个音效连续播放
- * @returns
- */
- public async playOneShot(path: string,overlap: boolean = true): Promise<void> {
- if(Utils.isNull(path)
- ||!settingData.data.soundFx)return;
- const fun = (audio:IAudioData)=>{
- if(overlap || !audio.playStatus){
- if(audio.audioSource == null){
- audio.audioSource = this.audioSourceLoop(false);
- }
- audio.audioSource.clip = audio.clip;
- audio.audioSource.play();
- audio.audioSource.volume = 1;
- audio.playStatus = true;
- setTimeout(()=>{
- audio.playStatus = false;
- },audio.totalTime * 1000)
- }
- }
- let a: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
- if(a){
- fun(a);
- }else{
- await bundleMgr.loadAsset(Constants.bundleName.audios,path,
- AudioClip,(err: Error, clip: AudioClip) => {
- if(err) {
- Logger.error("加载资源失败:", err);
- }else{
- let data:IAudioData = {
- path: path,
- clip: clip,
- audioSource: null,
- playStatus: false,
- totalTime: clip.getDuration(),
- time_id: -1,
- t: 0
- };
- this.cachedAudioArr.push(data);
- fun(data);
- }
- });
- }
- }
- /**
- * 停止播放音效
- * @param path 音效路径名称
- * @param s 为-1立即停止播放 非-1则是慢慢的声音越来越小的停止播放
- * @returns
- */
- public stop(path: string,s: number = -1): void {
- if(Utils.isNull(path))return;
- let audio: IAudioData = this.cachedAudioArr.find(e =>e.path == path);
- if(audio){
- if(!audio.audioSource)return;
- if(!audio.audioSource.playing)return;
- if(audio.time_id){
- clearInterval(audio.time_id);
- }
- let audioSource = audio.audioSource;
- if(s == -1){
- audioSource?.pause();
- }else{
- audio.t = 0;
- let interval: number = ((1 / s) / 10);
- audio.time_id = setInterval(()=>{
- if(audioSource){
- audio.t += interval;
- let volume: number = this.bgVolumeMax - audio.t / s;
- if(volume <= 0){
- clearInterval(audio.time_id);
- audioSource?.pause();
- }else{
- audioSource.volume = volume <= 0 ? 0 :volume;
- }
- }
- },interval * 1000);
- }
- audio.playStatus = false;
- }
- }
- /**
- * 加载音效
- * @param loop 是否循环
- */
- public audioSourceLoop(loop: boolean): AudioSource{
- let audioSource: AudioSource = null;
- if(loop){//播放单次的时候具柄
- audioSource = this.getAudioSource(null,true,this.bgVolumeMax)
- }else{//循环播放的时候具柄
- audioSource = this.getAudioSource(null,false,1);
- }
- return audioSource;
- }
- /**
- * 得到一个播放音乐的控制类
- * @param clip 音效片段
- * @param loop 是否循环
- * @param volume 音量
- * @returns 播放类
- */
- public getAudioSource(clip: AudioClip = null, loop: boolean = false, volume: number = 1): AudioSource{
- let audioSource: AudioSource = new AudioSource();
- if(clip){
- audioSource.clip = clip;
- }
- audioSource.loop = loop;
- audioSource.volume = volume;
- return audioSource;
- }
- }
- //全局单例
- export const audioMgr = AudioManager.ins();
|