添加了抽奖中和抽奖完成时的音效
This commit is contained in:
BIN
src/assets/audio/end.mp3
Normal file
BIN
src/assets/audio/end.mp3
Normal file
Binary file not shown.
BIN
src/assets/audio/worldcup.mp3
Normal file
BIN
src/assets/audio/worldcup.mp3
Normal file
Binary file not shown.
@@ -9,6 +9,8 @@ import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls
|
|||||||
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import enterAudio from '@/assets/audio/enter.wav'
|
import enterAudio from '@/assets/audio/enter.wav'
|
||||||
|
import worldCupAudio from '@/assets/audio/worldcup.mp3'
|
||||||
|
import dongSound from '@/assets/audio/end.mp3'
|
||||||
import { useElementPosition, useElementStyle } from '@/hooks/useElement'
|
import { useElementPosition, useElementStyle } from '@/hooks/useElement'
|
||||||
import i18n from '@/locales/i18n'
|
import i18n from '@/locales/i18n'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
@@ -70,6 +72,10 @@ export function useViewModel() {
|
|||||||
const isInitialDone = ref<boolean>(false)
|
const isInitialDone = ref<boolean>(false)
|
||||||
const animationFrameId = ref<any>(null)
|
const animationFrameId = ref<any>(null)
|
||||||
const playingAudios = ref<HTMLAudioElement[]>([])
|
const playingAudios = ref<HTMLAudioElement[]>([])
|
||||||
|
|
||||||
|
// 抽奖音乐相关
|
||||||
|
const lotteryMusic = ref<HTMLAudioElement | null>(null)
|
||||||
|
|
||||||
function initThreeJs() {
|
function initThreeJs() {
|
||||||
const felidView = 40
|
const felidView = 40
|
||||||
const width = window.innerWidth
|
const width = window.innerWidth
|
||||||
@@ -312,6 +318,90 @@ export function useViewModel() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 开始抽奖音乐
|
||||||
|
*/
|
||||||
|
function startLotteryMusic() {
|
||||||
|
if (lotteryMusic.value) {
|
||||||
|
lotteryMusic.value.pause()
|
||||||
|
lotteryMusic.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
lotteryMusic.value = new Audio(worldCupAudio)
|
||||||
|
lotteryMusic.value.loop = true
|
||||||
|
lotteryMusic.value.volume = 0.7
|
||||||
|
|
||||||
|
lotteryMusic.value.play().catch((error) => {
|
||||||
|
console.error('播放抽奖音乐失败:', error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 停止抽奖音乐
|
||||||
|
*/
|
||||||
|
function stopLotteryMusic() {
|
||||||
|
if (lotteryMusic.value) {
|
||||||
|
lotteryMusic.value.pause()
|
||||||
|
lotteryMusic.value = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 播放结束音效
|
||||||
|
*/
|
||||||
|
function playEndSound() {
|
||||||
|
console.log('准备播放结束音效', dongSound)
|
||||||
|
|
||||||
|
// 清理已结束的音频
|
||||||
|
playingAudios.value = playingAudios.value.filter(audio => !audio.ended)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const endSound = new Audio(dongSound)
|
||||||
|
endSound.volume = 1.0
|
||||||
|
|
||||||
|
// 简化播放逻辑
|
||||||
|
const playPromise = endSound.play()
|
||||||
|
|
||||||
|
if (playPromise) {
|
||||||
|
playPromise
|
||||||
|
.then(() => {
|
||||||
|
console.log('结束音效播放成功')
|
||||||
|
playingAudios.value.push(endSound)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error('播放失败:', err.name, err.message)
|
||||||
|
if (err.name === 'NotAllowedError') {
|
||||||
|
console.warn('自动播放被阻止,需用户交互后播放')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
endSound.onended = () => {
|
||||||
|
console.log('结束音效播放完成')
|
||||||
|
const index = playingAudios.value.indexOf(endSound)
|
||||||
|
if (index > -1) playingAudios.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建音频对象失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 重置音频状态
|
||||||
|
*/
|
||||||
|
function resetAudioState() {
|
||||||
|
// 停止抽奖音乐
|
||||||
|
stopLotteryMusic()
|
||||||
|
|
||||||
|
// 清理所有正在播放的音频
|
||||||
|
playingAudios.value.forEach(audio => {
|
||||||
|
if (!audio.ended && !audio.paused) {
|
||||||
|
audio.pause()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
playingAudios.value = []
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 开始抽奖,由横铺变换为球体(或其他图形)
|
* @description: 开始抽奖,由横铺变换为球体(或其他图形)
|
||||||
* @returns 随机抽取球数据
|
* @returns 随机抽取球数据
|
||||||
@@ -321,6 +411,20 @@ export function useViewModel() {
|
|||||||
if (!canOperate.value) {
|
if (!canOperate.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重置音频状态
|
||||||
|
resetAudioState()
|
||||||
|
|
||||||
|
// 预加载音频资源以解决浏览器自动播放策略
|
||||||
|
try {
|
||||||
|
const audioContext = window.AudioContext || (window as any).webkitAudioContext
|
||||||
|
if (audioContext) {
|
||||||
|
console.log('音频上下文可用')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('音频上下文不可用:', e)
|
||||||
|
}
|
||||||
|
|
||||||
if (!intervalTimer.value) {
|
if (!intervalTimer.value) {
|
||||||
randomBallData()
|
randomBallData()
|
||||||
}
|
}
|
||||||
@@ -396,6 +500,10 @@ export function useViewModel() {
|
|||||||
position: 'top-right',
|
position: 'top-right',
|
||||||
duration: 8000,
|
duration: 8000,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 开始播放抽奖音乐
|
||||||
|
startLotteryMusic()
|
||||||
|
|
||||||
currentStatus.value = LotteryStatus.running
|
currentStatus.value = LotteryStatus.running
|
||||||
rollBall(10, 3000)
|
rollBall(10, 3000)
|
||||||
if (definiteTime.value) {
|
if (definiteTime.value) {
|
||||||
@@ -413,6 +521,12 @@ export function useViewModel() {
|
|||||||
if (!canOperate.value) {
|
if (!canOperate.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 停止抽奖音乐
|
||||||
|
stopLotteryMusic()
|
||||||
|
|
||||||
|
// 播放结束音效
|
||||||
|
playEndSound()
|
||||||
|
|
||||||
// clearInterval(intervalTimer.value)
|
// clearInterval(intervalTimer.value)
|
||||||
// intervalTimer.value = null
|
// intervalTimer.value = null
|
||||||
canOperate.value = false
|
canOperate.value = false
|
||||||
@@ -459,11 +573,17 @@ export function useViewModel() {
|
|||||||
}
|
}
|
||||||
// 播放音频,中将卡片越多audio对象越多,声音越大
|
// 播放音频,中将卡片越多audio对象越多,声音越大
|
||||||
function playWinMusic() {
|
function playWinMusic() {
|
||||||
|
// 清理已结束的音频
|
||||||
|
playingAudios.value = playingAudios.value.filter(audio => !audio.ended && !audio.paused)
|
||||||
|
|
||||||
if (playingAudios.value.length > maxAudioLimit) {
|
if (playingAudios.value.length > maxAudioLimit) {
|
||||||
console.log('音频播放数量已达到上限,请勿重复播放')
|
console.log('音频播放数量已达到上限,请勿重复播放')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const enterNewAudio = new Audio(enterAudio)
|
const enterNewAudio = new Audio(enterAudio)
|
||||||
|
enterNewAudio.volume = 0.8
|
||||||
|
|
||||||
playingAudios.value.push(enterNewAudio)
|
playingAudios.value.push(enterNewAudio)
|
||||||
enterNewAudio.play()
|
enterNewAudio.play()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -483,6 +603,14 @@ export function useViewModel() {
|
|||||||
playingAudios.value.splice(index, 1)
|
playingAudios.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 播放错误时从数组中移除
|
||||||
|
enterNewAudio.onerror = () => {
|
||||||
|
const index = playingAudios.value.indexOf(enterNewAudio)
|
||||||
|
if (index > -1) {
|
||||||
|
playingAudios.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @description: 继续,意味着这抽奖作数,计入数据库
|
* @description: 继续,意味着这抽奖作数,计入数据库
|
||||||
@@ -514,6 +642,9 @@ export function useViewModel() {
|
|||||||
* @description: 放弃本次抽奖,回到初始状态
|
* @description: 放弃本次抽奖,回到初始状态
|
||||||
*/
|
*/
|
||||||
function quitLottery() {
|
function quitLottery() {
|
||||||
|
// 停止抽奖音乐
|
||||||
|
stopLotteryMusic()
|
||||||
|
|
||||||
enterLottery()
|
enterLottery()
|
||||||
currentStatus.value = LotteryStatus.init
|
currentStatus.value = LotteryStatus.init
|
||||||
}
|
}
|
||||||
@@ -590,6 +721,21 @@ export function useViewModel() {
|
|||||||
}
|
}
|
||||||
clearInterval(intervalTimer.value)
|
clearInterval(intervalTimer.value)
|
||||||
intervalTimer.value = null
|
intervalTimer.value = null
|
||||||
|
|
||||||
|
// 停止抽奖音乐
|
||||||
|
stopLotteryMusic()
|
||||||
|
|
||||||
|
// 清理所有音频资源
|
||||||
|
playingAudios.value.forEach(audio => {
|
||||||
|
if (!audio.ended && !audio.paused) {
|
||||||
|
audio.pause()
|
||||||
|
}
|
||||||
|
// 释放音频资源
|
||||||
|
audio.src = ''
|
||||||
|
audio.load()
|
||||||
|
})
|
||||||
|
playingAudios.value = []
|
||||||
|
|
||||||
if (scene.value) {
|
if (scene.value) {
|
||||||
scene.value.traverse((object: Object3D) => {
|
scene.value.traverse((object: Object3D) => {
|
||||||
if ((object as any).material) {
|
if ((object as any).material) {
|
||||||
|
|||||||
Reference in New Issue
Block a user