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
b480ffa9
Commit
b480ffa9
authored
Jun 06, 2026
by
董政锦
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: game4 修复苹果手机加速度计需要交互点击触摸一下才开启功能;
parent
848c80fd
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
165 additions
and
8 deletions
+165
-8
Game4.vue
frontend-h5/src/pages/game4/Game4.vue
+3
-2
PlayingView.vue
frontend-h5/src/pages/game4/views/PlayingView.vue
+162
-6
No files found.
frontend-h5/src/pages/game4/Game4.vue
View file @
b480ffa9
...
...
@@ -166,7 +166,7 @@ function handleRoomBack() {
}
const
touchHandler
=
()
=>
{
tick
.
value
+=
1
tick
.
value
+=
5
submitScore
()
}
...
...
@@ -247,7 +247,8 @@ onBeforeUnmount(() => {
</
template
>
<LoadingView
v-if=
"currentView === 'loading'"
:image-urls=
"imageUrls"
:user-join-status=
"userJoinStatus"
@
touchGameRule=
"showGameRuleHandler"
/>
<PlayingView
v-else-if=
"currentView === 'playing'"
:image-urls=
"imageUrls"
:tick=
"tick"
:rank=
"rank"
<!-- <PlayingView v-else :image-urls="imageUrls" :tick="tick" :rank="rank" -->
<PlayingView
v-else-if=
"currentView === 'playing'"
:image-urls=
"imageUrls"
:tick=
"tick"
:rank=
"rank"
:currentHorse=
"currentHorse"
:currentYaoyiyao=
"currentYaoyiyao"
:countdown-interval=
"countdownInterval"
:is-div-desc-visible=
"isDivDescVisible"
@
touch=
"touchHandler"
/>
<ScoreView
v-else
:image-urls=
"imageUrls"
:tick=
"tick"
:level=
"level"
@
replay=
"replayGame"
...
...
frontend-h5/src/pages/game4/views/PlayingView.vue
View file @
b480ffa9
<
script
setup
lang=
"ts"
>
import
{
onBeforeUnmount
,
onMounted
}
from
'vue'
import
{
onBeforeUnmount
,
onMounted
,
ref
}
from
'vue'
import
shakeSound
from
'@/assets/images/game4/yaoyiyao.mp3'
const
props
=
defineProps
<
{
...
...
@@ -16,6 +16,10 @@ const emit = defineEmits<{
touch
:
[]
}
>
()
// ========== iOS 设备检测 ==========
const
isIOS
=
typeof
(
DeviceMotionEvent
as
any
).
requestPermission
===
'function'
const
showIOSHint
=
ref
(
isIOS
)
// ========== 摇一摇 ==========
const
shakeCooldown
=
300
let
lastShakeTime
=
0
...
...
@@ -33,6 +37,37 @@ let wasShaking = false
let
audioContext
:
AudioContext
|
null
=
null
let
shakeAudioBuffer
:
AudioBuffer
|
null
=
null
// iOS 13+/iPadOS 需要主动请求 DeviceMotion 权限
let
motionPermissionGranted
=
false
// 摇一摇图片抖动动画状态
const
isYaoyiyaoShaking
=
ref
(
false
)
let
yaoyiyaoShakeTimer
:
ReturnType
<
typeof
setTimeout
>
|
null
=
null
const
requestMotionPermission
=
async
():
Promise
<
boolean
>
=>
{
// 检查是否需要权限请求(iOS 12.2+)
if
(
typeof
(
DeviceMotionEvent
as
any
).
requestPermission
===
'function'
)
{
try
{
const
state
=
await
(
DeviceMotionEvent
as
any
).
requestPermission
()
if
(
state
===
'granted'
)
{
console
.
log
(
'[摇一摇] iOS DeviceMotion 权限已授予'
)
motionPermissionGranted
=
true
// 权限拿到后再注册监听
window
.
addEventListener
(
'devicemotion'
,
handleDeviceMotion
)
return
true
}
console
.
warn
(
'[摇一摇] iOS DeviceMotion 权限被拒绝:'
,
state
)
return
false
}
catch
(
err
)
{
console
.
error
(
'[摇一摇] iOS 权限请求失败:'
,
err
)
return
false
}
}
// Android / 旧版 iOS:无需额外权限
motionPermissionGranted
=
true
return
true
}
const
initAudio
=
async
()
=>
{
try
{
audioContext
=
new
(
window
.
AudioContext
||
(
window
as
any
).
webkitAudioContext
)()
...
...
@@ -82,6 +117,13 @@ const handleDeviceMotion = (ev: DeviceMotionEvent) => {
if
(
now
-
lastShakeTime
<
shakeCooldown
)
return
lastShakeTime
=
now
// 摇一摇图片抖动动画
isYaoyiyaoShaking
.
value
=
true
if
(
yaoyiyaoShakeTimer
)
clearTimeout
(
yaoyiyaoShakeTimer
)
yaoyiyaoShakeTimer
=
setTimeout
(()
=>
{
isYaoyiyaoShaking
.
value
=
false
},
320
)
playShakeSound
()
// 摇晃时打印日志:输出将要通过 websocket 提交的数据
...
...
@@ -105,8 +147,6 @@ const handleDeviceMotion = (ev: DeviceMotionEvent) => {
}
}
window
.
addEventListener
(
'devicemotion'
,
handleDeviceMotion
)
// ========== 生命周期 ==========
onMounted
(
async
()
=>
{
...
...
@@ -115,6 +155,15 @@ onMounted(async () => {
}
catch
(
error
)
{
console
.
error
(
'初始化失败:'
,
error
)
}
// 非 iOS 设备直接注册监听;iOS 需等用户点击后通过 requestMotionPermission 注册
if
(
typeof
(
DeviceMotionEvent
as
any
).
requestPermission
!==
'function'
)
{
window
.
addEventListener
(
'devicemotion'
,
handleDeviceMotion
)
motionPermissionGranted
=
true
console
.
log
(
'[摇一摇] DeviceMotion 监听已启动(Android/旧版iOS)'
)
}
else
{
console
.
log
(
'[摇一摇] 等待用户点击以请求 iOS DeviceMotion 权限…'
)
}
})
onBeforeUnmount
(()
=>
{
...
...
@@ -122,7 +171,20 @@ onBeforeUnmount(() => {
if
(
audioContext
)
{
audioContext
.
close
()
}
if
(
yaoyiyaoShakeTimer
)
{
clearTimeout
(
yaoyiyaoShakeTimer
)
}
})
// 点击马触发:iOS 先请求权限 + 触发射分
const
onTapHorse
=
async
()
=>
{
if
(
!
motionPermissionGranted
)
{
await
requestMotionPermission
()
// 权限请求完成(无论结果)隐藏 iOS 提示
showIOSHint
.
value
=
false
}
emit
(
'touch'
)
}
</
script
>
<
template
>
...
...
@@ -141,9 +203,19 @@ onBeforeUnmount(() => {
<div>
{{
tick
}}
</div>
<div>
当前排名:
第
<label>
{{
rank
}}
</label>
名
</div>
</div>
<!-- iOS 权限提示蒙层 -->
<Transition
name=
"ios-hint-fade"
>
<div
v-if=
"showIOSHint"
class=
"ios-hint-overlay"
@
click=
"onTapHorse"
>
<div
class=
"ios-hint-content"
>
<div
class=
"ios-hint-title"
>
👇点击下方赛马
</div>
<div
class=
"ios-hint-desc"
>
启用摇一摇功能开始游戏
</div>
<div
class=
"ios-hint-arrow"
>
⬇
</div>
</div>
</div>
</Transition>
<!--
<div
class=
"bg-bottom"
></div>
-->
<div
class=
"bg-yaoyiyao"
:style=
"
{ background: `${currentYaoyiyao} center/cover` }">
</div>
<div
class=
"play-horse"
:
style=
"
{ background: `${currentHorse} center/cover` }" @click="$emit('touch')
">
</div>
<div
class=
"bg-yaoyiyao"
:
class=
"
{ 'is-shaking': isYaoyiyaoShaking }" :
style="{ background: `${currentYaoyiyao} center/cover` }">
</div>
<div
class=
"play-horse"
:
class=
"
{ 'horse-clickable': showIOSHint }" :style="{ background: `${currentHorse} center/cover` }" @click="onTapHorse
">
</div>
</div>
</
template
>
...
...
@@ -297,14 +369,98 @@ onBeforeUnmount(() => {
width
:
514.51px
;
height
:
229px
;
transform
:
translateX
(
-50%
);
transition
:
transform
0.08s
ease-out
;
}
/* 摇一摇图片抖动动画 */
.bg-yaoyiyao.is-shaking
{
animation
:
yaoyiyao-shake
0.32s
ease-in-out
;
}
@keyframes
yaoyiyao-shake
{
0
%
{
transform
:
translateX
(
-50%
)
rotate
(
0deg
);
}
15
%
{
transform
:
translateX
(
-50%
)
rotate
(
-8deg
);
}
30
%
{
transform
:
translateX
(
-50%
)
rotate
(
8deg
);
}
45
%
{
transform
:
translateX
(
-50%
)
rotate
(
-6deg
);
}
60
%
{
transform
:
translateX
(
-50%
)
rotate
(
6deg
);
}
75
%
{
transform
:
translateX
(
-50%
)
rotate
(
-3deg
);
}
90
%
{
transform
:
translateX
(
-50%
)
rotate
(
3deg
);
}
100
%
{
transform
:
translateX
(
-50%
)
rotate
(
0deg
);
}
}
.play-horse
{
position
:
absolute
;
bottom
:
164px
;
left
:
50%
;
width
:
597px
;
height
:
679px
;
/* transform: translateX(-50%) scale(2.4); */
transform
:
translateX
(
-50%
);
}
/* 马匹点击引导动画 - 脉冲呼吸效果 */
.horse-clickable
{
animation
:
horse-pulse
1.2s
ease-in-out
infinite
;
}
@keyframes
horse-pulse
{
0
%,
100
%
{
filter
:
brightness
(
1
)
drop-shadow
(
0
0
8px
rgba
(
255
,
215
,
0
,
0
));
}
50
%
{
filter
:
brightness
(
1.12
)
drop-shadow
(
0
0
24px
rgba
(
255
,
215
,
0
,
0.6
));
}
}
/* ===== iOS 权限提示蒙层 ===== */
.ios-hint-overlay
{
position
:
absolute
;
top
:
0
;
bottom
:
0
;
left
:
var
(
--stage-viewport-left
,
0
);
width
:
var
(
--stage-viewport-width
,
750px
);
z-index
:
10
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
background
:
rgba
(
0
,
0
,
0
,
0.55
);
cursor
:
pointer
;
-webkit-tap-highlight-color
:
transparent
;
}
.ios-hint-content
{
text-align
:
center
;
color
:
#fff
;
animation
:
ios-hint-bounce
1.6s
ease-in-out
infinite
;
}
.ios-hint-title
{
font-size
:
36pt
;
font-weight
:
bold
;
margin-bottom
:
16px
;
text-shadow
:
0
2px
8px
rgba
(
0
,
0
,
0
,
0.5
);
}
.ios-hint-desc
{
font-size
:
22pt
;
opacity
:
0.85
;
margin-bottom
:
20px
;
text-shadow
:
0
1px
4px
rgba
(
0
,
0
,
0
,
0.5
);
}
.ios-hint-arrow
{
font-size
:
40pt
;
animation
:
ios-arrow-bounce
0.8s
ease-in-out
infinite
alternate
;
}
@keyframes
ios-hint-bounce
{
0
%,
100
%
{
transform
:
translateY
(
0
);
}
50
%
{
transform
:
translateY
(
-12px
);
}
}
@keyframes
ios-arrow-bounce
{
from
{
transform
:
translateY
(
0
);
opacity
:
1
;
}
to
{
transform
:
translateY
(
16px
);
opacity
:
0.3
;
}
}
.ios-hint-fade-enter-active
{
transition
:
opacity
0.4s
ease
;
}
.ios-hint-fade-leave-active
{
transition
:
opacity
0.3s
ease
;
}
.ios-hint-fade-enter-from
,
.ios-hint-fade-leave-to
{
opacity
:
0
;
}
</
style
>
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