音频资源加入cdn方案
This commit is contained in:
parent
0c7df8acd1
commit
a00361d157
|
|
@ -139,96 +139,35 @@
|
|||
"__id__": 2
|
||||
},
|
||||
"_enabled": true,
|
||||
"audioGameBgm0": {
|
||||
"__uuid__": "75b4f368-70b5-452d-9afd-ca7a6f1e2e60"
|
||||
},
|
||||
"xiaochu": {
|
||||
"__uuid__": "8d67c864-c7f4-4305-8b3b-2d66eb69e349"
|
||||
},
|
||||
"hit": {
|
||||
"__uuid__": "7575a6bd-a21d-491e-aad2-e40a189683e9"
|
||||
},
|
||||
"down": {
|
||||
"__uuid__": "ec293610-1767-46e8-b6b6-4a9a79ef2233"
|
||||
},
|
||||
"fangxiang": null,
|
||||
"build": null,
|
||||
"win": {
|
||||
"__uuid__": "9f2906df-601d-4dfa-a561-31745b62c9dd"
|
||||
},
|
||||
"lose": null,
|
||||
"anniu_Big": {
|
||||
"__uuid__": "7362cac7-12b5-4704-af6d-5b110c5e9fcf"
|
||||
},
|
||||
"anniu_little": {
|
||||
"__uuid__": "a5518b0f-7ed3-46f0-aa78-93f02f4579cc"
|
||||
},
|
||||
"tanchuang": {
|
||||
"__uuid__": "1301aea4-4351-40d8-b4c4-e428613b3681"
|
||||
},
|
||||
"zhuan1": {
|
||||
"__uuid__": "e4d2f16e-7663-4ee5-a479-06ae0eae91d5"
|
||||
},
|
||||
"zhuan2": {
|
||||
"__uuid__": "998a24bd-ffa0-4f96-bc39-a9789f42bd9b"
|
||||
},
|
||||
"adhesive": {
|
||||
"__uuid__": "e0f2c22c-d8dd-4dad-9fa2-7b73d15a5518"
|
||||
},
|
||||
"freezeBlock": {
|
||||
"__uuid__": "9a056601-12c6-45dd-abde-a847d6f15247"
|
||||
},
|
||||
"freezeDoor": {
|
||||
"__uuid__": "20367986-5fa0-4558-9c73-861dc7bc1293"
|
||||
},
|
||||
"hammer": {
|
||||
"__uuid__": "a25b43cf-deba-4061-a5da-e87aa343269d"
|
||||
},
|
||||
"lockBlock1": {
|
||||
"__uuid__": "227cb730-4de8-41e2-93d1-f9e8cfdffd11"
|
||||
},
|
||||
"lockBlock2": {
|
||||
"__uuid__": "2cfcd2ad-bb5d-47c0-be0a-3a8135d89c1f"
|
||||
},
|
||||
"lockDoor": {
|
||||
"__uuid__": "25ca59d5-b522-472d-83e4-de16fd1cdd5c"
|
||||
},
|
||||
"magic1": {
|
||||
"__uuid__": "b8ec297a-cc2d-4a82-ac2c-345db075ce84"
|
||||
},
|
||||
"magic2": {
|
||||
"__uuid__": "e09b4699-ba82-4ac8-9894-d8b88640d041"
|
||||
},
|
||||
"simpleColor": {
|
||||
"__uuid__": "6f213771-d0ef-45ba-b87d-e878f291886b"
|
||||
},
|
||||
"stacking": {
|
||||
"__uuid__": "2c418573-4beb-49f8-bafe-6a9ae7906195"
|
||||
},
|
||||
"starBlock": {
|
||||
"__uuid__": "643d1ba5-fd6f-45ab-928e-c271afddbcef"
|
||||
},
|
||||
"timePause1": {
|
||||
"__uuid__": "f5c8c01d-aa75-4518-a7c6-82599ad31e58"
|
||||
},
|
||||
"timePause2": {
|
||||
"__uuid__": "37c7f2a9-e0d2-4f3e-9ed6-1ad2ef1862c0"
|
||||
},
|
||||
"hit1": {
|
||||
"__uuid__": "e16fd77e-9bbb-4bd1-b149-e1dd5a409c8f"
|
||||
},
|
||||
"hit2": {
|
||||
"__uuid__": "bab2f84c-f988-4355-8fc7-2c55a09cc089"
|
||||
},
|
||||
"hit3": {
|
||||
"__uuid__": "e06aa433-8f1d-4787-8e6d-7fe6a29ca6f5"
|
||||
},
|
||||
"hit4": {
|
||||
"__uuid__": "ed4cf450-ae51-46ce-997a-50dd75d9a519"
|
||||
},
|
||||
"hit5": {
|
||||
"__uuid__": "b27d353c-e4fe-46de-b7c9-75d2b96363d3"
|
||||
},
|
||||
"main_bgm": null,
|
||||
"xiaochu": null,
|
||||
"hit": null,
|
||||
"down": null,
|
||||
"win": null,
|
||||
"anniu_Big": null,
|
||||
"anniu_little": null,
|
||||
"tanchuang": null,
|
||||
"zhuan1": null,
|
||||
"zhuan2": null,
|
||||
"adhesive": null,
|
||||
"freezeBlock": null,
|
||||
"freezeDoor": null,
|
||||
"hammer": null,
|
||||
"lockBlock1": null,
|
||||
"lockBlock2": null,
|
||||
"lockDoor": null,
|
||||
"magic1": null,
|
||||
"magic2": null,
|
||||
"simpleColor": null,
|
||||
"stacking": null,
|
||||
"starBlock": null,
|
||||
"timePause1": null,
|
||||
"timePause2": null,
|
||||
"hit1": null,
|
||||
"hit2": null,
|
||||
"hit3": null,
|
||||
"hit4": null,
|
||||
"hit5": null,
|
||||
"_id": "24lN1LYRdNia3ZOiLsINIp"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1418,6 +1418,7 @@ export default class Block extends cc.Component {
|
|||
this.node.removeFromParent();
|
||||
}
|
||||
|
||||
const deadCheckVersion = MapConroler._instance.nextDeadCheckVersion();
|
||||
setTimeout(() => {
|
||||
if (MapConroler._instance) {
|
||||
if (MapConroler._instance.blockNum != 0 && (MapConroler._instance.openWall.length > 0 ||
|
||||
|
|
@ -1426,10 +1427,7 @@ export default class Block extends cc.Component {
|
|||
|| MapConroler._instance.change_colorBlock == true || MapConroler._instance.jump_state != null || MapConroler._instance.buttonWall.length > 0)
|
||||
&& !MapConroler._instance.gameOver && !MapConroler._instance.gameWin) {
|
||||
|
||||
let gameover = MapConroler._instance.predict_End(true);
|
||||
if (gameover == false) {
|
||||
MapConroler._instance.failReason();
|
||||
}
|
||||
MapConroler._instance.requestPredictEndCheck(deadCheckVersion);
|
||||
}
|
||||
}
|
||||
}, 1200);
|
||||
|
|
@ -2058,6 +2056,7 @@ export default class Block extends cc.Component {
|
|||
this.node.removeFromParent();
|
||||
}
|
||||
MapConroler._instance.checkColor(colorTemp, true, this.node);
|
||||
const deadCheckVersion = MapConroler._instance.nextDeadCheckVersion();
|
||||
setTimeout(() => {
|
||||
if (MapConroler._instance) {
|
||||
if (MapConroler._instance.blockNum != 0 && (MapConroler._instance.openWall.length > 0 ||
|
||||
|
|
@ -2065,10 +2064,7 @@ export default class Block extends cc.Component {
|
|||
MapConroler._instance.blockLock == true
|
||||
|| MapConroler._instance.change_colorBlock == true || MapConroler._instance.jump_state != null || MapConroler._instance.buttonWall.length > 0)
|
||||
&& !MapConroler._instance.gameOver && !MapConroler._instance.gameWin) {
|
||||
let gameover = MapConroler._instance.predict_End(true);
|
||||
if (gameover == false) {
|
||||
MapConroler._instance.failReason();
|
||||
}
|
||||
MapConroler._instance.requestPredictEndCheck(deadCheckVersion);
|
||||
}
|
||||
}
|
||||
}, 900);
|
||||
|
|
@ -2270,6 +2266,7 @@ export default class Block extends cc.Component {
|
|||
}
|
||||
MapConroler._instance.checkColor(colorTemp, true, this.node);
|
||||
|
||||
const deadCheckVersion = MapConroler._instance.nextDeadCheckVersion();
|
||||
setTimeout(() => {
|
||||
if (MapConroler._instance) {
|
||||
if (MapConroler._instance.blockNum != 0 && (MapConroler._instance.openWall.length > 0 ||
|
||||
|
|
@ -2277,10 +2274,7 @@ export default class Block extends cc.Component {
|
|||
MapConroler._instance.blockLock == true
|
||||
|| MapConroler._instance.change_colorBlock == true || MapConroler._instance.jump_state != null || MapConroler._instance.buttonWall.length > 0)
|
||||
&& !MapConroler._instance.gameOver && !MapConroler._instance.gameWin) {
|
||||
let gameover = MapConroler._instance.predict_End(true);
|
||||
if (gameover == false) {
|
||||
MapConroler._instance.failReason();
|
||||
}
|
||||
MapConroler._instance.requestPredictEndCheck(deadCheckVersion);
|
||||
}
|
||||
}
|
||||
}, 1200);
|
||||
|
|
|
|||
|
|
@ -158,12 +158,14 @@ export default class GameManager extends cc.Component {
|
|||
|
||||
}
|
||||
onHide() {
|
||||
cc.audioEngine.stopMusic();
|
||||
// 只暂停游戏逻辑,不要 stopMusic —— 微信小游戏 InnerAudioContext 的 resumeMusic 经常失效
|
||||
// 用 pauseAll,回前台时用 resumeAll 续播,保证退回 HomeScene 时音乐不被中断/丢失
|
||||
cc.audioEngine.pauseAll();
|
||||
cc.game.pause();
|
||||
}
|
||||
|
||||
onShow() {
|
||||
cc.audioEngine.resumeMusic();
|
||||
cc.audioEngine.resumeAll();
|
||||
cc.game.resume();
|
||||
}
|
||||
//#region 给加载好的墙壁资源排序
|
||||
|
|
@ -204,18 +206,19 @@ export default class GameManager extends cc.Component {
|
|||
if (err) {
|
||||
console.error('加载 shop 失败:', err);
|
||||
} else {
|
||||
// 加载成功后进入 HomeScene
|
||||
cc.assetManager.loadBundle('music', (err, bundle) => {
|
||||
if (err) {
|
||||
console.error('加载 music bundle 失败:', err);
|
||||
// 加载失败时仍尝试进入 HomeScene
|
||||
} else {
|
||||
}
|
||||
setTimeout(() => {
|
||||
cc.director.loadScene("HomeScene");
|
||||
}, 300);
|
||||
// 加载成功后进入 HomeScene
|
||||
// cc.assetManager.loadBundle('music', (err, bundle) => {
|
||||
// if (err) {
|
||||
// console.error('加载 music bundle 失败:', err);
|
||||
// // 加载失败时仍尝试进入 HomeScene
|
||||
// } else {
|
||||
// }
|
||||
// setTimeout(() => {
|
||||
|
||||
});
|
||||
// }, 300);
|
||||
|
||||
// });
|
||||
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ export default class JiaZai extends cc.Component {
|
|||
if (cc.fx.GameConfig.GM_INFO.openid) {
|
||||
if (cc.fx.GameConfig.GM_INFO.openid == "orm8I7N10NSQdAhN4LP04n8UP56I") {
|
||||
this.node.getChildByName("Load").getChildByName("New EditBox").active = true;
|
||||
cc.fx.GameTool.changeCoin(9999);
|
||||
// cc.fx.GameTool.changeCoin(9999);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ export default class JiaZai extends cc.Component {
|
|||
}
|
||||
|
||||
//console.log("音乐开关", cc.fx.GameConfig.GM_INFO.musicOpen);
|
||||
AudioManager._instance.playMusicGame();
|
||||
// AudioManager._instance.playMusicGame();
|
||||
// 从房间出来判断是否弹出通行证
|
||||
this.popUpPassCheck();
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ export default class MapConroler extends cc.Component {
|
|||
new_mode: number = 0;
|
||||
new_item: number = 0;
|
||||
autoNextAfterNewMode: boolean = false;
|
||||
deadCheckVersion: number = 0;
|
||||
deadCheckConfirmDelay: number = 450;
|
||||
mapWidth: number = 0;
|
||||
mapHeight: number = 0;
|
||||
wallNum: number = 0;
|
||||
|
|
@ -5899,6 +5901,45 @@ export default class MapConroler extends cc.Component {
|
|||
}
|
||||
|
||||
//提前判断游戏结束
|
||||
nextDeadCheckVersion() {
|
||||
this.deadCheckVersion += 1;
|
||||
return this.deadCheckVersion;
|
||||
}
|
||||
|
||||
canRunPredictEndCheck() {
|
||||
return this.blockNum != 0 && (this.openWall.length > 0 ||
|
||||
this.revolving_state != 0 || this.longAndShortWall.length > 0 ||
|
||||
this.blockLock == true || this.change_colorBlock == true ||
|
||||
this.jump_state != null || this.buttonWall.length > 0)
|
||||
&& !this.gameOver && !this.gameWin;
|
||||
}
|
||||
|
||||
requestPredictEndCheck(version: number) {
|
||||
if (version != this.deadCheckVersion || !this.canRunPredictEndCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let gameover = this.predict_End(true);
|
||||
if (gameover != false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.openWall.length > 0) {
|
||||
setTimeout(() => {
|
||||
if (version != this.deadCheckVersion || !this.canRunPredictEndCheck()) {
|
||||
return;
|
||||
}
|
||||
let confirmGameover = this.predict_End(true);
|
||||
if (confirmGameover == false) {
|
||||
this.failReason();
|
||||
}
|
||||
}, this.deadCheckConfirmDelay);
|
||||
return;
|
||||
}
|
||||
|
||||
this.failReason();
|
||||
}
|
||||
|
||||
predict_End(type) {
|
||||
//return true;
|
||||
// console.log("提前判断游戏结束");
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ export class GameConfig {
|
|||
vibrateOpen: true, //震动
|
||||
coinnum: 0, //每局的金币数
|
||||
paid_user: false, //是否是付费用户
|
||||
version: "1.9.94", //版本号
|
||||
version: "1.9.95", //版本号
|
||||
shushu_DistinctId: "", //数数访客ID
|
||||
shushu_AccountId: "", //数数账号ID
|
||||
uid: "", //用户和后端唯一id
|
||||
|
|
|
|||
|
|
@ -4,10 +4,41 @@ 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 } = {};
|
||||
// 远程 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)
|
||||
audioGameBgm0: cc.AudioClip = null;
|
||||
|
||||
main_bgm: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
xiaochu: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
|
|
@ -15,14 +46,8 @@ export default class AudioManager extends cc.Component {
|
|||
@property(cc.AudioClip)
|
||||
down: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
fangxiang: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
build: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
win: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
lose: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
anniu_Big: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
anniu_little: cc.AudioClip = null;
|
||||
|
|
@ -32,8 +57,6 @@ export default class AudioManager extends cc.Component {
|
|||
zhuan1: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
zhuan2: cc.AudioClip = null;
|
||||
|
||||
|
||||
@property(cc.AudioClip)
|
||||
adhesive: cc.AudioClip = null;
|
||||
@property(cc.AudioClip)
|
||||
|
|
@ -112,6 +135,257 @@ export default class AudioManager extends cc.Component {
|
|||
|
||||
this.mMusicSwitch = 1;
|
||||
this.mEffectSwitch = 1;
|
||||
|
||||
// 初始化远程音频 URL 映射
|
||||
this.initAudioUrlMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化远程音频 URL 映射表
|
||||
* 将所有音频文件路径映射到 CDN 完整 URL
|
||||
*/
|
||||
initAudioUrlMap() {
|
||||
const base = this.CDN_AUDIO_BASE;
|
||||
// 音效列表
|
||||
const names = [
|
||||
'main_bgm', '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';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取远程音频 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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 3. 从远程 CDN 加载
|
||||
const url = this.getRemoteUrl(name);
|
||||
// console.log('远程加载音频:', name, url);
|
||||
if (url == null || url == "") {
|
||||
callback && callback(null);
|
||||
return;
|
||||
}
|
||||
// 微信小游戏:先查本地缓存,没有再下载
|
||||
if (cc.sys.platform === cc.sys.WECHAT_GAME) {
|
||||
// @ts-ignore
|
||||
if (typeof wx !== 'undefined' && wx.downloadFile) {
|
||||
this.loadRemoteAudioWithCache(name, url, callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 其他平台直接 loadRemote
|
||||
cc.assetManager.loadRemote(url, (err, audioClip: cc.AudioClip) => {
|
||||
if (err) {
|
||||
console.error('远程音频加载失败:', name, err);
|
||||
callback && callback(null);
|
||||
return;
|
||||
}
|
||||
this.audioCache[name] = audioClip;
|
||||
callback && callback(audioClip);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信小游戏:优先从本地缓存加载音频,没有则下载并保存到本地
|
||||
* 缓存路径: wx.env.USER_DATA_PATH/audio_cache/<name>.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, loop, callback, isBgMusic) {
|
||||
// if (isBgMusic && !this.mMusicSwitch) return;
|
||||
|
|
@ -165,13 +439,65 @@ export default class AudioManager extends cc.Component {
|
|||
preload() {
|
||||
if (!(cc.sys.platform === cc.sys.WECHAT_GAME || cc.sys.platform === cc.sys.BYTEDANCE_GAME)) { return; }
|
||||
|
||||
var musics = [
|
||||
this.audioGameBgm0,
|
||||
];
|
||||
musics.forEach(function (path) {
|
||||
})
|
||||
// console.log("音乐开关", cc.fx.GameConfig.GM_INFO.musicOpen);
|
||||
// this.playMusicGame();
|
||||
// 预加载所有音频
|
||||
const allSounds = Object.keys(this.audioUrlMap);
|
||||
console.log('AudioManager 开始预加载所有音频,共', allSounds.length, '个');
|
||||
this.preloadAudios(
|
||||
allSounds,
|
||||
(loaded, total) => {
|
||||
// console.log('音频预加载进度:', loaded, '/', total);
|
||||
},
|
||||
() => {
|
||||
console.log('所有音频预加载完成');
|
||||
},
|
||||
// 单条加载完成回调:main_bgm 特殊处理
|
||||
(name, clip) => {
|
||||
if (name === 'main_bgm' && clip) {
|
||||
// main_bgm 加载完成后,如果音乐开关是打开的,自动播放
|
||||
if (cc.fx.GameConfig.GM_INFO && cc.fx.GameConfig.GM_INFO.musicOpen) {
|
||||
console.log('main_bgm 加载完成,音乐开关已开启,自动播放');
|
||||
this.playMusic('main_bgm', null, true);
|
||||
} else {
|
||||
console.log('main_bgm 加载完成,但音乐开关未开启');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载指定的音频列表
|
||||
* @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() {
|
||||
|
|
@ -217,30 +543,96 @@ export default class AudioManager extends cc.Component {
|
|||
if (!cc.fx.GameConfig.GM_INFO.effectOpen) {
|
||||
return;
|
||||
}
|
||||
if (this[name])
|
||||
// 1. 本地有 AudioClip 直接播放
|
||||
if (this[name] instanceof cc.AudioClip) {
|
||||
// console.log('____________本地有音频成功:', name);
|
||||
return this.play(this[name], false, callback, this.mEffectSwitch);
|
||||
}
|
||||
// 2. 缓存中有已加载的 AudioClip
|
||||
if (this.audioCache[name]) {
|
||||
// console.log('____________缓存音频加载成功:', name, this.audioCache);
|
||||
return this.play(this.audioCache[name], false, callback, this.mEffectSwitch);
|
||||
}
|
||||
// console.log('____________最终走远程加载:', name);
|
||||
// 3. 远程加载
|
||||
this.loadRemoteAudio(name, (clip) => {
|
||||
if (clip) {
|
||||
// console.log('____________远程音频加载成功:', name);
|
||||
this.play(clip, false, callback, this.mEffectSwitch);
|
||||
} else {
|
||||
console.log('音效播放失败:', name);
|
||||
}
|
||||
});
|
||||
}
|
||||
playMusic(key, callback, loop) {
|
||||
// console.log("音频开关________________________________________");
|
||||
console.log("音频开关________________________________________", cc.fx.GameConfig.GM_INFO.musicOpen);
|
||||
if (!cc.fx.GameConfig.GM_INFO.musicOpen) {
|
||||
return;
|
||||
}
|
||||
loop = typeof loop == 'undefined' || loop ? true : false;
|
||||
this.stopMusic();
|
||||
this.mMusicKey = this.play(key, loop, callback, true);
|
||||
|
||||
// 如果请求播放的就是当前已在播放的音乐,跳过 stop+restart,避免打断
|
||||
const targetName = (key instanceof cc.AudioClip) ? key.name : key;
|
||||
if (this.mMusicKey != null && this.mMusicKey === targetName
|
||||
&& cc.audioEngine.isMusicPlaying && cc.audioEngine.isMusicPlaying()) {
|
||||
console.log("当前已在播放的音乐,跳过 stop+restart,避免打断");
|
||||
return;
|
||||
}
|
||||
|
||||
// this.stopMusic();
|
||||
|
||||
// key 可能是 AudioClip 实例,也可能是字符串名称
|
||||
if (key instanceof cc.AudioClip) {
|
||||
this.mMusicKey = this.play(key, loop, callback, true);
|
||||
console.log("开始播放音乐", key.name);
|
||||
return;
|
||||
}
|
||||
|
||||
// 字符串名称:尝试从缓存或远程加载
|
||||
const name = key;
|
||||
console.log("开始播放音乐的名称", name);
|
||||
const playFromCache = () => {
|
||||
console.log("从缓存播放音乐", name);
|
||||
if (this.audioCache[name]) {
|
||||
this.mMusicKey = this.play(this.audioCache[name], loop, callback, true);
|
||||
} else {
|
||||
console.log('背景音乐播放失败:', name);
|
||||
}
|
||||
};
|
||||
if (this.audioCache[name]) {
|
||||
console.log("从缓存播放音乐", name);
|
||||
playFromCache();
|
||||
} else {
|
||||
this.loadRemoteAudio(name, (clip) => {
|
||||
console.log("从远程加载音乐", name, clip);
|
||||
if (clip) {
|
||||
this.mMusicKey = this.play(clip, loop, callback, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 游戏背景音乐
|
||||
* 仅当音乐开关开启、且当前没有在播放 main_bgm 时才真正播放
|
||||
* 避免从 GameScene 退回 HomeScene 时被打断重启
|
||||
*/
|
||||
playMusicGame() {
|
||||
this.stopMusic();
|
||||
this.playMusic(this.audioGameBgm0, {}, true);
|
||||
|
||||
if (!cc.fx.GameConfig.GM_INFO.musicOpen) {
|
||||
return;
|
||||
}
|
||||
// 已经在播背景音乐(musicId 不为 -1)就不再打断
|
||||
if (this.mMusicKey != null && this.mMusicKey !== undefined && cc.audioEngine.isMusicPlaying && cc.audioEngine.isMusicPlaying()) {
|
||||
return;
|
||||
}
|
||||
console.log("开始播放音乐");
|
||||
this.playMusic('main_bgm', null, true);
|
||||
}
|
||||
/**
|
||||
* 停止背景音乐播放
|
||||
*/
|
||||
stopMusic() {
|
||||
console.log("无论什么原因——————————————暂停了背景音乐播放", this.mMusicKey);
|
||||
// cc.wwx.OutPut.log('stopMusic audio effect wx: ' + this.mMusicKey);
|
||||
cc.audioEngine.stopAll();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@
|
|||
"trimThreshold": 1,
|
||||
"rotated": false,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"offsetY": 0.5,
|
||||
"trimX": 0,
|
||||
"trimY": 0,
|
||||
"width": 175,
|
||||
"height": 190,
|
||||
"height": 189,
|
||||
"rawWidth": 175,
|
||||
"rawHeight": 190,
|
||||
"borderTop": 0,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"ver": "1.1.3",
|
||||
"uuid": "6ebfe2d9-539a-4853-8b16-fca5c89cf2ce",
|
||||
"importer": "folder",
|
||||
"isBundle": true,
|
||||
"isBundle": false,
|
||||
"bundleName": "music",
|
||||
"priority": 9,
|
||||
"compressionType": {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"appid": "wxdd145ced49158a1e",
|
||||
"orientation": "portrait",
|
||||
"separate_engine": true,
|
||||
"REMOTE_SERVER_ROOT": "",
|
||||
"REMOTE_SERVER_ROOT": "https://cdn.pay.nika4games.com/",
|
||||
"subContext": "SubContextView",
|
||||
"startSceneAssetBundle": true
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user