Commit ae0b0947 authored by 董政锦's avatar 董政锦

h5-game 3和4游戏中声音问题;

parent 96495239
......@@ -38,6 +38,25 @@ function getEffectTemplate(music: string) {
template.volume = 1
template.load()
effectTemplates.set(music, template)
// 注册用户交互监听器,解决浏览器自动播放策略
const resumeAudio = async () => {
// 尝试播放一个静音的音频来激活 AudioContext
try {
const silentAudio = new Audio()
silentAudio.src = 'data:audio/mp3;base64,SUQzBAAAAAAAIgRTU0UAAAAPAAADTGF2ZjU3LjkyLjEzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//uQZAAAA'
await silentAudio.play()
silentAudio.pause()
console.log('[Music] 音频已通过用户交互激活')
} catch (e) {
console.log('[Music] 音频激活失败:', e)
}
window.removeEventListener('touchstart', resumeAudio)
window.removeEventListener('click', resumeAudio)
}
window.addEventListener('touchstart', resumeAudio, { once: true })
window.addEventListener('click', resumeAudio, { once: true })
}
return template
......
......@@ -8,7 +8,7 @@ import {
computed,
} from "vue";
import { assetUrl } from "@/commons/assets.ts";
// import { playGame6Music } from '@/commons/music'
import { playGame3Music } from '@/commons/music'
const props = defineProps<{
imageUrls: Record<string, string>;
......@@ -300,6 +300,13 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const isCoin = item.kind === "coin";
const delta = isCoin ? 5 : -3;
// 播放音效:金币用 game3_1.mp3,炸弹用 game3_2.mp3
if (isCoin) {
playGame3Music(1); // 金币音效
} else {
playGame3Music(2); // 炸弹音效
}
if (isCoin) {
emit("scoreChange", 5);
} else {
......
......@@ -12,11 +12,15 @@ import {
import LoadingView from "./views/LoadingView.vue";
import PlayingView from "./views/PlayingView.vue";
import ScoreView from "./views/ScoreView.vue";
import { $getWechat, $toast } from "@/commons/utils.ts";
import { $getWechat, $toast, $is_run_local } from "@/commons/utils.ts";
const gameId = "game4";
type GameView = "loading" | "playing" | "score";
// 本地模式检测
const isLocalMode = $is_run_local();
console.log('[Game4 H5] 本地模式:', isLocalMode);
const imageUrls = {
bg: cssAssetUrl("game4/h5-game4-bg.webp"),
bg2: cssAssetUrl("game1/bg2.png"),
......@@ -194,13 +198,26 @@ const showGameRuleHandler = () => {
showGameRule.value = !showGameRule.value;
};
if (wechat) {
if (wechat || isLocalMode) {
if (isLocalMode) {
// 本地模式:模拟用户数据
console.log('[Game4 H5] 本地模式启动,模拟用户数据');
token.value = 'local-token';
nickname.value = '本地测试玩家';
avatar.value = 'https://api.dicebear.com/9.x/fun-emoji/svg?seed=local';
userJoinStatus.value = true;
}
const { offSocketMessage } = useGameSocket({
gameId,
auth: {
userid: wechat.token,
userid: wechat?.token || 'local-token',
},
onConnect: () => {
if (isLocalMode) {
console.log('[Game4 H5] 本地模式:跳过 WebSocket 连接');
return;
}
window.setTimeout(() => {
const joined = joinSharedRoom(
nickname.value,
......@@ -253,6 +270,14 @@ onMounted(() => {
if (token.value) {
window.addEventListener("beforeunload", confirmRefresh);
}
// 本地模式:自动开始游戏
if (isLocalMode) {
console.log('[Game4 H5] 本地模式:2秒后自动开始游戏');
setTimeout(() => {
startGameView();
}, 2000);
}
});
onBeforeUnmount(() => {
......@@ -265,7 +290,7 @@ onBeforeUnmount(() => {
</script>
<template>
<MobileStage v-if="token" :showGameRule="showGameRule" ref="mobileStageRef" :background="stageBackground">
<MobileStage v-if="token || isLocalMode" :showGameRule="showGameRule" ref="mobileStageRef" :background="stageBackground">
<template #gameRule>
<div class="rule-container">
<div class="rule-txt-container">
......
......@@ -74,19 +74,56 @@ const requestMotionPermission = async (): Promise<boolean> => {
const initAudio = async () => {
try {
audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
// 如果 AudioContext 处于 suspended 状态,注册一次性交互监听器来激活
if (audioContext.state === 'suspended') {
console.log('[摇一摇] AudioContext 处于 suspended 状态,注册交互监听器')
const resumeAudio = async () => {
if (audioContext && audioContext.state === 'suspended') {
await audioContext.resume()
console.log('[摇一摇] AudioContext 已通过用户交互激活')
}
// 移除监听器
window.removeEventListener('touchstart', resumeAudio)
window.removeEventListener('click', resumeAudio)
}
window.addEventListener('touchstart', resumeAudio, { once: true })
window.addEventListener('click', resumeAudio, { once: true })
}
const response = await fetch(shakeSound)
const arrayBuffer = await response.arrayBuffer()
shakeAudioBuffer = await audioContext.decodeAudioData(arrayBuffer)
console.log('[摇一摇] 音频初始化成功,AudioContext state:', audioContext.state)
} catch (error) {
console.error('[摇一摇] 音频初始化失败:', error)
}
}
const playShakeSound = () => {
if (!audioContext || !shakeAudioBuffer) return
if (!audioContext || !shakeAudioBuffer) {
console.warn('[摇一摇] 音频未初始化,无法播放')
return
}
// 确保 AudioContext 处于运行状态
if (audioContext.state === 'suspended') {
audioContext.resume()
audioContext.resume().then(() => {
console.log('[摇一摇] AudioContext 已恢复')
playShakeSoundInternal()
}).catch(err => {
console.error('[摇一摇] AudioContext 恢复失败:', err)
})
} else {
playShakeSoundInternal()
}
}
const playShakeSoundInternal = () => {
if (!audioContext || !shakeAudioBuffer) return
const source = audioContext.createBufferSource()
source.buffer = shakeAudioBuffer
source.connect(audioContext.destination)
......@@ -181,6 +218,12 @@ onBeforeUnmount(() => {
// 点击马触发:iOS 先请求权限(不触发得分)
const onTapHorse = async () => {
// 激活 AudioContext(解决浏览器自动播放策略)
if (audioContext && audioContext.state === 'suspended') {
await audioContext.resume()
console.log('[摇一摇] 通过点击激活 AudioContext')
}
if (!motionPermissionGranted) {
await requestMotionPermission()
showIOSHint.value = false
......
......@@ -116,6 +116,23 @@ let audioContext: AudioContext | null = null
function getAudioContext(): AudioContext {
if (!audioContext) {
audioContext = new AudioContext()
// 如果 AudioContext 处于 suspended 状态,注册一次性交互监听器来激活
if (audioContext.state === 'suspended') {
console.log('[Audio] AudioContext 处于 suspended 状态,注册交互监听器')
const resumeAudio = async () => {
if (audioContext && audioContext.state === 'suspended') {
await audioContext.resume()
console.log('[Audio] AudioContext 已通过用户交互激活')
}
window.removeEventListener('touchstart', resumeAudio)
window.removeEventListener('click', resumeAudio)
}
window.addEventListener('touchstart', resumeAudio, { once: true })
window.addEventListener('click', resumeAudio, { once: true })
}
}
if (audioContext.state === 'suspended') {
audioContext.resume()
......
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