diff --git a/src/audioManager.js b/src/audioManager.js index d8d2fe8..c4db712 100644 --- a/src/audioManager.js +++ b/src/audioManager.js @@ -88,6 +88,11 @@ class AudioManager { this.isLoading = false; this.loadingPromise = null; + // 连续播放队列相关属性 + this.sequenceQueue = []; + this.sequenceIndex = 0; + this.isSequenceRunning = false; + // 网络状态相关 this.networkOnline = true; this.pendingPlayKey = null; @@ -206,6 +211,8 @@ class AudioManager { this.currentPlayingKey = null; } this.allowPlayMap.set(key, false); + // 触发连续播放队列的衔接 + this.onAudioEnded(key); }); // 监听播放停止事件 @@ -263,16 +270,51 @@ class AudioManager { this.createAudio(key); } - // 播放指定音频 - play(key) { - // 离线:缓存播放意图,待网络恢复后自动播放 + // 播放指定音频或音频数组(数组则按顺序连续播放) + play(input) { + // 离线:缓存播放意图(可为字符串或数组),待网络恢复后自动播放 + if (!this.networkOnline) { + this.pendingPlayKey = input; + debugLog(`网络不可用,记录播放意图: ${Array.isArray(input) ? input.join(',') : input}`); + return; + } + + // 再次调用 play:打断前面所有声音与队列 + this.stopAll(); + this.isSequenceRunning = false; + this.sequenceQueue = []; + this.sequenceIndex = 0; + + if (Array.isArray(input)) { + // 过滤可播放的 key + const queue = input.filter((k) => !!audioFils[k]); + if (queue.length === 0) { + debugLog("连续播放队列为空或无效"); + return; + } + this.sequenceQueue = queue; + this.sequenceIndex = 0; + this.isSequenceRunning = true; + // 开始播放队列的第一个 + this._playSingle(queue[0], false); + } else if (typeof input === "string") { + this._playSingle(input, false); + } else { + debugLog("play 参数类型无效,仅支持字符串或字符串数组"); + } + } + + // 内部方法:播放单个 key + _playSingle(key, forceStopAll = false) { if (!this.networkOnline) { this.pendingPlayKey = key; debugLog(`网络不可用,记录播放意图: ${key}`); return; } - // 覆盖播放:若当前播放且不是同一音频,先停止当前播放 - if (this.currentPlayingKey && this.currentPlayingKey !== key) { + + if (forceStopAll) { + this.stopAll(); + } else if (this.currentPlayingKey && this.currentPlayingKey !== key) { this.stop(this.currentPlayingKey); } @@ -303,6 +345,25 @@ class AudioManager { } } + // 连续播放:在某个音频结束后,若处于队列播放状态则继续下一个 + onAudioEnded(key) { + if (!this.isSequenceRunning) return; + const currentKey = this.sequenceQueue[this.sequenceIndex]; + if (currentKey !== key) return; + + const nextIndex = this.sequenceIndex + 1; + if (nextIndex < this.sequenceQueue.length) { + this.sequenceIndex = nextIndex; + const nextKey = this.sequenceQueue[nextIndex]; + this._playSingle(nextKey, false); + } else { + // 队列播放完成 + this.isSequenceRunning = false; + this.sequenceQueue = []; + this.sequenceIndex = 0; + } + } + // 停止指定音频 stop(key) { const audio = this.audioMap.get(key); diff --git a/src/components/HeaderProgress.vue b/src/components/HeaderProgress.vue index 94b967c..9ab2254 100644 --- a/src/components/HeaderProgress.vue +++ b/src/components/HeaderProgress.vue @@ -22,26 +22,23 @@ const totalShot = ref(0); watch( () => tips.value, (newVal) => { - let key = ""; - if (newVal.includes("重回")) return; - if (newVal.includes("红队")) key = "请红方射箭"; - if (newVal.includes("蓝队")) key = "请蓝方射箭"; if (!sound.value) return; + let key = []; + if (newVal.includes("重回")) return; if (currentRoundEnded.value) { currentRound.value += 1; // 播放当前轮次语音 - audioManager.play( - `第${["一", "二", "三", "四", "五"][currentRound.value - 1]}轮` - ); + key.push(`第${["一", "二", "三", "四", "五"][currentRound.value - 1]}轮`); } - // 延迟播放队伍提示音 - setTimeout( - () => { - if (key) audioManager.play(newVal.includes("你") ? "轮到你了" : key); - currentRoundEnded.value = false; - }, - currentRoundEnded.value ? 1000 : 0 + key.push( + newVal.includes("你") + ? "轮到你了" + : newVal.includes("红队") + ? "请红方射箭" + : "请蓝方射箭" ); + audioManager.play(key); + currentRoundEnded.value = false; } ); diff --git a/src/pages/audio-test.vue b/src/pages/audio-test.vue index a81381f..2bef875 100644 --- a/src/pages/audio-test.vue +++ b/src/pages/audio-test.vue @@ -26,6 +26,18 @@ onBeforeUnmount(() => {