const { ccclass, property } = cc._decorator; @ccclass export default class AudioManager extends cc.Component { static _instance: any; // 远程音频 CDN 基础地址 // public CDN_AUDIO_BASE: string = "https://pay.nika4games.com/remote/music/"; public CDN_AUDIO_BASE: string = "https://cdn.pay.nika4games.com/remote/music/"; // 本地缓存的 AudioClip(按需懒加载) private audioCache: { [key: string]: cc.AudioClip } = {}; // 合并同一音频的并发加载请求,避免预加载和场景播放重复下载。 private audioLoadingCallbacks: { [key: string]: Array<(clip: cc.AudioClip) => void> } = {}; // 远程 URL 映射表 private audioUrlMap: { [key: string]: string } = {}; // 本地持久化缓存目录(微信小游戏) private localCacheDir: string = ''; /** * 获取本地缓存目录 * 微信小游戏使用 USER_DATA_PATH 下的 audio_cache 子目录 */ getLocalCacheDir(): string { if (this.localCacheDir) return this.localCacheDir; // @ts-ignore if (typeof wx !== 'undefined' && wx.env && wx.env.USER_DATA_PATH) { // @ts-ignore this.localCacheDir = wx.env.USER_DATA_PATH + '/audio_cache/'; } return this.localCacheDir; } /** * 获取本地缓存文件路径 */ getLocalCachePath(name: string): string { return this.getLocalCacheDir() + name + '.mp3'; } // 背景音乐 @property(cc.AudioClip) main_bgm: cc.AudioClip = null; @property(cc.AudioClip) xiaochu: cc.AudioClip = null; @property(cc.AudioClip) hit: cc.AudioClip = null; @property(cc.AudioClip) down: cc.AudioClip = null; @property(cc.AudioClip) win: cc.AudioClip = null; @property(cc.AudioClip) anniu_Big: cc.AudioClip = null; @property(cc.AudioClip) anniu_little: cc.AudioClip = null; @property(cc.AudioClip) tanchuang: cc.AudioClip = null; @property(cc.AudioClip) zhuan1: cc.AudioClip = null; @property(cc.AudioClip) zhuan2: cc.AudioClip = null; @property(cc.AudioClip) adhesive: cc.AudioClip = null; @property(cc.AudioClip) freezeBlock: cc.AudioClip = null; @property(cc.AudioClip) freezeDoor: cc.AudioClip = null; @property(cc.AudioClip) hammer: cc.AudioClip = null; @property(cc.AudioClip) lockBlock1: cc.AudioClip = null; @property(cc.AudioClip) lockBlock2: cc.AudioClip = null; @property(cc.AudioClip) lockDoor: cc.AudioClip = null; @property(cc.AudioClip) magic1: cc.AudioClip = null; @property(cc.AudioClip) magic2: cc.AudioClip = null; @property(cc.AudioClip) simpleColor: cc.AudioClip = null; @property(cc.AudioClip) stacking: cc.AudioClip = null; @property(cc.AudioClip) starBlock: cc.AudioClip = null; @property(cc.AudioClip) timePause1: cc.AudioClip = null; @property(cc.AudioClip) timePause2: cc.AudioClip = null; @property(cc.AudioClip) hit1: cc.AudioClip = null; @property(cc.AudioClip) hit2: cc.AudioClip = null; @property(cc.AudioClip) hit3: cc.AudioClip = null; @property(cc.AudioClip) hit4: cc.AudioClip = null; @property(cc.AudioClip) hit5: cc.AudioClip = null; mAudioMap: { [name: string]: number }; bgMusicVolume: number; effectMusicVolume: number; mMusicSwitch: number; mEffectSwitch: number; brickSound: any; reward: boolean; finish: boolean; rewardCount: number; mMusicKey: any; private musicRequestId: number = 0; private shouldRestartMusicOnShow: boolean = false; private restartMusicTimer: number = null; onLoad() { if (AudioManager._instance == null) { AudioManager._instance = this; cc.fx.AudioManager = AudioManager; cc.game.addPersistRootNode(this.node); } else { return; } this.reward = false; this.finish = false; this.rewardCount = 0; this.ctor(); this.registerAndroidWechatLifecycle(); this.preload(); } onDestroy() { this.unregisterAndroidWechatLifecycle(); } ctor() { this.mAudioMap = {}; /** * 默认音量大小 * @type {number} */ this.bgMusicVolume = 0.1; this.effectMusicVolume = 1; this.mMusicSwitch = 1; this.mEffectSwitch = 1; // 初始化远程音频 URL 映射 this.initAudioUrlMap(); } /** * 初始化远程音频 URL 映射表 * 将所有音频文件路径映射到 CDN 完整 URL */ initAudioUrlMap() { const base = this.CDN_AUDIO_BASE; // 音效列表 const names = [ 'main_bgm', 'homeScene', 'gameScene', 'xiaochu', 'hit', 'down', 'win', 'anniu_Big', 'anniu_little', 'tanchuang', 'zhuan1', 'zhuan2', 'adhesive', 'freezeBlock', 'freezeDoor', 'hammer', 'lockBlock1', 'lockBlock2', 'lockDoor', 'magic1', 'magic2', 'simpleColor', 'stacking', 'starBlock', 'timePause1', 'timePause2', 'hit1', 'hit2', 'hit3', 'hit4', 'hit5' ]; names.forEach((name) => { this.audioUrlMap[name] = base + name + '.mp3'; }); } private isLayerOneVariantB(): boolean { const gameInfo = cc.fx.GameConfig && cc.fx.GameConfig.GM_INFO; const abTests = gameInfo && gameInfo.abTests; return !!abTests && Number(abTests.layer_one) === 2; } private isAndroidWechatGame(): boolean { return cc.sys.platform === cc.sys.WECHAT_GAME && cc.sys.os === cc.sys.OS_ANDROID; } private logLifecycleAudioError(stage: string, error: any) { try { console.error('AudioManager 前后台音乐处理失败:', stage, error); } catch (e) { // 日志本身也不能影响前后台事件链。 } } private registerAndroidWechatLifecycle() { try { if (!this.isAndroidWechatGame()) { return; } } catch (error) { this.logLifecycleAudioError('注册监听前的平台判断', error); return; } try { cc.game.on(cc.game.EVENT_HIDE, this.onHide, this); } catch (error) { this.logLifecycleAudioError('注册 EVENT_HIDE 监听', error); } try { cc.game.on(cc.game.EVENT_SHOW, this.onShow, this); } catch (error) { this.logLifecycleAudioError('注册 EVENT_SHOW 监听', error); } } private unregisterAndroidWechatLifecycle() { try { cc.game.off(cc.game.EVENT_HIDE, this.onHide, this); } catch (error) { this.logLifecycleAudioError('移除 EVENT_HIDE 监听', error); } try { cc.game.off(cc.game.EVENT_SHOW, this.onShow, this); } catch (error) { this.logLifecycleAudioError('移除 EVENT_SHOW 监听', error); } if (this.restartMusicTimer != null) { try { clearTimeout(this.restartMusicTimer); } catch (error) { this.logLifecycleAudioError('清理恢复定时器', error); } this.restartMusicTimer = null; } } private isBackgroundMusicName(name: string): boolean { return name === 'main_bgm' || name === 'homeScene' || name === 'gameScene'; } private isBackgroundMusicAllowedForGroup(name: string): boolean { if (!this.isBackgroundMusicName(name)) { return true; } if (this.isLayerOneVariantB()) { return name === 'homeScene' || name === 'gameScene'; } // 未分组、异常值和 layer_one=1 都按默认 A 方案处理。 return name === 'main_bgm'; } private getCurrentSceneName(sceneName?: string): string { if (sceneName) { return sceneName; } const scene = cc.director.getScene && cc.director.getScene(); if (scene && scene.name) { return scene.name; } const gameInfo = cc.fx.GameConfig && cc.fx.GameConfig.GM_INFO; return gameInfo && gameInfo.sceneValue ? gameInfo.sceneValue : ''; } public getSceneBackgroundMusicName(sceneName?: string): string { if (!this.isLayerOneVariantB()) { return 'main_bgm'; } const currentSceneName = this.getCurrentSceneName(sceneName); if (currentSceneName === 'HomeScene') { return 'homeScene'; } if (currentSceneName === 'GameScene') { return 'gameScene'; } return ''; } /** * 根据名称获取远程音频 URL */ getRemoteUrl(name: string): string { if (name == null || name == "null") { return ""; } return this.audioUrlMap[name] || (this.CDN_AUDIO_BASE + name + '.mp3'); } /** * 加载远程音频 * 优先从缓存获取,没有则从 CDN 下载 */ loadRemoteAudio(name: string, callback?: (clip: cc.AudioClip) => void) { if (!this.isBackgroundMusicAllowedForGroup(name)) { console.warn('当前 layer_one 分组禁止加载背景音乐:', name); callback && callback(null); return; } // 1. 已有缓存直接返回 if (this.audioCache[name]) { callback && callback(this.audioCache[name]); return; } // 2. 本地有 @property 注入的 AudioClip,优先使用 if (this[name] instanceof cc.AudioClip) { this.audioCache[name] = this[name]; callback && callback(this[name]); return; } // 已有相同音频正在加载时只追加回调,不重复请求 CDN。 if (this.audioLoadingCallbacks[name]) { callback && this.audioLoadingCallbacks[name].push(callback); return; } this.audioLoadingCallbacks[name] = []; callback && this.audioLoadingCallbacks[name].push(callback); const finishLoading = (clip: cc.AudioClip) => { const callbacks = this.audioLoadingCallbacks[name] || []; delete this.audioLoadingCallbacks[name]; for (let i = 0; i < callbacks.length; i++) { callbacks[i](clip); } }; // 3. 从远程 CDN 加载 const url = this.getRemoteUrl(name); // console.log('远程加载音频:', name, url); if (url == null || url == "") { finishLoading(null); return; } // 微信小游戏:先查本地缓存,没有再下载 if (cc.sys.platform === cc.sys.WECHAT_GAME) { // @ts-ignore if (typeof wx !== 'undefined' && wx.downloadFile) { this.loadRemoteAudioWithCache(name, url, finishLoading); return; } } // 4. 其他平台直接 loadRemote cc.assetManager.loadRemote(url, (err, audioClip: cc.AudioClip) => { if (err) { console.error('远程音频加载失败:', name, err); finishLoading(null); return; } this.audioCache[name] = audioClip; finishLoading(audioClip); }); } /** * 微信小游戏:优先从本地缓存加载音频,没有则下载并保存到本地 * 缓存路径: wx.env.USER_DATA_PATH/audio_cache/.mp3 * 微信本地缓存总上限 50MB,超出 saveFile 会失败但不影响本次播放 */ loadRemoteAudioWithCache(name: string, url: string, callback?: (clip: cc.AudioClip) => void) { const localPath = this.getLocalCachePath(name); if (!localPath) { // 拿不到本地路径,回退到直接下载 this.downloadAndCacheAudio(name, url, '', callback); return; } // @ts-ignore const fs = wx.getFileSystemManager(); // 确保缓存目录存在(递归创建) try { fs.mkdirSync(this.getLocalCacheDir(), true); } catch (e) { // 目录已存在或其他错误,忽略 } // 1. 检查本地缓存文件是否存在 fs.access({ path: localPath, success: () => { // 本地缓存命中,直接从本地路径加载 // console.log('____________音频本地缓存命中:', name, localPath); cc.assetManager.loadRemote(localPath, (err, audioClip: cc.AudioClip) => { if (err) { //console.log('____________本地缓存加载失败,重新下载:', name, err); // 加载失败,删除坏文件并重新下载 try { fs.unlinkSync(localPath); } catch (e) { } this.downloadAndCacheAudio(name, url, localPath, callback); return; } this.audioCache[name] = audioClip; //console.log('____________本地缓存加载成功:', name, this.audioCache); callback && callback(audioClip); }); }, fail: () => { // 本地缓存未命中,从 CDN 下载 //console.log('____________本地缓存未命中,下载音频:', name, url); this.downloadAndCacheAudio(name, url, localPath, callback); } }); } /** * 下载音频,保存到本地后再从本地路径加载(避免 loadRemote 与 saveFile 竞争) * 关键:wx.saveFile 是移动 temp 文件,而 cc.assetManager.loadRemote 是异步读, * 如果先 loadRemote(tempPath) 再 saveFile,引擎真正读 temp 时文件已被移走 → 500。 * 正确顺序:saveFile 落盘 → loadRemote(本地路径) * @param localPath 本地保存路径,为空时只下载不缓存 */ downloadAndCacheAudio(name: string, url: string, localPath: string, callback?: (clip: cc.AudioClip) => void) { // @ts-ignore const fs = wx.getFileSystemManager(); // @ts-ignore wx.downloadFile({ url: url, success: (res: any) => { if (res.statusCode !== 200) { //console.error('____________下载音频失败:', name, res.statusCode); callback && callback(null); return; } const tempFilePath = res.tempFilePath; if (!localPath) { // 不需要缓存,直接从 temp 加载 cc.assetManager.loadRemote(tempFilePath, (err, audioClip: cc.AudioClip) => { if (err) { //console.error('____________远程音频加载失败:', name, err); callback && callback(null); return; } this.audioCache[name] = audioClip; callback && callback(audioClip); }); return; } // 先 saveFile 落盘到本地缓存,再从稳定的本地路径 loadRemote fs.saveFile({ tempFilePath: tempFilePath, filePath: localPath, success: (saveRes: any) => { const savedPath = saveRes.savedFilePath || localPath; //console.log('____________音频已缓存到本地:', name, savedPath); cc.assetManager.loadRemote(savedPath, (err, audioClip: cc.AudioClip) => { if (err) { console.error('____________本地缓存加载失败:', name, err); try { fs.unlinkSync(savedPath); } catch (e) { } callback && callback(null); return; } //console.log('____________远程音频加载成功:', name); this.audioCache[name] = audioClip; callback && callback(audioClip); }); }, fail: (saveErr: any) => { // saveFile 失败(50MB 超出 / temp 已被清理等),回退到 temp 直接加载 //console.log('____________saveFile 失败,回退到 temp 直接加载:', name, saveErr); cc.assetManager.loadRemote(tempFilePath, (err, audioClip: cc.AudioClip) => { if (err) { //console.error('____________远程音频加载失败:', name, err); callback && callback(null); return; } this.audioCache[name] = audioClip; callback && callback(audioClip); }); } }); }, fail: (err: any) => { //console.error('____________downloadFile 失败:', name, err); callback && callback(null); } }); } /** * 清除所有音频本地缓存(调试/换包用) */ clearLocalAudioCache(onComplete?: () => void) { if (!(cc.sys.platform === cc.sys.WECHAT_GAME)) { onComplete && onComplete(); return; } // @ts-ignore const fs = wx.getFileSystemManager(); const dir = this.getLocalCacheDir(); if (!dir) { onComplete && onComplete(); return; } fs.readdir({ dirPath: dir, success: (res: any) => { const files: string[] = res.files || []; let removed = 0; if (files.length === 0) { onComplete && onComplete(); return; } files.forEach((file) => { const filePath = dir + file; fs.unlink({ filePath: filePath, success: () => { removed++; if (removed === files.length) onComplete && onComplete(); }, fail: () => { removed++; if (removed === files.length) onComplete && onComplete(); } }); }); }, fail: () => { onComplete && onComplete(); } }); } play(audioSource: cc.AudioClip, loop: boolean, callback: Function, isBgMusic: boolean) { // if (isBgMusic && !this.mMusicSwitch) return; // if (!isBgMusic && !this.mEffectSwitch) return; const shouldPlayAsBackgroundMusic = isBgMusic === true; var volume = shouldPlayAsBackgroundMusic ? this.bgMusicVolume : this.effectMusicVolume; // if (cc.sys.isBrowser) { // if(audioSource == this.brickSound){ // volume = 0.1; // } volume = 1; cc.audioEngine.setEffectsVolume(1); cc.audioEngine.setMusicVolume(1); if (shouldPlayAsBackgroundMusic) { const musicContext = cc.audioEngine.playMusic(audioSource, loop); this.mAudioMap[audioSource.name] = musicContext; return audioSource; } if (audioSource.name == "lose" || audioSource.name == "zhuan1" || audioSource.name == "zhuan2") { cc.audioEngine.setEffectsVolume(0.5); } else { cc.audioEngine.setEffectsVolume(1); } var context = cc.audioEngine.playEffect(audioSource, loop); // if (callback) { // cc.audioEngine.setFinishCallback(context, function () { // if (this && callback) { // callback.call(this); // } // }.bind(this)); // } // cc.wwx.OutPut.log('play audio effect isBrowser: ' + context.src); this.mAudioMap[audioSource.name] = context; return audioSource; // } else { // return audioSource; // } } save() { // cc.wwx.Storage.setItem(cc.wwx.Storage.Key_Setting_Music_Volume, this.mMusicSwitch); // cc.wwx.Storage.setItem(cc.wwx.Storage.Key_Setting_Effect_Volume, this.mEffectSwitch); } // static get Instance() // { // if (this._instance == null) // { // this._instance = new AudioManager(); // } // return this._instance; // } preload() { if (!(cc.sys.platform === cc.sys.WECHAT_GAME || cc.sys.platform === cc.sys.BYTEDANCE_GAME)) { return; } // 音效全部预加载;背景音乐只预加载当前 AB 分组允许的资源。 const allSounds = Object.keys(this.audioUrlMap).filter((name) => { return this.isBackgroundMusicAllowedForGroup(name); }); console.log('AudioManager 开始按 layer_one 分组预加载音频,共', allSounds.length, '个'); this.preloadAudios( allSounds, (loaded, total) => { // console.log('音频预加载进度:', loaded, '/', total); }, () => { console.log('所有音频预加载完成'); }, // 当前场景对应的背景音乐加载完成后自动播放。 (name, clip) => { if (this.isBackgroundMusicName(name) && name === this.getSceneBackgroundMusicName() && clip) { if (cc.fx.GameConfig.GM_INFO && cc.fx.GameConfig.GM_INFO.musicOpen) { console.log(name, '加载完成,音乐开关已开启,自动播放'); this.playSceneMusic(); } else { console.log(name, '加载完成,但音乐开关未开启'); } } } ); } /** * 预加载指定的音频列表 * @param names 音频名称数组 * @param onProgress 进度回调 (loaded, total) * @param onComplete 完成回调 */ preloadAudios( names: string[], onProgress?: (loaded: number, total: number) => void, onComplete?: () => void, onItemLoaded?: (name: string, clip: cc.AudioClip) => void ) { if (!names || names.length === 0) { onComplete && onComplete(); return; } let loaded = 0; const total = names.length; const onOneLoaded = (name: string, clip: cc.AudioClip) => { loaded++; onItemLoaded && onItemLoaded(name, clip); onProgress && onProgress(loaded, total); if (loaded === total) onComplete && onComplete(); }; names.forEach((name) => { if (this[name] instanceof cc.AudioClip || this.audioCache[name]) { onOneLoaded(name, this[name] || this.audioCache[name]); return; } this.loadRemoteAudio(name, (clip) => { onOneLoaded(name, clip); }); }); } getAudioMusicSwitch() { return this.mMusicSwitch; } getAudioEffectSwitch() { return this.mEffectSwitch; } trunAudioSound(on) { this.switchMusic(on); this.switchEffect(on) } switchMusic(on) { if (this.mMusicSwitch != (on ? 1 : 0)) { this.mMusicSwitch = 1 - this.mMusicSwitch; // this.save(); } if (on) { this.playMusicGame(); } else { this.stopMusic(); } } switchEffect(on) { if (this.mEffectSwitch != (on ? 1 : 0)) { this.mEffectSwitch = 1 - this.mEffectSwitch; // this.save(); } } onHide() { try { if (!this.isAndroidWechatGame()) { return; } } catch (error) { this.logLifecycleAudioError('onHide 平台判断', error); return; } try { const gameInfo = cc.fx && cc.fx.GameConfig && cc.fx.GameConfig.GM_INFO; // Android 微信退后台或锁屏后,原音乐上下文可能无法正常 resume。 // 只要音乐开关开启,回前台时就按当时的场景和 AB 分组重新播放。 this.shouldRestartMusicOnShow = !!(gameInfo && gameInfo.musicOpen); } catch (error) { this.shouldRestartMusicOnShow = false; this.logLifecycleAudioError('onHide 读取音乐开关', error); } try { cc.audioEngine.pauseAll(); } catch (error) { this.logLifecycleAudioError('onHide 暂停音频', error); } try { this.stopMusic(); } catch (error) { this.logLifecycleAudioError('onHide 停止背景音乐', error); } } onShow() { try { if (!this.isAndroidWechatGame()) { return; } } catch (error) { this.logLifecycleAudioError('onShow 平台判断', error); return; } try { cc.audioEngine.resumeAll(); } catch (error) { this.logLifecycleAudioError('onShow 恢复音频', error); } if (!this.shouldRestartMusicOnShow) { return; } this.shouldRestartMusicOnShow = false; if (this.restartMusicTimer != null) { try { clearTimeout(this.restartMusicTimer); } catch (error) { this.logLifecycleAudioError('onShow 清理旧定时器', error); } this.restartMusicTimer = null; } try { // 等微信小游戏从锁屏/后台恢复音频环境后,再创建新的背景音乐播放。 this.restartMusicTimer = setTimeout(() => { this.restartMusicTimer = null; try { const gameInfo = cc.fx && cc.fx.GameConfig && cc.fx.GameConfig.GM_INFO; if (!gameInfo || !gameInfo.musicOpen) { return; } const sceneName = this.getCurrentSceneName(); const backgroundMusicName = this.getSceneBackgroundMusicName(sceneName); if (!backgroundMusicName) { return; } console.log( 'Android 微信小游戏回到前台,重新播放场景背景音乐:', sceneName, backgroundMusicName ); this.stopMusic(); this.playSceneMusic(sceneName); } catch (error) { this.logLifecycleAudioError('onShow 重新播放背景音乐', error); } }, 300); } catch (error) { this.restartMusicTimer = null; this.logLifecycleAudioError('onShow 创建恢复定时器', error); } } //播放音效 playEffect(name, callback) { if (!cc.fx.GameConfig.GM_INFO.effectOpen) { return; } if (this.isBackgroundMusicName(name)) { console.warn('背景音乐必须通过 playSceneMusic/playMusic 播放:', name); return; } // 1. 本地有 AudioClip 直接播放 if (this[name] instanceof cc.AudioClip) { // console.log('____________本地有音频成功:', name); return this.play(this[name], false, callback, false); } // 2. 缓存中有已加载的 AudioClip if (this.audioCache[name]) { // console.log('____________缓存音频加载成功:', name, this.audioCache); return this.play(this.audioCache[name], false, callback, false); } // console.log('____________最终走远程加载:', name); // 3. 远程加载 this.loadRemoteAudio(name, (clip) => { if (clip) { // console.log('____________远程音频加载成功:', name); this.play(clip, false, callback, false); } else { console.log('音效播放失败:', name); } }); } playMusic(key, callback, loop) { console.log("音频开关________________________________________", cc.fx.GameConfig.GM_INFO.musicOpen); if (!cc.fx.GameConfig.GM_INFO.musicOpen) { return; } loop = typeof loop == 'undefined' || loop ? true : false; const targetName = (key instanceof cc.AudioClip) ? key.name : key; if (this.isBackgroundMusicName(targetName)) { if (!this.isBackgroundMusicAllowedForGroup(targetName)) { console.warn('当前 layer_one 分组禁止播放背景音乐:', targetName); return; } const expectedName = this.getSceneBackgroundMusicName(); if (targetName !== expectedName) { console.warn('当前场景禁止播放背景音乐:', targetName, '期望:', expectedName); return; } } // 如果请求播放的就是当前音乐,不重复中断和重启。 if (this.mMusicKey != null && this.mMusicKey === targetName && cc.audioEngine.isMusicPlaying && cc.audioEngine.isMusicPlaying()) { console.log("当前已在播放的音乐,跳过 stop+restart,避免打断"); return; } // 场景切换时先停止旧背景音乐;请求编号用于拦截旧场景的异步加载回调。 this.stopMusic(); const requestId = ++this.musicRequestId; const playClip = (clip: cc.AudioClip, name: string) => { if (!clip || requestId !== this.musicRequestId) { return; } if (this.isBackgroundMusicName(name) && name !== this.getSceneBackgroundMusicName()) { return; } this.play(clip, loop, callback, true); this.mMusicKey = name; }; // key 可能是 AudioClip 实例,也可能是字符串名称 if (key instanceof cc.AudioClip) { playClip(key, targetName); console.log("开始播放音乐", key.name); return; } // 字符串名称:尝试从缓存或远程加载 const name = key; console.log("开始播放音乐的名称", name); if (this.audioCache[name]) { console.log("从缓存播放音乐", name); playClip(this.audioCache[name], name); } else { this.loadRemoteAudio(name, (clip) => { console.log("从远程加载音乐", name, clip); if (clip) { playClip(clip, name); } }); } } public playSceneMusic(sceneName?: string) { const backgroundMusicName = this.getSceneBackgroundMusicName(sceneName); if (!backgroundMusicName) { this.stopMusic(); return; } this.playMusic(backgroundMusicName, null, true); } /** * 兼容原有调用入口,根据当前场景和 layer_one 自动选择背景音乐。 */ playMusicGame() { this.playSceneMusic(); } /** * 停止背景音乐播放 */ stopMusic() { console.log("无论什么原因——————————————暂停了背景音乐播放", this.mMusicKey); this.musicRequestId++; this.mMusicKey = null; cc.audioEngine.stopMusic(); } /** * 恢复被暂停的背景音乐播放 */ resumeMusic() { // 调用 cc.audioEngine 的 resumeMusic 方法恢复音乐播放 cc.audioEngine.resumeMusic(); } /* * 游戏开始音效 * */ playGameStart() { } /* * 失败的游戏结束 */ playGameOver() { } /* * 成功的游戏结束 */ playGameResultFailed() { } /* * 成功的游戏结束 */ playGameResultSuccess() { } /** * 报警的音效 */ /** * 按钮 */ playAudioButton() { // return this.play(this.audioButtonClick, false,null,this.mEffectSwitch); } }; // export { AudioManager };