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
94cab0cd
Commit
94cab0cd
authored
Jun 28, 2026
by
陈冲
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: 添加了提交分数5秒提示倒计时
parent
02b57a26
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1210 additions
and
153 deletions
+1210
-153
socket_io.rs
backend/src/protocols/socket_io.rs
+16
-8
utils.ts
frontend-h5/src/commons/utils.ts
+14
-0
useGameSocket.ts
frontend-h5/src/composables/useGameSocket.ts
+49
-5
Game.vue
frontend-h5/src/pages/game1/Game.vue
+76
-17
Game.vue
frontend-h5/src/pages/game2/Game.vue
+86
-16
PlayingView.vue
frontend-h5/src/pages/game2/views/PlayingView.vue
+4
-0
Game3.vue
frontend-h5/src/pages/game3/Game3.vue
+93
-21
Game4.vue
frontend-h5/src/pages/game4/Game4.vue
+60
-14
Game5.vue
frontend-h5/src/pages/game5/Game5.vue
+80
-17
Game.vue
frontend-h5/src/pages/game6/Game.vue
+87
-17
useAdminGameSocket.ts
frontend-large/src/composables/useAdminGameSocket.ts
+19
-2
Game.vue
frontend-large/src/pages/game1/Game.vue
+102
-4
Game.vue
frontend-large/src/pages/game2/Game.vue
+102
-4
Game3.vue
frontend-large/src/pages/game3/Game3.vue
+105
-6
Game4.vue
frontend-large/src/pages/game4/Game4.vue
+102
-3
Game5.vue
frontend-large/src/pages/game5/Game5.vue
+107
-9
Game.vue
frontend-large/src/pages/game6/Game.vue
+108
-10
No files found.
backend/src/protocols/socket_io.rs
View file @
94cab0cd
...
...
@@ -36,7 +36,7 @@ const ROOM_ENTRY_LIMIT: usize = 20;
///游戏结束排序最大用户数
const
ROOM_SCORE_RANK_LIMIT
:
usize
=
10
;
const
GAME_START_COUNTDOWN_SECS
:
u64
=
3
;
const
GAME_RESULT_WAIT_SECS
:
u64
=
2
;
const
GAME_RESULT_WAIT_SECS
:
u64
=
5
;
const
GAME_RUNNING_SECS
:
u64
=
60
;
//管理员退出5分钟后,关闭所有玩家的连接
const
ADMIN_ABSENT_DEACTIVATE_PLAYER_SECS
:
u64
=
5
*
60
;
...
...
@@ -1031,11 +1031,6 @@ async fn handle_room_command(
if
game
.insert
()
.await
{
if
!
already_top_ranked
&&
(
1
..=
ROOM_SCORE_RANK_LIMIT
as
i64
)
.contains
(
&
rank
)
{
CLIENT_TOP_RANKED_MAP
.insert
(
userid
.to_string
(),
true
);
if
let
Ok
(
mut
state
)
=
ROOM_STATE
.lock
()
{
if
let
Some
(
player
)
=
state
.players
.get_mut
(
userid
)
{
player
.already_top_ranked
=
true
;
}
}
}
let
mut
payload
=
json!
({
...
...
@@ -1077,19 +1072,32 @@ async fn handle_room_command(
}
}
// 获取房间状态
"room_state"
=>
{
"room_state"
|
"status"
=>
{
if
let
Ok
(
state
)
=
ROOM_STATE
.lock
()
{
let
gameId
=
state
.current_game_id
.clone
()
.unwrap_or_default
();
let
count
=
state
.players
.len
();
let
ranking
=
state
.current_ranking_payload
();
let
status
=
state
.status
as
i32
;
let
player_rank
=
if
is_admin
{
Value
::
Null
}
else
{
state
.player_rank
(
userid
)
.map_or
(
Value
::
Null
,
|
rank
|
json!
(
rank
))
};
let
player_score
=
if
is_admin
{
Value
::
Null
}
else
{
state
.players
.get
(
userid
)
.map_or
(
Value
::
Null
,
|
player
|
json!
(
player
.score
))
};
// let snapshot = state.snapshot();
drop
(
state
);
emit_msgpack
(
&
socket
,
evt
,
&
ok_resp
(
Some
(
json!
({
"status"
:
status
,
"list"
:
ranking
,
"count"
:
count
,
"gameId"
:
gameId
,}),
json!
({
"status"
:
status
,
"list"
:
ranking
,
"count"
:
count
,
"gameId"
:
gameId
,
"rank"
:
player_rank
,
"score"
:
player_score
,
}),
)),
);
}
...
...
frontend-h5/src/commons/utils.ts
View file @
94cab0cd
...
...
@@ -66,6 +66,20 @@ export function $format_str(str: string, num: number) {
let
toastElement
:
HTMLDivElement
|
undefined
;
let
toastTimer
:
ReturnType
<
typeof
window
.
setTimeout
>
|
undefined
;
export
function
$hideToast
()
{
if
(
toastTimer
)
{
window
.
clearTimeout
(
toastTimer
);
toastTimer
=
undefined
;
}
if
(
!
toastElement
)
{
return
;
}
toastElement
.
style
.
opacity
=
'0'
;
toastElement
.
style
.
transform
=
'translate(-50%, -40%)'
;
}
export
function
$toast
(
message
?:
string
,
duration
=
2000
)
{
if
(
!
message
)
{
return
;
...
...
frontend-h5/src/composables/useGameSocket.ts
View file @
94cab0cd
...
...
@@ -2,7 +2,7 @@ import { ref } from 'vue'
import
{
useRouter
}
from
'vue-router'
import
type
{
Socket
}
from
'socket.io-client'
import
{
initSocket
,
onSocketMessage
,
sendSocketMessage
}
from
'@/commons/ws'
import
{
$getWechat
,
$read
,
$save
,
$toast
,
postScreenGameScore
}
from
'@/commons/utils'
import
{
$getWechat
,
$
hideToast
,
$
read
,
$save
,
$toast
,
postScreenGameScore
}
from
'@/commons/utils'
type
SocketPayload
=
{
msg
?:
string
...
...
@@ -26,6 +26,7 @@ type GameSocketOptions = {
onRescoreSubmitted
?:
(
recount
:
number
)
=>
void
onRoomClosed
?:
(
data
:
any
)
=>
void
onGameRecover
?:
(
data
:
any
)
=>
void
onStatus
?:
(
data
:
any
)
=>
void
onEvent
?:
(
evt
:
string
,
payload
:
SocketPayload
)
=>
void
onRoomBack
?:
(
data
:
any
)
=>
void
}
...
...
@@ -52,28 +53,59 @@ export function joinSharedRoom(nickname: string, token: string, avatar: string,
return
sendSocketMessage
(
'room_join'
,
{
nickname
:
nickname
,
token
,
avatar
,
gameId
:
gameId
})
}
const
networkDisconnectToastDuration
=
30
*
60
*
1000
;
export
function
sendGameMessage
(
cmd
:
string
,
data
:
any
=
{})
{
return
sendSocketMessage
(
cmd
,
data
)
const
sent
=
sendSocketMessage
(
cmd
,
data
)
if
(
!
sent
)
{
$toast
(
'网络不好,分数无法提交'
,
networkDisconnectToastDuration
)
}
return
sent
}
export
function
requestGameStatus
()
{
return
sendSocketMessage
(
'status'
)
}
export
const
userJoinStatus
=
ref
(
false
)
export
const
userTop10RankStatus
=
ref
(
false
)
export
const
isGameSocketConnected
=
ref
(
false
)
export
function
useGameSocket
(
options
:
GameSocketOptions
)
{
const
router
=
useRouter
()
let
socket
:
Socket
|
null
=
null
let
offSocketMessage
:
(()
=>
void
)
|
undefined
let
statusTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
domain
=
$read
(
'domain'
,
''
);
let
resubmitcount
=
0
;
const
stopStatusPolling
=
()
=>
{
if
(
statusTimer
)
{
window
.
clearInterval
(
statusTimer
)
statusTimer
=
undefined
}
}
const
startStatusPolling
=
()
=>
{
stopStatusPolling
()
requestGameStatus
()
statusTimer
=
window
.
setInterval
(
requestGameStatus
,
1000
)
}
socket
=
initSocket
({
socket_path
:
'/socket.io'
,
client_ns
:
`
${
domain
}
/ws`
,
auth
:
options
.
auth
,
onConnect
:
(
socket
)
=>
{
isGameSocketConnected
.
value
=
true
;
$hideToast
();
startStatusPolling
();
options
.
onConnect
?.();
},
onDisconnect
:
(
_reason
:
string
)
=>
{
// $toast('网络中断,尝试重新连接...')
isGameSocketConnected
.
value
=
false
;
stopStatusPolling
();
$toast
(
'网络连接已断开,请检查网络后重新进入游戏'
,
networkDisconnectToastDuration
)
socket
=
null
;
},
onError
:
(
error
:
any
)
=>
{
...
...
@@ -136,6 +168,7 @@ export function useGameSocket(options: GameSocketOptions) {
//是否上过前十榜
userTop10RankStatus
.
value
=
data
.
alreadyTopRanked
$toast
(
'您已进入游戏房间'
)
userTop10RankStatus
.
value
=
data
.
alreadyTopRanked
userJoinStatus
.
value
=
true
break
}
...
...
@@ -148,6 +181,7 @@ export function useGameSocket(options: GameSocketOptions) {
let
{
rank
,
remainingSeconds
,
score
}
=
data
;
//返回的时间可能会慢一秒
options
.
onGameRecover
?.({
rank
,
remainingSeconds
,
score
});
options
.
onGameRecover
?.({
rank
,
remainingSeconds
,
score
});
break
}
case
'game_start_result'
:
{
...
...
@@ -162,7 +196,6 @@ export function useGameSocket(options: GameSocketOptions) {
break
}
case
'submit_score_save_result'
:
{
//if (!userTop10RankStatus) {//保证每一轮玩家数据完整性, 暂时不需要这个条件
const
submittedScore
=
options
.
onScoreSubmitted
?.(
true
,
data
)
const
token_origin
=
$getWechat
()?.
token_origin
if
(
token_origin
&&
submittedScore
&&
Number
.
isFinite
(
submittedScore
.
score
))
{
...
...
@@ -174,7 +207,13 @@ export function useGameSocket(options: GameSocketOptions) {
rank_no
:
submittedScore
.
rank_no
,
})
}
//}
break
}
case
'status_result'
:
{
if
(
data
?.
gameId
&&
data
.
gameId
!==
options
.
gameId
)
{
return
}
options
.
onStatus
?.(
data
)
break
}
case
'room_back_result'
:
{
...
...
@@ -189,6 +228,7 @@ export function useGameSocket(options: GameSocketOptions) {
case
'room_rank_result'
:
{
//如果是游戏开始中再进入会收到这个排行榜消息
options
.
onShowRank
?.(
data
);
options
.
onShowRank
?.(
data
);
return
;
}
default
:
{
...
...
@@ -207,6 +247,10 @@ export function useGameSocket(options: GameSocketOptions) {
socket
,
userJoinStatus
,
userTop10RankStatus
,
offSocketMessage
requestGameStatus
,
offSocketMessage
:
()
=>
{
stopStatusPolling
()
offSocketMessage
?.()
}
}
}
frontend-h5/src/pages/game1/Game.vue
View file @
94cab0cd
...
...
@@ -34,6 +34,8 @@ const countdownInterval = ref(60)
const
isDivDescVisible
=
ref
(
false
)
const
tick
=
ref
(
0
)
//点击次数
const
rank
=
ref
(
0
)
//排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
currentGuFrame
=
ref
(
0
)
const
isGuPlaying
=
ref
(
false
)
const
token
=
ref
(
wechat
?.
token
??
''
)
...
...
@@ -51,6 +53,47 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
''
}
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
'object'
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
const
nextRank
=
Number
(
value
)
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showScoreView
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
tick
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
}
...
...
@@ -62,21 +105,27 @@ function stopGameCountdown() {
}
}
function
submitScore
(
save
:
boolean
=
false
)
{
function
submitScore
(
save
:
boolean
=
false
,
currentTick
=
tick
.
value
)
{
//最后提交保存在数据库中
if
(
save
)
{
//item_num 游戏项目(1到6)
//wechat 原始token
sendGameMessage
(
'submit_score_save'
,
{
score
:
tick
.
value
,
const
sent
=
sendGameMessage
(
'submit_score_save'
,
{
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
1
,
nickname
:
wechat
.
nickname
,
avatar
:
wechat
.
avatar
,
rank
:
rank
.
value
,
})
if
(
sent
&&
!
userTop10RankStatus
.
value
)
{
window
.
setTimeout
(()
=>
{
$toast
(
'成绩提交中,请稍候...'
,
5000
)
},
0
)
}
return
sent
}
else
{
sendGameMessage
(
'submit_score'
,
{
score
:
tick
.
value
})
return
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
}
}
...
...
@@ -92,9 +141,11 @@ function startGameCountdown(seconds = 60) {
countdownInterval
.
value
=
0
gameCountdownTimer
=
undefined
setDivDescVisible
(
false
)
hasFinalScoreResult
.
value
=
false
submitScore
(
true
)
if
(
!
userTop10RankStatus
.
value
)
{
$toast
(
'成绩提交中,请稍候...'
,
2000
)
if
(
userTop10RankStatus
.
value
)
{
userJoinStatus
.
value
=
false
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
}
return
}
...
...
@@ -125,6 +176,8 @@ function resetToLoadingView() {
}
tick
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
countdownInterval
.
value
=
60
currentGuFrame
.
value
=
0
isGuPlaying
.
value
=
false
...
...
@@ -137,6 +190,8 @@ function startGameView() {
stopGameCountdown
()
tick
.
value
=
0
currentGuFrame
.
value
=
0
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
...
...
@@ -159,8 +214,9 @@ const touchHandler = () => {
return
}
tick
.
value
+=
5
submitScore
()
const
nextTick
=
tick
.
value
+
5
if
(
!
submitScore
(
false
,
nextTick
))
return
tick
.
value
=
nextTick
playGame1Music
();
isGuPlaying
.
value
=
true
...
...
@@ -208,39 +264,42 @@ if (wechat) {
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
if
(
!
is_save
)
{
//非保存状态下
const
nextScore
=
Number
(
typeof
data
===
'object'
?
data
?.
score
:
NaN
)
const
nextRank
=
Number
(
typeof
data
===
'object'
?
data
?.
rank
:
data
)
const
nextRank
=
getServerRank
(
data
)
const
remainingSeconds
=
Number
(
typeof
data
===
'object'
?
data
?.
remainingSeconds
:
NaN
)
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
tick
.
value
=
nextScore
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
remainingSeconds
)
&&
remainingSeconds
>=
0
)
{
syncGameCountdown
(
remainingSeconds
)
}
}
else
if
(
typeof
data
===
'object'
&&
data
)
{
const
nextRank
=
Number
(
data
.
rank
)
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
const
nextRank
=
getServerRank
(
data
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
showScoreView
()
markFinalScoreResult
()
}
return
{
code
:
'JGQF'
,
score
:
tick
.
value
,
rank_no
:
rank
.
value
}
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
;
submitScore
(
true
)
},
onGameRecover
:
(
data
)
=>
{
const
recoveredRank
=
Number
(
data
?.
rank
)
const
recoveredRank
=
getServerRank
(
data
)
const
recoveredScore
=
Number
(
data
?.
score
)
const
recoveredSeconds
=
Number
(
data
?.
remainingSeconds
)
rank
.
value
=
Number
.
isFinite
(
recoveredRank
)
&&
recoveredRank
>
0
?
recoveredRank
:
0
rank
.
value
=
recoveredRank
tick
.
value
=
Number
.
isFinite
(
recoveredScore
)
&&
recoveredScore
>
0
?
recoveredScore
:
0
showGameRule
.
value
=
false
// showGameRank.value = false
currentView
.
value
=
'playing'
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
(
Number
.
isFinite
(
recoveredSeconds
)
&&
recoveredSeconds
>
0
?
recoveredSeconds
:
0
,
)
...
...
frontend-h5/src/pages/game2/Game.vue
View file @
94cab0cd
...
...
@@ -37,6 +37,8 @@ const countdownInterval = ref(60)
const
isDivDescVisible
=
ref
(
false
)
const
score
=
ref
(
0
)
const
rank
=
ref
(
0
)
//排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
rankList
=
ref
<
RankPlayer
[]
>
([])
const
displayRankList
=
computed
<
RankPlayer
[]
>
(()
=>
{
const
list
=
rankList
.
value
.
slice
(
0
,
10
)
...
...
@@ -76,6 +78,56 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
''
}
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
'object'
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
const
nextRank
=
Number
(
value
)
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showGameOverRank
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
if
(
Array
.
isArray
(
data
?.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
}
...
...
@@ -92,7 +144,7 @@ function submitScore(save: boolean = false, currentTick = score.value) {
if
(
save
)
{
//item_num 游戏项目(1到6)
//wechat 原始token
sendGameMessage
(
'submit_score_save'
,
{
const
sent
=
sendGameMessage
(
'submit_score_save'
,
{
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
2
,
...
...
@@ -100,8 +152,14 @@ function submitScore(save: boolean = false, currentTick = score.value) {
avatar
:
wechat
.
avatar
,
rank
:
rank
.
value
,
})
if
(
sent
&&
!
userTop10RankStatus
.
value
)
{
window
.
setTimeout
(()
=>
{
$toast
(
'成绩提交中,请稍候...'
,
5000
)
},
0
)
}
return
sent
}
else
{
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
return
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
}
}
...
...
@@ -118,6 +176,7 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer
=
undefined
currentView
.
value
=
'loading'
setDivDescVisible
(
false
)
hasFinalScoreResult
.
value
=
false
submitScore
(
true
)
if
(
userTop10RankStatus
.
value
)
{
userJoinStatus
.
value
=
false
;
...
...
@@ -125,7 +184,7 @@ function startGameCountdown(seconds = 60) {
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
//这里还要再发
}
else
{
$toast
(
'成绩提交中,请稍候...'
,
2
000
)
$toast
(
'成绩提交中,请稍候...'
,
5
000
)
}
return
}
...
...
@@ -156,7 +215,11 @@ function resetToLoadingView() {
}
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
countdownInterval
.
value
=
60
// currentGu.value = guFrames[0]
isGuPlaying
.
value
=
false
...
...
@@ -170,9 +233,15 @@ function startGameView() {
stopGameCountdown
()
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
// currentGu.value = guFrames[0]
showGameRank
.
value
=
false
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
...
...
@@ -186,9 +255,9 @@ function showGameOverRank() {
}
const
touchHandler
=
(
currentScore
:
number
)
=>
{
if
(
!
submitScore
(
false
,
currentScore
))
return
score
.
value
=
currentScore
playGame2Music
();
submitScore
(
false
,
currentScore
)
}
if
(
wechat
)
{
...
...
@@ -217,12 +286,12 @@ if (wechat) {
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
if
(
!
is_save
)
{
//非保存状态下
const
nextScore
=
Number
(
typeof
data
===
'object'
?
data
?.
score
:
NaN
)
const
nextRank
=
Number
(
typeof
data
===
'object'
?
data
?.
rank
:
data
)
const
nextRank
=
getServerRank
(
data
)
const
remainingSeconds
=
Number
(
typeof
data
===
'object'
?
data
?.
remainingSeconds
:
NaN
)
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
remainingSeconds
)
&&
remainingSeconds
>=
0
)
{
...
...
@@ -231,36 +300,37 @@ if (wechat) {
}
else
if
(
typeof
data
===
'object'
&&
data
)
{
if
(
Array
.
isArray
(
data
.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
Number
(
item
?.
rank
??
index
+
1
),
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
Number
(
data
.
rank
)
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
const
nextRank
=
getServerRank
(
data
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
!
userTop10RankStatus
.
value
)
{
showGameOverRank
()
}
markFinalScoreResult
()
}
return
{
code
:
'JBJF'
,
score
:
score
.
value
,
rank_no
:
rank
.
value
}
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
;
submitScore
(
true
)
},
onGameRecover
:
(
data
)
=>
{
const
recoveredRank
=
Number
(
data
?.
rank
)
const
recoveredRank
=
getServerRank
(
data
)
const
recoveredScore
=
Number
(
data
?.
score
)
const
recoveredSeconds
=
Number
(
data
?.
remainingSeconds
)
rank
.
value
=
Number
.
isFinite
(
recoveredRank
)
&&
recoveredRank
>
0
?
recoveredRank
:
0
rank
.
value
=
recoveredRank
score
.
value
=
Number
.
isFinite
(
recoveredScore
)
&&
recoveredScore
>
0
?
recoveredScore
:
0
showGameRule
.
value
=
false
// showGameRank.value = false
currentView
.
value
=
'playing'
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
(
Number
.
isFinite
(
recoveredSeconds
)
&&
recoveredSeconds
>
0
?
recoveredSeconds
:
0
,
)
...
...
frontend-h5/src/pages/game2/views/PlayingView.vue
View file @
94cab0cd
<
script
setup
lang=
"ts"
>
import
{
onBeforeUnmount
,
ref
}
from
'vue'
;
import
{
isGameSocketConnected
}
from
'@/composables/useGameSocket'
;
defineProps
<
{
imageUrls
:
Record
<
string
,
string
>
...
...
@@ -74,6 +75,9 @@ function rotateCoin(event: PointerEvent) {
while
(
clockwiseAngle
>=
FULL_ROTATION
)
{
clockwiseAngle
-=
FULL_ROTATION
if
(
!
isGameSocketConnected
.
value
)
{
return
}
score
.
value
+=
5
emit
(
'touch'
,
score
.
value
)
}
...
...
frontend-h5/src/pages/game3/Game3.vue
View file @
94cab0cd
...
...
@@ -48,6 +48,8 @@ const countdownInterval = ref(60)
const
isDivDescVisible
=
ref
(
false
)
const
score
=
ref
(
0
)
const
rank
=
ref
(
0
)
//排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
rankList
=
ref
<
RankPlayer
[]
>
([])
const
displayRankList
=
computed
<
RankPlayer
[]
>
(()
=>
{
const
list
=
rankList
.
value
.
slice
(
0
,
10
)
...
...
@@ -88,6 +90,56 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
''
}
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
'object'
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
const
nextRank
=
Number
(
value
)
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showGameOverRank
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
if
(
Array
.
isArray
(
data
?.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
}
...
...
@@ -100,13 +152,13 @@ function stopGameCountdown() {
}
function
submitScore
(
save
:
boolean
=
false
,
currentTick
=
score
.
value
)
{
if
(
!
wechat
&&
!
isLocalMode
)
return
if
(
!
wechat
&&
!
isLocalMode
)
return
false
if
(
save
)
{
if
(
isLocalMode
&&
!
wechat
)
{
console
.
log
(
'[game3 本地模式] 提交最终分数:'
,
currentTick
)
return
return
true
}
sendGameMessage
(
'submit_score_save'
,
{
const
sent
=
sendGameMessage
(
'submit_score_save'
,
{
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
3
,
...
...
@@ -114,12 +166,18 @@ function submitScore(save: boolean = false, currentTick = score.value) {
avatar
:
wechat
.
avatar
,
rank
:
rank
.
value
,
})
if
(
sent
&&
!
userTop10RankStatus
.
value
)
{
window
.
setTimeout
(()
=>
{
$toast
(
'成绩提交中,请稍候...'
,
5000
)
},
0
)
}
return
sent
}
else
{
if
(
isLocalMode
&&
!
wechat
)
{
console
.
log
(
'[game3 本地模式] 实时分数:'
,
currentTick
)
return
return
true
}
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
return
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
}
}
...
...
@@ -136,13 +194,14 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer
=
undefined
currentView
.
value
=
'loading'
setDivDescVisible
(
false
)
hasFinalScoreResult
.
value
=
false
submitScore
(
true
)
if
(
userTop10RankStatus
.
value
)
{
userJoinStatus
.
value
=
false
;
showGameRank
.
value
=
false
;
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
}
else
{
$toast
(
'成绩提交中,请稍候...'
,
2
000
)
$toast
(
'成绩提交中,请稍候...'
,
5
000
)
}
return
}
...
...
@@ -173,7 +232,11 @@ function resetToLoadingView() {
}
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
countdownInterval
.
value
=
60
// currentGu.value = guFrames[0]
isGuPlaying
.
value
=
false
...
...
@@ -187,9 +250,15 @@ function startGameView() {
stopGameCountdown
()
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
// currentGu.value = guFrames[0]
showGameRank
.
value
=
false
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
...
...
@@ -209,20 +278,20 @@ const touchHandler = (mole: boolean) => {
let
scoreDelta
=
mole
?
5
:
-
3
;
let
nextTick
=
score
.
value
+
scoreDelta
if
(
nextTick
<
0
)
nextTick
=
0
if
(
!
submitScore
(
false
,
nextTick
))
return
score
.
value
=
nextTick
if
(
mole
)
{
playGame3Music
(
1
);
}
else
{
playGame3Music
(
2
);
}
submitScore
(
false
,
nextTick
)
}
const
scoreChangeHandler
=
(
delta
:
number
)
=>
{
let
nextTick
=
score
.
value
+
delta
if
(
nextTick
<
0
)
nextTick
=
0
if
(
!
submitScore
(
false
,
nextTick
))
return
score
.
value
=
nextTick
submitScore
(
false
,
nextTick
)
}
if
(
wechat
)
{
...
...
@@ -245,12 +314,12 @@ if (wechat) {
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
if
(
!
is_save
)
{
//非保存状态下
const
nextScore
=
Number
(
typeof
data
===
'object'
?
data
?.
score
:
NaN
)
const
nextRank
=
Number
(
typeof
data
===
'object'
?
data
?.
rank
:
data
)
const
nextRank
=
getServerRank
(
data
)
const
remainingSeconds
=
Number
(
typeof
data
===
'object'
?
data
?.
remainingSeconds
:
NaN
)
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
remainingSeconds
)
&&
remainingSeconds
>=
0
)
{
...
...
@@ -259,36 +328,37 @@ if (wechat) {
}
else
if
(
typeof
data
===
'object'
&&
data
)
{
if
(
Array
.
isArray
(
data
.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
Number
(
item
?.
rank
??
index
+
1
),
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
Number
(
data
.
rank
)
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
const
nextRank
=
getServerRank
(
data
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
!
userTop10RankStatus
.
value
)
{
showGameOverRank
()
}
markFinalScoreResult
()
}
return
{
code
:
'MSYF'
,
score
:
score
.
value
,
rank_no
:
rank
.
value
}
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
;
submitScore
(
true
)
},
onGameRecover
:
(
data
)
=>
{
const
recoveredRank
=
Number
(
data
?.
rank
)
const
recoveredRank
=
getServerRank
(
data
)
const
recoveredScore
=
Number
(
data
?.
score
)
const
recoveredSeconds
=
Number
(
data
?.
remainingSeconds
)
rank
.
value
=
Number
.
isFinite
(
recoveredRank
)
&&
recoveredRank
>
0
?
recoveredRank
:
0
rank
.
value
=
recoveredRank
score
.
value
=
Number
.
isFinite
(
recoveredScore
)
&&
recoveredScore
>
0
?
recoveredScore
:
0
showGameRule
.
value
=
false
showGameRank
.
value
=
false
currentView
.
value
=
'playing'
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
(
Number
.
isFinite
(
recoveredSeconds
)
&&
recoveredSeconds
>
0
?
recoveredSeconds
:
0
,
)
...
...
@@ -318,7 +388,9 @@ onMounted(() => {
// TODO_LOCAL: 本地模拟游戏开始,稍后部署上线前删除此段
if
(
$is_run_local
())
{
showGameRule
.
value
=
false
currentView
.
value
=
'playing'
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
})
...
...
frontend-h5/src/pages/game4/Game4.vue
View file @
94cab0cd
...
...
@@ -59,6 +59,8 @@ const countdownInterval = ref(60);
const
isDivDescVisible
=
ref
(
false
);
const
tick
=
ref
(
0
);
// 点击次数/摇动次数
const
rank
=
ref
(
0
);
// 排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
currentHorse
=
ref
(
imageUrls
.
horse
);
const
currentYaoyiyao
=
ref
(
imageUrls
.
yaoyiyao
);
const
token
=
ref
(
wechat
?.
token
??
""
);
...
...
@@ -76,6 +78,48 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
""
;
};
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
"object"
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
;
const
nextRank
=
Number
(
value
);
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
;
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showScoreView
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
tick
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
;
}
...
...
@@ -87,13 +131,13 @@ function stopGameCountdown() {
}
}
function
submitScore
(
save
:
boolean
=
false
)
{
function
submitScore
(
save
:
boolean
=
false
,
currentTick
=
tick
.
value
)
{
// 最后提交保存在数据库中
if
(
save
)
{
// item_num 游戏项目(1到6)
// wechat 原始token
sendGameMessage
(
"submit_score_save"
,
{
score
:
tick
.
value
,
return
sendGameMessage
(
"submit_score_save"
,
{
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
4
,
nickname
:
wechat
.
nickname
,
...
...
@@ -101,7 +145,7 @@ function submitScore(save: boolean = false) {
rank
:
rank
.
value
,
});
}
else
{
sendGameMessage
(
"submit_score"
,
{
score
:
tick
.
value
});
return
sendGameMessage
(
"submit_score"
,
{
score
:
currentTick
});
}
}
...
...
@@ -123,7 +167,7 @@ function startGameCountdown(seconds = 60) {
// showGameRank.value = false;
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
}
else
{
$toast
(
'成绩提交中,请稍候...'
,
2
000
)
$toast
(
'成绩提交中,请稍候...'
,
5
000
)
}
return
;
}
...
...
@@ -189,8 +233,9 @@ function backToWaiting() { }
function
handleRoomBack
()
{
}
const
touchHandler
=
()
=>
{
tick
.
value
+=
5
;
submitScore
();
const
nextTick
=
tick
.
value
+
5
;
if
(
!
submitScore
(
false
,
nextTick
))
return
;
tick
.
value
=
nextTick
;
};
const
showGameRuleHandler
=
()
=>
{
...
...
@@ -233,7 +278,7 @@ if (wechat || isLocalMode) {
},
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
const
nextScore
=
Number
(
typeof
data
===
"object"
?
data
?.
score
:
NaN
);
const
nextRank
=
Number
(
typeof
data
===
"object"
?
data
?.
rank
:
data
);
const
nextRank
=
getServerRank
(
data
);
const
remainingSeconds
=
Number
(
typeof
data
===
"object"
?
data
?.
remainingSeconds
:
NaN
,
);
...
...
@@ -247,17 +292,18 @@ if (wechat || isLocalMode) {
)
{
syncGameCountdown
(
remainingSeconds
);
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
;
}
if
(
is_save
&&
!
userTop10RankStatus
.
value
)
{
showScoreView
();
if
(
is_save
)
{
markFinalScoreResult
();
}
return
{
code
:
"CMYF"
,
score
:
tick
.
value
,
rank_no
:
rank
.
value
};
},
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
);
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
},
onRoomClosed
:
showLoadingView
,
onRoomBack
:
handleRoomBack
,
onGameRecover
:
()
=>
{
...
...
frontend-h5/src/pages/game5/Game5.vue
View file @
94cab0cd
...
...
@@ -86,6 +86,8 @@ const countdownInterval = ref(60)
const
isDivDescVisible
=
ref
(
false
)
const
tick
=
ref
(
0
)
//点击次数
const
rank
=
ref
(
0
)
//排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
guFrames
:
[
string
,
string
,
string
]
=
[
imageUrls
.
gu01
,
imageUrls
.
gu02
,
imageUrls
.
gu03
]
const
currentGu
=
ref
(
imageUrls
.
gu01
)
const
isGuPlaying
=
ref
(
false
)
...
...
@@ -118,6 +120,56 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
''
}
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
'object'
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
const
nextRank
=
Number
(
value
)
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showGameOverRank
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
if
(
Array
.
isArray
(
data
?.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
tick
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
}
...
...
@@ -129,13 +181,13 @@ function stopGameCountdown() {
}
}
function
submitScore
(
save
:
boolean
=
false
)
{
function
submitScore
(
save
:
boolean
=
false
,
currentTick
=
tick
.
value
)
{
//最后提交保存在数据库中
if
(
save
)
{
//item_num 游戏项目(1到6)
//wechat 原始token
const
data
=
{
score
:
tick
.
value
,
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
5
,
nickname
:
wechat
.
nickname
,
...
...
@@ -143,11 +195,11 @@ function submitScore(save: boolean = false) {
rank
:
rank
.
value
,
}
console
.
log
(
'[WebSocket] send submit_score_save:'
,
JSON
.
stringify
(
data
,
null
,
2
))
sendGameMessage
(
'submit_score_save'
,
data
)
return
sendGameMessage
(
'submit_score_save'
,
data
)
}
else
{
const
data
=
{
score
:
tick
.
value
}
const
data
=
{
score
:
currentTick
}
console
.
log
(
'[WebSocket] send submit_score:'
,
JSON
.
stringify
(
data
))
sendGameMessage
(
'submit_score'
,
data
)
return
sendGameMessage
(
'submit_score'
,
data
)
}
}
...
...
@@ -163,13 +215,14 @@ function startGameCountdown(seconds = 60) {
countdownInterval
.
value
=
0
gameCountdownTimer
=
undefined
setDivDescVisible
(
false
)
hasFinalScoreResult
.
value
=
false
submitScore
(
true
)
if
(
userTop10RankStatus
.
value
)
{
userJoinStatus
.
value
=
false
;
// showGameRank.value = false;
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
}
else
{
$toast
(
'成绩提交中,请稍候...'
,
2
000
)
$toast
(
'成绩提交中,请稍候...'
,
5
000
)
}
return
}
...
...
@@ -210,7 +263,11 @@ function resetToLoadingView() {
}
tick
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
countdownInterval
.
value
=
60
currentGu
.
value
=
guFrames
[
0
]
isGuPlaying
.
value
=
false
...
...
@@ -224,9 +281,15 @@ function startGameView() {
stopGameCountdown
()
tick
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
currentGu
.
value
=
guFrames
[
0
]
showGameRank
.
value
=
false
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
...
...
@@ -244,9 +307,10 @@ function handleRoomBack() {
}
const
hitHandler
=
(
score
:
number
)
=>
{
tick
.
value
+=
score
const
nextTick
=
tick
.
value
+
score
if
(
!
submitScore
(
false
,
nextTick
))
return
tick
.
value
=
nextTick
console
.
log
(
'[WebSocket] 圈中马!得分:'
,
score
,
'当前总分:'
,
tick
.
value
)
submitScore
()
// console.log('[Audio] playGame1Music() 被调用 - 播放 game1.mp3 背景音乐')
// playGame1Music()
}
...
...
@@ -275,12 +339,12 @@ if (wechat) {
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
if
(
!
is_save
)
{
//非保存状态下
const
nextScore
=
Number
(
typeof
data
===
'object'
?
data
?.
score
:
NaN
)
const
nextRank
=
Number
(
typeof
data
===
'object'
?
data
?.
rank
:
data
)
const
nextRank
=
getServerRank
(
data
)
const
remainingSeconds
=
Number
(
typeof
data
===
'object'
?
data
?.
remainingSeconds
:
NaN
)
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
tick
.
value
=
nextScore
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
remainingSeconds
)
&&
remainingSeconds
>=
0
)
{
...
...
@@ -289,25 +353,24 @@ if (wechat) {
}
else
if
(
typeof
data
===
'object'
&&
data
)
{
if
(
Array
.
isArray
(
data
.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
Number
(
item
?.
rank
??
index
+
1
),
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
Number
(
data
.
rank
)
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
const
nextRank
=
getServerRank
(
data
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
!
userTop10RankStatus
.
value
)
{
showGameOverRank
()
}
markFinalScoreResult
()
}
return
{
code
:
'QCNF'
,
score
:
tick
.
value
,
rank_no
:
rank
.
value
}
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
;
submitScore
(
true
)
},
onRoomClosed
:
showLoadingView
,
onRoomBack
:
handleRoomBack
,
...
...
frontend-h5/src/pages/game6/Game.vue
View file @
94cab0cd
...
...
@@ -44,6 +44,8 @@ const countdownInterval = ref(60)
const
isDivDescVisible
=
ref
(
false
)
const
score
=
ref
(
0
)
const
rank
=
ref
(
0
)
//排名
const
roomStatus
=
ref
(
0
)
const
hasFinalScoreResult
=
ref
(
false
)
const
rankList
=
ref
<
RankPlayer
[]
>
([])
const
displayRankList
=
computed
<
RankPlayer
[]
>
(()
=>
{
const
list
=
rankList
.
value
.
slice
(
0
,
10
)
...
...
@@ -83,6 +85,56 @@ const confirmRefresh = (event: BeforeUnloadEvent) => {
event
.
returnValue
=
''
}
function
getServerRank
(
data
:
any
,
fallback
?:
unknown
)
{
const
value
=
typeof
data
===
'object'
&&
data
?
data
.
rank
??
data
.
rank_no
??
data
.
rankNo
??
data
.
game_rank
??
data
.
gameRank
??
fallback
:
data
const
nextRank
=
Number
(
value
)
return
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
?
nextRank
:
0
}
function
showFinalScoreIfReady
()
{
if
(
roomStatus
.
value
!==
4
||
!
hasFinalScoreResult
.
value
)
return
hasFinalScoreResult
.
value
=
false
showGameOverRank
()
}
function
markFinalScoreResult
()
{
hasFinalScoreResult
.
value
=
true
showFinalScoreIfReady
()
}
function
syncFinalStatus
(
data
:
any
)
{
const
nextStatus
=
Number
(
data
?.
status
)
if
(
!
Number
.
isFinite
(
nextStatus
))
return
roomStatus
.
value
=
nextStatus
if
(
nextStatus
===
3
)
{
return
}
if
(
nextStatus
!==
4
)
return
if
(
Array
.
isArray
(
data
?.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
getServerRank
(
data
)
const
nextScore
=
Number
(
data
?.
score
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
showFinalScoreIfReady
()
}
function
setDivDescVisible
(
visible
:
boolean
)
{
isDivDescVisible
.
value
=
visible
}
...
...
@@ -99,7 +151,7 @@ function submitScore(save: boolean = false, currentTick = score.value) {
if
(
save
)
{
//item_num 游戏项目(1到6)
//wechat 原始token
sendGameMessage
(
'submit_score_save'
,
{
const
sent
=
sendGameMessage
(
'submit_score_save'
,
{
score
:
currentTick
,
wechat
:
wechat
.
token
,
item_num
:
6
,
...
...
@@ -107,8 +159,14 @@ function submitScore(save: boolean = false, currentTick = score.value) {
avatar
:
wechat
.
avatar
,
rank
:
rank
.
value
,
})
if
(
sent
&&
!
userTop10RankStatus
.
value
)
{
window
.
setTimeout
(()
=>
{
$toast
(
'成绩提交中,请稍候...'
,
5000
)
},
0
)
}
return
sent
}
else
{
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
return
sendGameMessage
(
'submit_score'
,
{
score
:
currentTick
})
}
}
...
...
@@ -125,13 +183,14 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer
=
undefined
currentView
.
value
=
'loading'
setDivDescVisible
(
false
)
hasFinalScoreResult
.
value
=
false
submitScore
(
true
)
if
(
userTop10RankStatus
.
value
)
{
userJoinStatus
.
value
=
false
;
showGameRank
.
value
=
false
;
$toast
(
'一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧'
,
30000
)
}
else
{
$toast
(
'成绩提交中,请稍候...'
,
2
000
)
$toast
(
'成绩提交中,请稍候...'
,
5
000
)
}
return
}
...
...
@@ -162,7 +221,11 @@ function resetToLoadingView() {
}
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
countdownInterval
.
value
=
60
// currentGu.value = guFrames[0]
isGuPlaying
.
value
=
false
...
...
@@ -176,9 +239,15 @@ function startGameView() {
stopGameCountdown
()
score
.
value
=
0
rank
.
value
=
0
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
rankList
.
value
=
[]
roomStatus
.
value
=
0
hasFinalScoreResult
.
value
=
false
// currentGu.value = guFrames[0]
showGameRank
.
value
=
false
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
()
}
...
...
@@ -194,10 +263,10 @@ function showGameOverRank() {
const
touchHandler
=
(
mole
:
boolean
)
=>
{
let
scoreDelta
=
mole
?
5
:
0
;
let
nextTick
=
score
.
value
+
scoreDelta
score
.
value
=
nextTick
if
(
mole
)
{
if
(
!
submitScore
(
false
,
nextTick
))
return
score
.
value
=
nextTick
playGame6Music
(
1
);
submitScore
(
false
,
nextTick
)
}
else
{
playGame6Music
(
2
);
}
...
...
@@ -223,12 +292,12 @@ if (wechat) {
onScoreSubmitted
:
(
is_save
,
data
)
=>
{
if
(
!
is_save
)
{
//非保存状态下
const
nextScore
=
Number
(
typeof
data
===
'object'
?
data
?.
score
:
NaN
)
const
nextRank
=
Number
(
typeof
data
===
'object'
?
data
?.
rank
:
data
)
const
nextRank
=
getServerRank
(
data
)
const
remainingSeconds
=
Number
(
typeof
data
===
'object'
?
data
?.
remainingSeconds
:
NaN
)
if
(
Number
.
isFinite
(
nextScore
)
&&
nextScore
>=
0
)
{
score
.
value
=
nextScore
}
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
Number
.
isFinite
(
remainingSeconds
)
&&
remainingSeconds
>=
0
)
{
...
...
@@ -237,36 +306,37 @@ if (wechat) {
}
else
if
(
typeof
data
===
'object'
&&
data
)
{
if
(
Array
.
isArray
(
data
.
list
))
{
rankList
.
value
=
data
.
list
.
map
((
item
:
any
,
index
:
number
)
=>
({
rank
:
Number
(
item
?.
rank
??
index
+
1
),
rank
:
getServerRank
(
item
,
index
+
1
),
nickname
:
String
(
item
?.
nickname
??
''
),
avatar
:
String
(
item
?.
avatar
??
''
),
score
:
Number
(
item
?.
score
??
0
),
}))
}
const
nextRank
=
Number
(
data
.
rank
)
if
(
Number
.
isFinite
(
nextRank
)
&&
nextRank
>
0
)
{
const
nextRank
=
getServerRank
(
data
)
if
(
nextRank
>
0
)
{
rank
.
value
=
nextRank
}
if
(
!
userTop10RankStatus
.
value
)
{
showGameOverRank
()
}
markFinalScoreResult
()
}
return
{
code
:
'FYDT'
,
score
:
score
.
value
,
rank_no
:
rank
.
value
}
},
onStatus
:
syncFinalStatus
,
onRescoreSubmitted
:
(
_recount
)
=>
{
submitScore
(
true
)
;
submitScore
(
true
)
},
onGameRecover
:
(
data
)
=>
{
const
recoveredRank
=
Number
(
data
?.
rank
)
const
recoveredRank
=
getServerRank
(
data
)
const
recoveredScore
=
Number
(
data
?.
score
)
const
recoveredSeconds
=
Number
(
data
?.
remainingSeconds
)
rank
.
value
=
Number
.
isFinite
(
recoveredRank
)
&&
recoveredRank
>
0
?
recoveredRank
:
0
rank
.
value
=
recoveredRank
score
.
value
=
Number
.
isFinite
(
recoveredScore
)
&&
recoveredScore
>
0
?
recoveredScore
:
0
showGameRule
.
value
=
false
showGameRank
.
value
=
false
currentView
.
value
=
'playing'
roomStatus
.
value
=
2
hasFinalScoreResult
.
value
=
false
currentView
.
value
=
'playing'
startGameCountdown
(
Number
.
isFinite
(
recoveredSeconds
)
&&
recoveredSeconds
>
0
?
recoveredSeconds
:
0
,
)
...
...
frontend-large/src/composables/useAdminGameSocket.ts
View file @
94cab0cd
...
...
@@ -24,11 +24,16 @@ type AdminGameSocketOptions = {
export
function
useAdminGameSocket
(
options
:
AdminGameSocketOptions
)
{
let
offSocketMessage
:
(()
=>
void
)
|
undefined
let
statusTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
function
requestRoomState
()
{
return
sendSocketMessage
(
'room_state'
)
}
function
requestStatus
()
{
return
sendSocketMessage
(
'status'
)
}
function
createRoom
(
index
:
number
)
{
return
sendSocketMessage
(
'room_create'
,
index
)
}
...
...
@@ -65,9 +70,15 @@ export function useAdminGameSocket(options: AdminGameSocketOptions) {
}
}
window
.
setTimeout
(
requestRoomState
,
200
)
window
.
setTimeout
(
requestStatus
,
200
)
statusTimer
=
window
.
setInterval
(
requestStatus
,
1000
)
},
onDisconnect
:
(
_reason
:
string
)
=>
{
console
.
log
(
'[useAdminGameSocket] WebSocket 断开连接,reason:'
,
_reason
,
'gameId:'
,
options
.
gameId
);
console
.
log
(
'[useAdminGameSocket] WebSocket disconnected:'
,
_reason
,
'gameId:'
,
options
.
gameId
);
if
(
statusTimer
)
{
window
.
clearInterval
(
statusTimer
)
statusTimer
=
undefined
}
},
onError
:
(
error
:
any
)
=>
{
console
.
error
(
'[useAdminGameSocket] WebSocket 错误:'
,
error
,
'gameId:'
,
options
.
gameId
);
...
...
@@ -97,7 +108,8 @@ export function useAdminGameSocket(options: AdminGameSocketOptions) {
}
switch
(
evt
)
{
case
'room_state_result'
:
{
case
'room_state_result'
:
case
'status_result'
:
{
if
(
data
.
gameId
)
{
//如果这两个值不一致说明浏览器有直接更新游戏房间号
if
(
data
.
gameId
!=
options
.
gameId
)
{
...
...
@@ -134,11 +146,16 @@ export function useAdminGameSocket(options: AdminGameSocketOptions) {
})
onBeforeUnmount
(()
=>
{
if
(
statusTimer
)
{
window
.
clearInterval
(
statusTimer
)
statusTimer
=
undefined
}
offSocketMessage
?.()
})
return
{
requestRoomState
,
requestStatus
,
createRoom
,
backRoom
,
startGame
,
...
...
frontend-large/src/pages/game1/Game.vue
View file @
94cab0cd
...
...
@@ -38,6 +38,9 @@ const playerCount = ref(0)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
// closeRoom();
...
...
@@ -87,11 +90,37 @@ const seedRankPlayersFromLoading = () => {
)
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -110,7 +139,7 @@ const gotoRank1WithIntro = async () => {
screen
.
value
=
'rank1'
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
s
creen
.
value
=
'rank2'
s
howSubmitWaiting
()
isPlayingStartAnimation
=
false
}
...
...
@@ -118,7 +147,7 @@ const gameId = 'game1'
const
{
startGame
,
createRoom
,
backRoom
,
closeRoom
}
=
useAdminGameSocket
({
gameId
,
onRoomState
:
(
data
:
any
)
=>
{
if
(
Array
.
isArray
(
data
?.
list
))
{
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
...
...
@@ -133,10 +162,17 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
gotoLoading
()
break
case
2
:
seedRankPlayersFromLoading
()
screen
.
value
=
'rank1'
screen
.
value
=
'rank1'
clearSubmitWaiting
()
break
case
3
:
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank2'
break
}
...
...
@@ -211,4 +247,66 @@ watch(screen, (value) => {
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-else-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
@
start=
"startGameWithMusic"
/>
<Rank2
v-else
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
style
>
frontend-large/src/pages/game2/Game.vue
View file @
94cab0cd
...
...
@@ -52,6 +52,9 @@ const playerCount = ref(0)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
// closeRoom();
...
...
@@ -117,11 +120,37 @@ const seedRankPlayersFromLoading = () => {
)
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -140,7 +169,7 @@ const gotoRank1WithIntro = async () => {
screen
.
value
=
'rank1'
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
s
creen
.
value
=
'rank2'
s
howSubmitWaiting
()
isPlayingStartAnimation
=
false
}
...
...
@@ -152,7 +181,7 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
},
onRoomState
:
(
data
:
any
)
=>
{
console
.
log
(
"[Game2] onRoomState 触发,data:"
,
JSON
.
stringify
(
data
));
if
(
Array
.
isArray
(
data
?.
list
))
{
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
...
...
@@ -168,11 +197,18 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
break
case
2
:
console
.
log
(
"[Game2] status=2,准备进入 rank1,loadingPlayers:"
,
loadingPlayers
.
value
.
length
);
seedRankPlayersFromLoading
()
console
.
log
(
"[Game2] seedRankPlayersFromLoading 后,rankPlayers:"
,
rankPlayers
.
value
.
length
,
JSON
.
stringify
(
rankPlayers
.
value
.
slice
(
0
,
3
)));
console
.
log
(
"[Game2] seedRankPlayersFromLoading 后,rankPlayers:"
,
rankPlayers
.
value
.
length
,
JSON
.
stringify
(
rankPlayers
.
value
.
slice
(
0
,
3
)));
screen
.
value
=
'rank1'
clearSubmitWaiting
()
break
case
3
:
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank2'
break
}
...
...
@@ -255,4 +291,66 @@ watch(screen, (value) => {
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-else-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
@
start=
"startGameWithMusic"
/>
<Rank2
v-else
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
style
>
frontend-large/src/pages/game3/Game3.vue
View file @
94cab0cd
...
...
@@ -39,6 +39,9 @@ const rankPlayers = ref<Player[]>(Array.from({ length: RANK_LIMIT }, (_, index)
const
horseBoosts
=
ref
<
Record
<
string
,
number
>>
({});
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
event
.
preventDefault
()
...
...
@@ -99,12 +102,38 @@ const updateRankPlayers = (data: any) => {
);
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
horseBoosts
.
value
=
{}
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -125,13 +154,14 @@ const gotoRank1WithIntro = async () => {
await
rank1Ref
.
value
?.
startIntro
()
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
function
handleRoomState
(
data
:
any
)
{
console
.
log
(
"[Game3] onRoomState 触发,data:"
,
JSON
.
stringify
(
data
));
if
(
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
case
0
:
...
...
@@ -144,7 +174,7 @@ function handleRoomState(data: any) {
case
2
:
console
.
log
(
"[Game3] status=2,准备进入 rank1,loadingPlayers:"
,
loadingPlayers
.
value
.
length
);
// 重连/中途进房时游戏已在运行,直接进入赛马画面
if
(
isPlayingStartAnimation
)
break
;
if
(
screen
.
value
===
'rank1'
||
isPlayingStartAnimation
)
break
;
isPlayingStartAnimation
=
true
;
screen
.
value
=
'rank1'
console
.
log
(
'[game3] handleRoomState: status=2, 直接启动赛马动画'
);
...
...
@@ -155,8 +185,15 @@ function handleRoomState(data: any) {
});
break
case
3
:
screen
.
value
=
'rank2'
break
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank2'
break
}
}
const
gameId
=
'game3'
...
...
@@ -297,4 +334,66 @@ watch(screen, (value) => {
<Rank1
v-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
:horse-boosts=
"horseBoosts"
@
start=
"startGameWithMusic"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<Rank2
v-if=
"screen === 'rank2'"
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
style
>
frontend-large/src/pages/game4/Game4.vue
View file @
94cab0cd
...
...
@@ -39,6 +39,9 @@ const playerCount = ref(0)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
// closeRoom();
...
...
@@ -105,11 +108,37 @@ const seedRankPlayersFromLoading = () => {
console
.
log
(
"[Game4] seedRankPlayersFromLoading 完成,rankPlayers:"
,
rankPlayers
.
value
.
length
,
JSON
.
stringify
(
rankPlayers
.
value
.
slice
(
0
,
3
)));
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -131,6 +160,7 @@ const gotoRank1WithIntro = async () => {
await
rank1Ref
.
value
?.
startIntro
()
// 结果页已在 Rank1View 内部渲染(showResult + result-overlay),不需要切到 rank2
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
horseBoosts
=
ref
<
Record
<
string
,
number
>>
({});
...
...
@@ -181,7 +211,7 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
},
onRoomState
:
(
data
:
any
)
=>
{
console
.
log
(
"[Game4] onRoomState 触发,data:"
,
JSON
.
stringify
(
data
));
if
(
Array
.
isArray
(
data
?.
list
))
{
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
...
...
@@ -197,11 +227,18 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
break
case
2
:
console
.
log
(
"[Game4] status=2,准备进入 rank1,loadingPlayers:"
,
loadingPlayers
.
value
.
length
);
seedRankPlayersFromLoading
()
console
.
log
(
"[Game4] seedRankPlayersFromLoading 后,rankPlayers:"
,
rankPlayers
.
value
.
length
,
JSON
.
stringify
(
rankPlayers
.
value
.
slice
(
0
,
3
)));
console
.
log
(
"[Game4] seedRankPlayersFromLoading 后,rankPlayers:"
,
rankPlayers
.
value
.
length
,
JSON
.
stringify
(
rankPlayers
.
value
.
slice
(
0
,
3
)));
screen
.
value
=
'rank1'
clearSubmitWaiting
()
break
case
3
:
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank1'
break
}
...
...
@@ -492,4 +529,66 @@ watch(screen, (value) => {
<Rank1
v-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
:horse-boosts=
"horseBoosts"
@
start=
"startGameWithMusic"
@
next=
"nextRound"
@
back=
"backHandler"
/>
<!--
<Rank2
v-else-if=
"screen === 'rank2'"
:rank-list=
"rankPlayers"
@
next=
"nextRound"
/>
-->
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
style
>
frontend-large/src/pages/game5/Game5.vue
View file @
94cab0cd
...
...
@@ -53,6 +53,9 @@ const playerCount = ref(0)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
event
.
preventDefault
()
...
...
@@ -112,11 +115,37 @@ const seedRankPlayersFromLoading = () => {
)
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -137,15 +166,15 @@ const gotoRank1WithIntro = async () => {
screen
.
value
=
'rank1'
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
s
creen
.
value
=
'rank2'
s
howSubmitWaiting
()
isPlayingStartAnimation
=
false
}
function
handleRoomState
(
data
:
any
)
{
console
.
log
(
'[WebSocket] 房间状态更新 - status:'
,
data
?.
status
,
'数据:'
,
JSON
.
stringify
(
data
))
if
(
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
case
0
:
...
...
@@ -156,12 +185,19 @@ function handleRoomState(data: any) {
gotoLoading
()
break
case
2
:
seedRankPlayersFromLoading
()
screen
.
value
=
'rank1'
break
screen
.
value
=
'rank1'
clearSubmitWaiting
()
break
case
3
:
screen
.
value
=
'rank2'
break
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank2'
break
}
}
...
...
@@ -263,4 +299,66 @@ watch(screen, (value) => {
@
next=
"nextRoundWithMusic"
/>
<!--
<Rank1
v-else
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
@
start=
"startGameWithMusic"
--
>
<Rank2
v-else
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
style
>
frontend-large/src/pages/game6/Game.vue
View file @
94cab0cd
...
...
@@ -38,6 +38,9 @@ const playerCount = ref(0)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
isSubmitWaiting
=
ref
(
false
)
const
submitWaitingSeconds
=
ref
(
5
)
let
submitWaitingTimer
:
ReturnType
<
typeof
window
.
setInterval
>
|
undefined
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
event
.
preventDefault
()
...
...
@@ -86,11 +89,37 @@ const seedRankPlayersFromLoading = () => {
)
}
function
showSubmitWaiting
()
{
if
(
!
isSubmitWaiting
.
value
)
{
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
}
submitWaitingTimer
=
window
.
setInterval
(()
=>
{
submitWaitingSeconds
.
value
=
Math
.
max
(
0
,
submitWaitingSeconds
.
value
-
1
)
if
(
submitWaitingSeconds
.
value
<=
0
&&
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
},
1000
)
}
isSubmitWaiting
.
value
=
true
}
function
clearSubmitWaiting
()
{
isSubmitWaiting
.
value
=
false
submitWaitingSeconds
.
value
=
5
if
(
submitWaitingTimer
)
{
window
.
clearInterval
(
submitWaitingTimer
)
submitWaitingTimer
=
undefined
}
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
clearSubmitWaiting
()
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
...
...
@@ -109,14 +138,14 @@ const gotoRank1WithIntro = async () => {
screen
.
value
=
'rank1'
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
s
creen
.
value
=
'rank2'
s
howSubmitWaiting
()
isPlayingStartAnimation
=
false
}
function
handleRoomState
(
data
:
any
)
{
if
(
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
if
(
(
data
?.
status
===
0
||
data
?.
status
===
1
)
&&
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
case
0
:
...
...
@@ -127,12 +156,19 @@ function handleRoomState(data: any) {
gotoLoading
()
break
case
2
:
seedRankPlayersFromLoading
()
screen
.
value
=
'rank1'
break
case
3
:
screen
.
value
=
'rank2'
break
screen
.
value
=
'rank1'
clearSubmitWaiting
()
break
case
3
:
showSubmitWaiting
()
break
case
4
:
clearSubmitWaiting
()
if
(
Array
.
isArray
(
data
?.
list
))
{
updateRankPlayers
(
data
.
list
)
}
screen
.
value
=
'rank2'
break
}
}
const
gameId
=
'game6'
...
...
@@ -209,4 +245,66 @@ watch(screen, (value) => {
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-else-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
@
start=
"startGameWithMusic"
/>
<Rank2
v-else
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<div
v-if=
"isSubmitWaiting"
class=
"submit-waiting-overlay"
>
<div
class=
"submit-waiting-title"
>
正在等待玩家提交分数
</div>
<div
:key=
"submitWaitingSeconds"
class=
"submit-waiting-count"
>
{{
submitWaitingSeconds
}}
</div>
</div>
</
template
>
<
style
scoped
>
.submit-waiting-overlay
{
position
:
fixed
;
inset
:
0
;
z-index
:
9999
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
background
:
radial-gradient
(
ellipse
at
center
,
rgba
(
0
,
0
,
0
,
0.22
)
0%
,
rgba
(
0
,
0
,
0
,
0.08
)
48%
,
transparent
72%
);
color
:
#fff
;
pointer-events
:
none
;
}
.submit-waiting-title
{
position
:
absolute
;
bottom
:
8vh
;
left
:
0
;
width
:
100%
;
font-size
:
56px
;
font-weight
:
700
;
line-height
:
1
;
text-align
:
center
;
text-shadow
:
0
10px
24px
rgba
(
0
,
0
,
0
,
0.35
);
}
.submit-waiting-count
{
color
:
white
;
font-size
:
300pt
;
font-weight
:
800
;
line-height
:
1
;
text-shadow
:
0
18px
38px
rgba
(
0
,
0
,
0
,
0.25
);
animation
:
submit-countdown-pop
1s
ease
both
;
}
@keyframes
submit-countdown-pop
{
0
%
{
opacity
:
0
;
transform
:
scale
(
0.45
);
}
18
%
{
opacity
:
1
;
transform
:
scale
(
1.14
);
}
58
%
{
opacity
:
1
;
transform
:
scale
(
1
);
}
100
%
{
opacity
:
0
;
transform
:
scale
(
0.84
);
}
}
</
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