Commit aba1225d authored by 陈冲's avatar 陈冲

feat: 添加game1,game6大屏音乐及H5音效

parent 0638a2a7
import game1MusicUrl from '@/assets/images/game1.mp3' import game1MusicUrl from '@/assets/images/game1.mp3'
import game6Music1Url from '@/assets/images/game6_1.mp3'
import game6Music2Url from '@/assets/images/game6_2.mp3'
import game6Music3Url from '@/assets/images/game6_3.mp3'
import go321 from '@/assets/images/321go.mp3'
let backgroundMusic: HTMLAudioElement | null = null
function getBackgroundMusic() { const effectTemplates = new Map<string, HTMLAudioElement>()
if (!backgroundMusic) { const playingEffects = new Set<HTMLAudioElement>()
backgroundMusic = new Audio(game1MusicUrl) let pendingPlay = false
backgroundMusic.loop = true let pendingRetry: (() => void) | null = null
backgroundMusic.preload = 'auto'
backgroundMusic.volume = 0.6 function getEffectTemplate(music: string) {
backgroundMusic.load() let template = effectTemplates.get(music)
if (!template) {
template = new Audio(music)
template.loop = false
template.preload = 'auto'
template.volume = 0.6
template.load()
effectTemplates.set(music, template)
} }
return backgroundMusic return template
} }
export async function playGame1Music() { function releaseEffect(audio: HTMLAudioElement) {
const audio = getBackgroundMusic() audio.pause()
audio.removeAttribute('src')
audio.load()
playingEffects.delete(audio)
}
function clearPendingRetry() {
if (pendingRetry) {
window.removeEventListener('pointerdown', pendingRetry)
window.removeEventListener('keydown', pendingRetry)
pendingRetry = null
}
pendingPlay = false
}
function setPendingRetry(retry: () => void) {
clearPendingRetry()
pendingPlay = true
pendingRetry = retry
window.addEventListener('pointerdown', retry, { once: true })
window.addEventListener('keydown', retry, { once: true })
}
async function playEffect(music: string, retry: () => void) {
const audio = getEffectTemplate(music).cloneNode(true) as HTMLAudioElement
audio.loop = false
audio.volume = 0.6
playingEffects.add(audio)
const release = () => releaseEffect(audio)
audio.addEventListener('ended', release, { once: true })
audio.addEventListener('error', release, { once: true })
try { try {
await audio.play() await audio.play()
window.removeEventListener('pointerdown', playGame1Music) if (pendingRetry === retry) {
window.removeEventListener('keydown', playGame1Music) clearPendingRetry()
}
} catch { } catch {
window.addEventListener('pointerdown', playGame1Music, { once: true }) releaseEffect(audio)
window.addEventListener('keydown', playGame1Music, { once: true })
if (!pendingPlay) {
setPendingRetry(retry)
}
}
}
function stopEffects() {
clearPendingRetry()
for (const audio of playingEffects) {
releaseEffect(audio)
} }
playingEffects.clear()
}
export async function playGame1Music() {
await playEffect(game1MusicUrl, playGame1Music)
} }
export function stopGame1Music() { export function stopGame1Music() {
window.removeEventListener('pointerdown', playGame1Music) window.removeEventListener('pointerdown', playGame1Music)
window.removeEventListener('keydown', playGame1Music) window.removeEventListener('keydown', playGame1Music)
backgroundMusic?.pause() stopEffects()
}
export async function playCountdownMusic() {
await playEffect(go321, playCountdownMusic)
}
export function stopCountdownMusic() {
window.removeEventListener('pointerdown', playCountdownMusic)
window.removeEventListener('keydown', playCountdownMusic)
stopEffects()
}
/*
打地鼠击中爆炸6-1
打小白兔眩晕6-2
没打中6-3
*/
export async function playGame6Music(index: number) {
let arr: [string, string, string, string] = ['', game6Music1Url, game6Music2Url, game6Music3Url];
const music = arr[index]
if (!music) {
return
}
const retry = () => { playGame6Music(index) }
await playEffect(music, retry)
}
export function stopGame6Music() {
stopEffects()
} }
<script setup lang="ts"> <script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue' import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { playCountdownMusic, stopCountdownMusic } from '@/commons/music'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
background?: string background?: string
...@@ -74,6 +75,7 @@ onMounted(() => { ...@@ -74,6 +75,7 @@ onMounted(() => {
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
stopCountdown()
window.removeEventListener('resize', updateScale) window.removeEventListener('resize', updateScale)
window.visualViewport?.removeEventListener('resize', updateScale) window.visualViewport?.removeEventListener('resize', updateScale)
}) })
...@@ -106,6 +108,7 @@ const clearCountdown = () => { ...@@ -106,6 +108,7 @@ const clearCountdown = () => {
} }
const stopCountdown = () => { const stopCountdown = () => {
clearCountdown() clearCountdown()
stopCountdownMusic()
countdownVisible.value = false countdownVisible.value = false
gameCountdownVisible.value = false gameCountdownVisible.value = false
countdownResolve?.() countdownResolve?.()
...@@ -113,6 +116,7 @@ const stopCountdown = () => { ...@@ -113,6 +116,7 @@ const stopCountdown = () => {
} }
const startCountdown = (startSeconds = 3) => { const startCountdown = (startSeconds = 3) => {
stopCountdown() stopCountdown()
playCountdownMusic()
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
countdownResolve = resolve countdownResolve = resolve
......
...@@ -303,4 +303,4 @@ const showGameRuleHandler = () => { ...@@ -303,4 +303,4 @@ const showGameRuleHandler = () => {
transform: scale(0.8); transform: scale(0.8);
} }
} }
</style> </style>
\ No newline at end of file
...@@ -6,7 +6,7 @@ import { useGameSocket, joinSharedRoom, sendGameMessage, userJoinStatus } from ' ...@@ -6,7 +6,7 @@ import { useGameSocket, joinSharedRoom, sendGameMessage, userJoinStatus } from '
import LoadingView from './views/LoadingView.vue' import LoadingView from './views/LoadingView.vue'
import PlayingView from './views/PlayingView.vue' import PlayingView from './views/PlayingView.vue'
import { $getWechat } from '@/commons/utils.ts' import { $getWechat } from '@/commons/utils.ts'
import { playGame1Music } from '@/commons/music' import { playGame6Music, stopGame6Music } from '@/commons/music';
type GameView = 'loading' | 'playing' type GameView = 'loading' | 'playing'
type RankPlayer = { type RankPlayer = {
...@@ -181,7 +181,13 @@ const touchHandler = (scoreDelta: number) => { ...@@ -181,7 +181,13 @@ const touchHandler = (scoreDelta: number) => {
const nextTick = score.value + scoreDelta const nextTick = score.value + scoreDelta
score.value = nextTick score.value = nextTick
submitScore(false, nextTick) submitScore(false, nextTick)
playGame1Music(); if (scoreDelta == 5) {
playGame6Music(1);
} else if (scoreDelta == -3) {
playGame6Music(2);
} else {
playGame6Music(3);
}
} }
if (wechat) { if (wechat) {
...@@ -240,6 +246,7 @@ onMounted(() => { ...@@ -240,6 +246,7 @@ onMounted(() => {
onBeforeUnmount(() => { onBeforeUnmount(() => {
_offSocketMessage.value?.() _offSocketMessage.value?.()
stopGame6Music()
if (guFrameTimer) { if (guFrameTimer) {
window.clearTimeout(guFrameTimer) window.clearTimeout(guFrameTimer)
} }
......
...@@ -21,16 +21,7 @@ onMounted(() => { ...@@ -21,16 +21,7 @@ onMounted(() => {
<div class="img-logo"></div> <div class="img-logo"></div>
<div class="img-loadingbg1">游戏等待开始倒计时60秒</div> <div class="img-loadingbg1">游戏等待开始倒计时60秒</div>
<div class="img-loadingbg2">游戏即将开始 敬请期待</div> <div class="img-loadingbg2">游戏即将开始 敬请期待</div>
<div class="txt-bottom">您已成功加入游戏<br />等待主持人开始</div> <div class="txt-bottom" v-if="userJoinStatus">您已成功加入游戏<br />等待主持人开始</div>
<!-- <div class="img-title"></div> -->
<!-- <div class="img-avatar" :style="`background: url(${avatar});border-radius:66px;width:132px;height:132px;`"></div> -->
<!-- <div class="txt-nickname">{{ nickname }}</div>
<div class="txt-loading">
<label v-if="userJoinStatus">您已成功加入游戏等待主持人开始</label>
<label v-else>正在加入游戏...</label>
</div> -->
<!-- <div class="bg-bottom"></div> -->
<!-- <div class="loading-gu"></div> -->
</div> </div>
</template> </template>
......
...@@ -288,10 +288,10 @@ onBeforeUnmount(() => { ...@@ -288,10 +288,10 @@ onBeforeUnmount(() => {
width: 750px; width: 750px;
height: 600px; height: 600px;
row-gap: 70px; row-gap: 70px;
top: 560px; top: 560px;
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr);
place-items: center; place-items: center;
>div { >div {
......
<script setup lang="ts"> <!-- <script setup lang="ts">
import { $getWechat } from '@/commons/utils'; import { $getWechat } from '@/commons/utils';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
...@@ -46,4 +46,4 @@ onMounted(() => { ...@@ -46,4 +46,4 @@ onMounted(() => {
transform: translateX(-50%); transform: translateX(-50%);
} }
</style> </style> -->
import game1MusicUrl from '@/assets/images/game1.mp3' import game1MusicUrl from '@/assets/images/game1.mp3'
import game6MusicUrl from '@/assets/images/game6.mp3'
import go321 from '@/assets/images/321go.mp3'
let backgroundMusic: HTMLAudioElement | null = null let backgroundMusic: HTMLAudioElement | null = null
let countdownTemplate: HTMLAudioElement | null = null
let pendingCountdownRetry: (() => void) | null = null
const countdownAudios = new Set<HTMLAudioElement>()
function getBackgroundMusic() { function getBackgroundMusic(music: string) {
if (!backgroundMusic) { if (!backgroundMusic) {
backgroundMusic = new Audio(game1MusicUrl) backgroundMusic = new Audio(music)
backgroundMusic.loop = true backgroundMusic.loop = true
backgroundMusic.preload = 'auto' backgroundMusic.preload = 'auto'
backgroundMusic.volume = 0.6 backgroundMusic.volume = 0.6
...@@ -15,7 +20,7 @@ function getBackgroundMusic() { ...@@ -15,7 +20,7 @@ function getBackgroundMusic() {
} }
export async function playGame1Music() { export async function playGame1Music() {
const audio = getBackgroundMusic() const audio = getBackgroundMusic(game1MusicUrl)
try { try {
await audio.play() await audio.play()
...@@ -32,3 +37,80 @@ export function stopGame1Music() { ...@@ -32,3 +37,80 @@ export function stopGame1Music() {
window.removeEventListener('keydown', playGame1Music) window.removeEventListener('keydown', playGame1Music)
backgroundMusic?.pause() backgroundMusic?.pause()
} }
export async function playGame6Music() {
const audio = getBackgroundMusic(game6MusicUrl)
try {
await audio.play()
window.removeEventListener('pointerdown', playGame6Music)
window.removeEventListener('keydown', playGame6Music)
} catch {
window.addEventListener('pointerdown', playGame6Music, { once: true })
window.addEventListener('keydown', playGame6Music, { once: true })
}
}
export function stopGame6Music() {
window.removeEventListener('pointerdown', playGame6Music)
window.removeEventListener('keydown', playGame6Music)
backgroundMusic?.pause()
}
function getCountdownTemplate() {
if (!countdownTemplate) {
countdownTemplate = new Audio(go321)
countdownTemplate.loop = false
countdownTemplate.preload = 'auto'
countdownTemplate.volume = 0.8
countdownTemplate.load()
}
return countdownTemplate
}
function releaseCountdownAudio(audio: HTMLAudioElement) {
audio.pause()
audio.removeAttribute('src')
audio.load()
countdownAudios.delete(audio)
}
function clearCountdownRetry() {
if (!pendingCountdownRetry) return
window.removeEventListener('pointerdown', pendingCountdownRetry)
window.removeEventListener('keydown', pendingCountdownRetry)
pendingCountdownRetry = null
}
export async function playCountdownMusic() {
const audio = getCountdownTemplate().cloneNode(true) as HTMLAudioElement
audio.loop = false
audio.volume = 0.8
countdownAudios.add(audio)
const release = () => releaseCountdownAudio(audio)
audio.addEventListener('ended', release, { once: true })
audio.addEventListener('error', release, { once: true })
try {
await audio.play()
clearCountdownRetry()
} catch {
releaseCountdownAudio(audio)
if (pendingCountdownRetry) return
pendingCountdownRetry = () => {
pendingCountdownRetry = null
void playCountdownMusic()
}
window.addEventListener('pointerdown', pendingCountdownRetry, { once: true })
window.addEventListener('keydown', pendingCountdownRetry, { once: true })
}
}
export function stopCountdownMusic() {
clearCountdownRetry()
countdownAudios.forEach(releaseCountdownAudio)
}
<script setup lang="ts"> <script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue' import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { playCountdownMusic, stopCountdownMusic } from '@/commons/music'
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
width?: number width?: number
...@@ -45,6 +46,7 @@ const clearCountdown = () => { ...@@ -45,6 +46,7 @@ const clearCountdown = () => {
const stopCountdown = () => { const stopCountdown = () => {
clearCountdown() clearCountdown()
stopCountdownMusic()
countdownVisible.value = false countdownVisible.value = false
gameCountdownVisible.value = false gameCountdownVisible.value = false
countdownResolve?.() countdownResolve?.()
...@@ -53,6 +55,7 @@ const stopCountdown = () => { ...@@ -53,6 +55,7 @@ const stopCountdown = () => {
const startCountdown = (startSeconds = 3, gameSeconds = 60) => { const startCountdown = (startSeconds = 3, gameSeconds = 60) => {
stopCountdown() stopCountdown()
void playCountdownMusic()
return new Promise<void>((resolve) => { return new Promise<void>((resolve) => {
countdownResolve = resolve countdownResolve = resolve
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import { $save } from '@/commons/utils.ts'; import { $save } from '@/commons/utils.ts';
import { onMounted, ref } from 'vue' import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
// import { playGame1Music } from '@/commons/music'
const emit = defineEmits<{ const emit = defineEmits<{
loginSuccess: [] loginSuccess: []
...@@ -32,7 +31,6 @@ async function login() { ...@@ -32,7 +31,6 @@ async function login() {
} }
const loginHandler = async () => { const loginHandler = async () => {
// playGame1Music()
const { state, msg, data } = await login() const { state, msg, data } = await login()
if (state === 0) { if (state === 0) {
...@@ -46,7 +44,6 @@ const loginHandler = async () => { ...@@ -46,7 +44,6 @@ const loginHandler = async () => {
} }
onMounted(() => { onMounted(() => {
// playGame1Music()
}) })
</script> </script>
......
...@@ -3,7 +3,7 @@ import { cssAssetUrl } from '@/commons/assets.ts'; ...@@ -3,7 +3,7 @@ import { cssAssetUrl } from '@/commons/assets.ts';
import { $read } from '@/commons/utils'; import { $read } from '@/commons/utils';
import router from '@/router'; import router from '@/router';
import { ref } from 'vue'; import { ref } from 'vue';
import Login from './Login.vue'; import Login from '../components/Login.vue';
const imageUrls = { const imageUrls = {
bg1: cssAssetUrl('main-bg1.png'), bg1: cssAssetUrl('main-bg1.png'),
......
...@@ -6,7 +6,7 @@ import Rank1 from './views/Rank1View.vue' ...@@ -6,7 +6,7 @@ import Rank1 from './views/Rank1View.vue'
import Rank2 from './views/Rank2View.vue' import Rank2 from './views/Rank2View.vue'
import { useAdminGameSocket } from '@/composables/useAdminGameSocket' import { useAdminGameSocket } from '@/composables/useAdminGameSocket'
import type Player from '@/commons/player.ts' import type Player from '@/commons/player.ts'
import { playGame1Music } from '@/commons/music' import { playGame1Music, stopGame1Music } from '@/commons/music'
import { $remove_socket_storage } from '@/commons/utils.ts' import { $remove_socket_storage } from '@/commons/utils.ts'
const router = useRouter() const router = useRouter()
...@@ -156,7 +156,6 @@ const startGameWithMusic = () => { ...@@ -156,7 +156,6 @@ const startGameWithMusic = () => {
alert('房间中没有玩家') alert('房间中没有玩家')
return; return;
} }
playGame1Music()
startGame() startGame()
} }
...@@ -167,7 +166,6 @@ const nextRound = () => { ...@@ -167,7 +166,6 @@ const nextRound = () => {
} }
const nextRoundWithMusic = () => { const nextRoundWithMusic = () => {
playGame1Music()
nextRound() nextRound()
} }
...@@ -177,6 +175,7 @@ onMounted(() => { ...@@ -177,6 +175,7 @@ onMounted(() => {
}) })
onUnmounted(() => { onUnmounted(() => {
stopGame1Music()
window.removeEventListener('beforeunload', confirmRefresh) window.removeEventListener('beforeunload', confirmRefresh)
}) })
</script> </script>
......
...@@ -6,7 +6,7 @@ import Rank1 from './views/Rank1View.vue' ...@@ -6,7 +6,7 @@ import Rank1 from './views/Rank1View.vue'
import Rank2 from './views/Rank2View.vue' import Rank2 from './views/Rank2View.vue'
import { useAdminGameSocket } from '@/composables/useAdminGameSocket' import { useAdminGameSocket } from '@/composables/useAdminGameSocket'
import type Player from '@/commons/player.ts' import type Player from '@/commons/player.ts'
import { playGame1Music } from '@/commons/music' import { playGame6Music, stopGame6Music } from '@/commons/music'
import { $remove_socket_storage } from '@/commons/utils.ts' import { $remove_socket_storage } from '@/commons/utils.ts'
const router = useRouter() const router = useRouter()
...@@ -156,7 +156,6 @@ const startGameWithMusic = () => { ...@@ -156,7 +156,6 @@ const startGameWithMusic = () => {
alert('房间中没有玩家') alert('房间中没有玩家')
return; return;
} }
playGame1Music()
startGame() startGame()
} }
...@@ -167,16 +166,16 @@ const nextRound = () => { ...@@ -167,16 +166,16 @@ const nextRound = () => {
} }
const nextRoundWithMusic = () => { const nextRoundWithMusic = () => {
playGame1Music()
nextRound() nextRound()
} }
onMounted(() => { onMounted(() => {
window.addEventListener('beforeunload', confirmRefresh) window.addEventListener('beforeunload', confirmRefresh)
playGame1Music() playGame6Music()
}) })
onUnmounted(() => { onUnmounted(() => {
stopGame6Music();
window.removeEventListener('beforeunload', confirmRefresh) window.removeEventListener('beforeunload', confirmRefresh)
}) })
</script> </script>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment