Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
fc-minigame
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈冲
fc-minigame
Commits
ae0b0947
Commit
ae0b0947
authored
Jun 17, 2026
by
董政锦
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
h5-game 3和4游戏中声音问题;
parent
96495239
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
118 additions
and
7 deletions
+118
-7
music.ts
frontend-h5/src/commons/music.ts
+19
-0
PlayingView.vue
frontend-h5/src/pages/game3/views/PlayingView.vue
+8
-1
Game4.vue
frontend-h5/src/pages/game4/Game4.vue
+29
-4
PlayingView.vue
frontend-h5/src/pages/game4/views/PlayingView.vue
+45
-2
PlayingView.vue
frontend-h5/src/pages/game5/views/PlayingView.vue
+17
-0
No files found.
frontend-h5/src/commons/music.ts
View file @
ae0b0947
...
@@ -38,6 +38,25 @@ function getEffectTemplate(music: string) {
...
@@ -38,6 +38,25 @@ function getEffectTemplate(music: string) {
template
.
volume
=
1
template
.
volume
=
1
template
.
load
()
template
.
load
()
effectTemplates
.
set
(
music
,
template
)
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
return
template
...
...
frontend-h5/src/pages/game3/views/PlayingView.vue
View file @
ae0b0947
...
@@ -8,7 +8,7 @@ import {
...
@@ -8,7 +8,7 @@ import {
computed
,
computed
,
}
from
"vue"
;
}
from
"vue"
;
import
{
assetUrl
}
from
"@/commons/assets.ts"
;
import
{
assetUrl
}
from
"@/commons/assets.ts"
;
// import { playGame6
Music } from '@/commons/music'
import
{
playGame3
Music
}
from
'@/commons/music'
const
props
=
defineProps
<
{
const
props
=
defineProps
<
{
imageUrls
:
Record
<
string
,
string
>
;
imageUrls
:
Record
<
string
,
string
>
;
...
@@ -300,6 +300,13 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
...
@@ -300,6 +300,13 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const
isCoin
=
item
.
kind
===
"coin"
;
const
isCoin
=
item
.
kind
===
"coin"
;
const
delta
=
isCoin
?
5
:
-
3
;
const
delta
=
isCoin
?
5
:
-
3
;
// 播放音效:金币用 game3_1.mp3,炸弹用 game3_2.mp3
if
(
isCoin
)
{
playGame3Music
(
1
);
// 金币音效
}
else
{
playGame3Music
(
2
);
// 炸弹音效
}
if
(
isCoin
)
{
if
(
isCoin
)
{
emit
(
"scoreChange"
,
5
);
emit
(
"scoreChange"
,
5
);
}
else
{
}
else
{
...
...
frontend-h5/src/pages/game4/Game4.vue
View file @
ae0b0947
...
@@ -12,11 +12,15 @@ import {
...
@@ -12,11 +12,15 @@ import {
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
ScoreView
from
"./views/ScoreView.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"
;
const
gameId
=
"game4"
;
type
GameView
=
"loading"
|
"playing"
|
"score"
;
type
GameView
=
"loading"
|
"playing"
|
"score"
;
// 本地模式检测
const
isLocalMode
=
$is_run_local
();
console
.
log
(
'[Game4 H5] 本地模式:'
,
isLocalMode
);
const
imageUrls
=
{
const
imageUrls
=
{
bg
:
cssAssetUrl
(
"game4/h5-game4-bg.webp"
),
bg
:
cssAssetUrl
(
"game4/h5-game4-bg.webp"
),
bg2
:
cssAssetUrl
(
"game1/bg2.png"
),
bg2
:
cssAssetUrl
(
"game1/bg2.png"
),
...
@@ -194,13 +198,26 @@ const showGameRuleHandler = () => {
...
@@ -194,13 +198,26 @@ const showGameRuleHandler = () => {
showGameRule
.
value
=
!
showGameRule
.
value
;
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
({
const
{
offSocketMessage
}
=
useGameSocket
({
gameId
,
gameId
,
auth
:
{
auth
:
{
userid
:
wechat
.
token
,
userid
:
wechat
?.
token
||
'local-token'
,
},
},
onConnect
:
()
=>
{
onConnect
:
()
=>
{
if
(
isLocalMode
)
{
console
.
log
(
'[Game4 H5] 本地模式:跳过 WebSocket 连接'
);
return
;
}
window
.
setTimeout
(()
=>
{
window
.
setTimeout
(()
=>
{
const
joined
=
joinSharedRoom
(
const
joined
=
joinSharedRoom
(
nickname
.
value
,
nickname
.
value
,
...
@@ -253,6 +270,14 @@ onMounted(() => {
...
@@ -253,6 +270,14 @@ onMounted(() => {
if
(
token
.
value
)
{
if
(
token
.
value
)
{
window
.
addEventListener
(
"beforeunload"
,
confirmRefresh
);
window
.
addEventListener
(
"beforeunload"
,
confirmRefresh
);
}
}
// 本地模式:自动开始游戏
if
(
isLocalMode
)
{
console
.
log
(
'[Game4 H5] 本地模式:2秒后自动开始游戏'
);
setTimeout
(()
=>
{
startGameView
();
},
2000
);
}
});
});
onBeforeUnmount
(()
=>
{
onBeforeUnmount
(()
=>
{
...
@@ -265,7 +290,7 @@ onBeforeUnmount(() => {
...
@@ -265,7 +290,7 @@ onBeforeUnmount(() => {
</
script
>
</
script
>
<
template
>
<
template
>
<MobileStage
v-if=
"token"
:showGameRule=
"showGameRule"
ref=
"mobileStageRef"
:background=
"stageBackground"
>
<MobileStage
v-if=
"token
|| isLocalMode
"
:showGameRule=
"showGameRule"
ref=
"mobileStageRef"
:background=
"stageBackground"
>
<template
#
gameRule
>
<template
#
gameRule
>
<div
class=
"rule-container"
>
<div
class=
"rule-container"
>
<div
class=
"rule-txt-container"
>
<div
class=
"rule-txt-container"
>
...
...
frontend-h5/src/pages/game4/views/PlayingView.vue
View file @
ae0b0947
...
@@ -74,19 +74,56 @@ const requestMotionPermission = async (): Promise<boolean> => {
...
@@ -74,19 +74,56 @@ const requestMotionPermission = async (): Promise<boolean> => {
const
initAudio
=
async
()
=>
{
const
initAudio
=
async
()
=>
{
try
{
try
{
audioContext
=
new
(
window
.
AudioContext
||
(
window
as
any
).
webkitAudioContext
)()
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
response
=
await
fetch
(
shakeSound
)
const
arrayBuffer
=
await
response
.
arrayBuffer
()
const
arrayBuffer
=
await
response
.
arrayBuffer
()
shakeAudioBuffer
=
await
audioContext
.
decodeAudioData
(
arrayBuffer
)
shakeAudioBuffer
=
await
audioContext
.
decodeAudioData
(
arrayBuffer
)
console
.
log
(
'[摇一摇] 音频初始化成功,AudioContext state:'
,
audioContext
.
state
)
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'[摇一摇] 音频初始化失败:'
,
error
)
console
.
error
(
'[摇一摇] 音频初始化失败:'
,
error
)
}
}
}
}
const
playShakeSound
=
()
=>
{
const
playShakeSound
=
()
=>
{
if
(
!
audioContext
||
!
shakeAudioBuffer
)
return
if
(
!
audioContext
||
!
shakeAudioBuffer
)
{
console
.
warn
(
'[摇一摇] 音频未初始化,无法播放'
)
return
}
// 确保 AudioContext 处于运行状态
if
(
audioContext
.
state
===
'suspended'
)
{
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
()
const
source
=
audioContext
.
createBufferSource
()
source
.
buffer
=
shakeAudioBuffer
source
.
buffer
=
shakeAudioBuffer
source
.
connect
(
audioContext
.
destination
)
source
.
connect
(
audioContext
.
destination
)
...
@@ -181,6 +218,12 @@ onBeforeUnmount(() => {
...
@@ -181,6 +218,12 @@ onBeforeUnmount(() => {
// 点击马触发:iOS 先请求权限(不触发得分)
// 点击马触发:iOS 先请求权限(不触发得分)
const
onTapHorse
=
async
()
=>
{
const
onTapHorse
=
async
()
=>
{
// 激活 AudioContext(解决浏览器自动播放策略)
if
(
audioContext
&&
audioContext
.
state
===
'suspended'
)
{
await
audioContext
.
resume
()
console
.
log
(
'[摇一摇] 通过点击激活 AudioContext'
)
}
if
(
!
motionPermissionGranted
)
{
if
(
!
motionPermissionGranted
)
{
await
requestMotionPermission
()
await
requestMotionPermission
()
showIOSHint
.
value
=
false
showIOSHint
.
value
=
false
...
...
frontend-h5/src/pages/game5/views/PlayingView.vue
View file @
ae0b0947
...
@@ -116,6 +116,23 @@ let audioContext: AudioContext | null = null
...
@@ -116,6 +116,23 @@ let audioContext: AudioContext | null = null
function
getAudioContext
():
AudioContext
{
function
getAudioContext
():
AudioContext
{
if
(
!
audioContext
)
{
if
(
!
audioContext
)
{
audioContext
=
new
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'
)
{
if
(
audioContext
.
state
===
'suspended'
)
{
audioContext
.
resume
()
audioContext
.
resume
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment