Commit f4049020 authored by 陈冲's avatar 陈冲

feat: 图片压缩

parent 301b840f
cp.cmd
.vscode/launch.json
......@@ -30,6 +30,18 @@ const GAME_START_COUNTDOWN_SECS: u64 = 3;
const GAME_RESULT_WAIT_SECS: u64 = 2;
const GAME_RUNNING_SECS: u64 = 60;
fn get_game_tilte(key: &str) -> String {
let mut GAME_MAP = HashMap::new();
GAME_MAP.insert("game1", "击鼓齐福");
GAME_MAP.insert("game2", "聚宝接福");
GAME_MAP.insert("game3", "马上有福");
GAME_MAP.insert("game4", "策马迎福");
GAME_MAP.insert("game5", "圈彩纳福");
GAME_MAP.insert("game6", "福运当头");
let str = GAME_MAP.get(key).map_or("", |v| v);
str.to_string()
}
#[derive(Clone, Default)]
struct RoomPlayer {
/// 成绩分数,具体含义由前端和游戏逻辑自行定义,后端只负责存储和排序。
......@@ -464,15 +476,26 @@ async fn handle_room_command(
}
if let Some(index) = data.as_i64() {
if let Ok(mut state) = ROOM_STATE.lock() {
let game_id = format!("game{index}");
if cmd == "room_create" {
if state.status != RoomStatus::Closed {
drop(state);
emit_msgpack(&socket, evt, &err_resp("不能重复创建房间", None));
emit_msgpack(
&socket,
evt,
&err_resp(
&format!(
"不能重复创建游戏 - {} 房间",
get_game_tilte(&game_id)
),
None,
),
);
return;
}
}
state.reset();
state.current_game_id = Some(format!("game{index}"));
state.current_game_id = Some(game_id);
state.status = RoomStatus::Start;
// let snapshot = state.snapshot();
drop(state);
......@@ -492,7 +515,6 @@ async fn handle_room_command(
//超过300人的情况
if get_player_count() > 300 {
emit_msgpack(&socket, evt, &err_resp("本场游戏人员已满", Some(json!(3))));
_ = socket.clone().disconnect();
return;
}
let gameId = data
......@@ -522,57 +544,44 @@ async fn handle_room_command(
emit_msgpack(
&socket,
evt,
&err_resp("当前游戏房间还未开启", Some(json!(2))),
&err_resp(
&format!("当前游戏 - {} 房间还未开启", get_game_tilte(&gameId)),
Some(json!(2)),
),
);
return;
}
//游戏不是等待跟正在运行
if !matches!(state.status, RoomStatus::Start | RoomStatus::Running) {
drop(state);
emit_msgpack(
&socket,
evt,
&err_resp(
&format!(
"当前游戏 - {} 已经开始了,请在下一场游戏开始前进入",
get_game_tilte(&gameId)
),
Some(json!(2)),
),
);
_ = socket.clone().disconnect();
return;
}
let already_joined = state.players.contains_key(userid);
//玩家游戏过程中掉线重连
if already_joined {
if let Some(player) = state.players.get_mut(userid) {
player.online = true;
if !nickname.is_empty() {
player.nickname = nickname.to_string();
}
if !avatar.is_empty() {
player.avatar = avatar.to_string();
}
player.nickname = nickname.to_string();
player.avatar = avatar.to_string();
}
let reconnect_payload = state.reconnect_payload(userid);
let should_resume_game = state.status == RoomStatus::Running;
drop(state);
if let Some(mut player) = CLIENT_PLAYER_MAP.get_mut(userid) {
player.0 = 1;
}
emit_msgpack(&socket, evt, &ok_resp(reconnect_payload.clone()));
if should_resume_game {
if let Some(game_id) = reconnect_payload
.as_ref()
.and_then(|payload| payload.get("gameId"))
.and_then(|value| value.as_str())
{
emit_msgpack(
&socket,
"game_start_result",
&ok_resp(Some(json!(game_id))),
);
}
}
return;
}
if state.status != RoomStatus::Start {
drop(state);
emit_msgpack(
&socket,
evt,
&err_resp(
"当前游戏已经开始了,请在下一场游戏开始前进入",
Some(json!(2)),
),
);
_ = socket.clone().disconnect();
emit_msgpack(&socket, "room_recover_result", &ok_resp(reconnect_payload));
return;
}
let entry_order = state.next_entry_order;
......@@ -856,7 +865,7 @@ pub async fn on_connect(_io: SocketIo, socket: SocketRef, Data(data): Data<Value
emit_msgpack(
&socket,
"login_result",
&err_resp("当前管理员已登录,不能重复登录", Some(json!(1))),
&err_resp("当前管理员账号已登录,不能重复登录", Some(json!(1))),
);
_ = socket.disconnect();
return;
......@@ -870,7 +879,7 @@ pub async fn on_connect(_io: SocketIo, socket: SocketRef, Data(data): Data<Value
emit_msgpack(
&socket,
"connect_result",
&err_resp("game is not open", None),
&err_resp("游戏管理员暂未开启该房间", None),
);
_ = socket.disconnect();
return;
......@@ -942,10 +951,10 @@ pub async fn on_connect(_io: SocketIo, socket: SocketRef, Data(data): Data<Value
let count = state.players.len();
let ranking = state.current_ranking_payload();
drop(state);
broadcast_msgpack_all_admin(
"room_join_result",
&ok_resp(Some(json!({"list":ranking,"count":count}))),
);
// broadcast_msgpack_all_admin(
// "room_join_result",
// &ok_resp(Some(json!({"list":ranking,"count":count}))),
// );
}
}
}
......@@ -1001,7 +1010,7 @@ pub async fn login(req: &mut Request, res: &mut Response) {
let passphrase = utils::get_aes_passphrase();
if passphrase.is_none() {
res.render(Json(err_resp("username 和 password 不能为空", None)));
res.render(Json(err_resp("用户名或密码不能为空", None)));
return;
}
//当前管理员已登录,不能重复登录
......
import game1MusicUrl from '@/assets/images/game1.mp3'
import game6Music1Url from '@/assets/images/game6_1.mp3'
import game6Music2Url from '@/assets/images/game6_2.mp3'
import game6Music3Url from '@/assets/images/game6_3.mp3'
import go321 from '@/assets/images/321go.mp3'
......@@ -17,7 +16,7 @@ function getEffectTemplate(music: string) {
template = new Audio(music)
template.loop = false
template.preload = 'auto'
template.volume = 0.6
template.volume = 1
template.load()
effectTemplates.set(music, template)
}
......@@ -52,7 +51,7 @@ function setPendingRetry(retry: () => void) {
async function playEffect(music: string, retry: () => void) {
const audio = getEffectTemplate(music).cloneNode(true) as HTMLAudioElement
audio.loop = false
audio.volume = 0.6
audio.volume = 1
playingEffects.add(audio)
const release = () => releaseEffect(audio)
......@@ -105,10 +104,9 @@ export function stopCountdownMusic() {
/*
打地鼠击中爆炸6-1
打小白兔眩晕6-2
没打中6-3
*/
export async function playGame6Music(index: number) {
let arr: [string, string, string, string] = ['', game6Music1Url, game6Music2Url, game6Music3Url];
let arr: [string, string, string] = ['', game6Music1Url, game6Music2Url];
const music = arr[index]
if (!music) {
......
......@@ -18,12 +18,11 @@ type GameSocketOptions = {
onScoreSubmitted?: (is_save: boolean, data: any) => void
onRescoreSubmitted?: (recount: number) => void
onRoomClosed?: (data: any) => void
onGameRecover?: (data: any) => void
onEvent?: (evt: string, payload: SocketPayload) => void
onRoomBack?: (data: any) => void
}
let gameId = '';
function getGameIndex(data: any) {
if (typeof data === 'object' && data !== null) {
return Number(data.game ?? data.game_id ?? data.gameId ?? data.id)
......@@ -42,7 +41,7 @@ function getGameHomePath(data: any) {
return `/game${gameIndex}`
}
export function joinSharedRoom(nickname: string, token: string, avatar: string) {
export function joinSharedRoom(nickname: string, token: string, avatar: string, gameId: string) {
return sendSocketMessage('room_join', { nickname: nickname, token, avatar, gameId: gameId })
}
......@@ -52,7 +51,6 @@ export function sendGameMessage(cmd: string, data: any = {}) {
export const userJoinStatus = ref(false)
export function useGameSocket(options: GameSocketOptions) {
gameId = options.gameId;
const router = useRouter()
let socket: Socket | null = null
let offSocketMessage: (() => void) | undefined
......@@ -68,7 +66,7 @@ export function useGameSocket(options: GameSocketOptions) {
},
onDisconnect: (_reason: string) => { },
onError: (error: any) => {
console.error('socket.io connect_error:', error)
// console.error('socket.io connect_error:', error)
},
})
......@@ -79,10 +77,10 @@ export function useGameSocket(options: GameSocketOptions) {
if (evt === 'room_join_result') {
switch (data) {
case 1: userJoinStatus.value = true; break;
case 2:
case 3:
alert(msg);
break;
case 2:
case 3:
alert(msg);
break;
}
} else if (evt == 'submit_score_save') {
//提交分数的情况下有问题的情况下,只重试3次
......@@ -103,6 +101,10 @@ export function useGameSocket(options: GameSocketOptions) {
}
switch (evt) {
case 'connect_result':{
debugger
break;
}
case 'room_create_result': {
const nextPath = getGameHomePath(data)
......@@ -113,12 +115,30 @@ export function useGameSocket(options: GameSocketOptions) {
}
case 'room_join_result': {
if (data != options.gameId) {
alert('当前游戏房间还未开启');
return;
}
userJoinStatus.value = true
break
}
case 'room_recover_result': {
/*{
"gameId": "game6",
"rank": 1,
"reconnect": true,
"remainingSeconds": 56,
"score": 0,
"status": "running"
}*/
//游戏进行中玩家掉线重连时
if (data.gameId != options.gameId) {
return;
}
userJoinStatus.value = true
let { rank, remainingSeconds, score } = data;
//返回的时间可能会慢一秒
options.onGameRecover?.({ rank, remainingSeconds, score });
break
}
case 'game_start_result': {
if (data === options.gameId) {
options.onGameStart?.(data)
......
......@@ -106,12 +106,6 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
}
function showLoadingView() {
stopGameCountdown()
currentView.value = 'loading'
setDivDescVisible(false)
}
function resetToLoadingView() {
stopGameCountdown()
if (guFrameTimer) {
......@@ -142,14 +136,6 @@ function showScoreView() {
currentView.value = 'score'
}
function handleRoomBack() {
resetToLoadingView()
window.setTimeout(() => {
joinSharedRoom(nickname.value, token.value, avatar.value)
}, 200)
}
const touchHandler = () => {
if (isGuPlaying.value) {
return
......@@ -181,14 +167,15 @@ const touchHandler = () => {
}
if (wechat) {
const gameId = 'game1';
const { offSocketMessage } = useGameSocket({
gameId: 'game1',
gameId,
auth: {
userid: wechat.token,
},
onConnect: () => {
window.setTimeout(() => {
const joined = joinSharedRoom(nickname.value, token.value, avatar.value)
const joined = joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
}, 200)
},
onGameStart: async () => {
......@@ -207,8 +194,32 @@ if (wechat) {
onRescoreSubmitted: (_recount) => {
submitScore(true);
},
onRoomClosed: showLoadingView,
onRoomBack: handleRoomBack,
onGameRecover: (data) => {
const recoveredRank = Number(data?.rank)
const recoveredScore = Number(data?.score)
const recoveredSeconds = Number(data?.remainingSeconds)
rank.value = Number.isFinite(recoveredRank) && recoveredRank > 0 ? recoveredRank : 0
tick.value = Number.isFinite(recoveredScore) && recoveredScore > 0 ? recoveredScore : 0
showGameRule.value = false
// showGameRank.value = false
currentView.value = 'playing'
startGameCountdown(
Number.isFinite(recoveredSeconds) && recoveredSeconds > 0 ? recoveredSeconds : 0,
)
},
onRoomClosed: () => {
stopGameCountdown()
currentView.value = 'loading'
setDivDescVisible(false)
alert('管理员关闭了该房间')
},
onRoomBack: () => {
resetToLoadingView()
window.setTimeout(() => {
joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
}, 200)
},
})
_offSocketMessage.value = offSocketMessage
}
......
......@@ -128,12 +128,6 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
}
function showLoadingView() {
stopGameCountdown()
currentView.value = 'loading'
setDivDescVisible(false)
}
function resetToLoadingView() {
stopGameCountdown()
if (guFrameTimer) {
......@@ -168,37 +162,31 @@ function showGameOverRank() {
setDivDescVisible(false)
currentView.value = 'loading'
showGameRank.value = true
userJoinStatus.value = false;
}
function handleRoomBack() {
resetToLoadingView()
window.setTimeout(() => {
joinSharedRoom(nickname.value, token.value, avatar.value)
}, 200)
}
const touchHandler = (scoreDelta: number) => {
const nextTick = score.value + scoreDelta
const touchHandler = (mole: boolean) => {
let scoreDelta = mole ? 5 : 0;
let nextTick = score.value + scoreDelta
score.value = nextTick
submitScore(false, nextTick)
if (scoreDelta == 5) {
if (mole) {
playGame6Music(1);
} else if (scoreDelta == -3) {
playGame6Music(2);
submitScore(false, nextTick)
} else {
playGame6Music(3);
playGame6Music(2);
}
}
if (wechat) {
const gameId = 'game6';
const { offSocketMessage } = useGameSocket({
gameId: 'game6',
gameId,
auth: {
userid: wechat.token,
},
onConnect: () => {
window.setTimeout(() => {
const joined = joinSharedRoom(nickname.value, token.value, avatar.value)
const joined = joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
}, 200)
},
onGameStart: async () => {
......@@ -231,8 +219,32 @@ if (wechat) {
onRescoreSubmitted: (_recount) => {
submitScore(true);
},
onRoomClosed: showLoadingView,
onRoomBack: handleRoomBack,
onGameRecover: (data) => {
const recoveredRank = Number(data?.rank)
const recoveredScore = Number(data?.score)
const recoveredSeconds = Number(data?.remainingSeconds)
rank.value = Number.isFinite(recoveredRank) && recoveredRank > 0 ? recoveredRank : 0
score.value = Number.isFinite(recoveredScore) && recoveredScore > 0 ? recoveredScore : 0
showGameRule.value = false
showGameRank.value = false
currentView.value = 'playing'
startGameCountdown(
Number.isFinite(recoveredSeconds) && recoveredSeconds > 0 ? recoveredSeconds : 0,
)
},
onRoomClosed: () => {
stopGameCountdown()
currentView.value = 'loading'
setDivDescVisible(false)
alert('管理员关闭了该房间')
},
onRoomBack: () => {
resetToLoadingView()
window.setTimeout(() => {
joinSharedRoom(nickname.value, token.value, avatar.value, gameId)
}, 200)
},
})
_offSocketMessage.value = offSocketMessage
}
......@@ -279,7 +291,7 @@ const rankCloseHandler = () => {
<div class="rule-txt-container">
<div class="rule-title">游戏规则</div>
<div class="rule-txt">
1. 主持人开赛点击敲击,打中地鼠 + 5 分、误击白兔-3分;<br />
1. 主持人开赛点击敲击,打中地鼠 + 5 分、打中白兔不得分;<br />
2. 限时比拼反应速度,结束后按积分排名;<br />
3. 高分用户有机会领取新疆福彩定制周边;<br />
4. 禁止外挂作弊,违规账号取消成绩与领奖资格;<br /><br />
......
......@@ -11,7 +11,7 @@ defineProps<{
}>()
const emit = defineEmits<{
touch: [scoreDelta: number]
touch: [mole: boolean]
}>()
type TargetKind = 'mole' | 'rabbit'
......@@ -91,7 +91,7 @@ function playTargetLifecycle(index: number, kind: TargetKind, duration = 1000) {
}
function randomTargetKind(): TargetKind {
return Math.random() < 0.65 ? 'mole' : 'rabbit'
return Math.random() < 0.75 ? 'mole' : 'rabbit'
}
function randomCount(min = 1, max = 3) {
......@@ -120,9 +120,7 @@ function handleTargetTouch(index: number) {
if (!item || item.state === 'idle' || item.state === 'hit') {
return
}
const scoreDelta = item.kind === 'mole' ? 5 : -3
emit('touch', scoreDelta)
emit('touch', item.kind === 'mole')
clearTargetTimer(item)
item.state = 'hit'
item.timer = window.setTimeout(() => {
......
......@@ -87,7 +87,7 @@ function clearCountdownRetry() {
export async function playCountdownMusic() {
const audio = getCountdownTemplate().cloneNode(true) as HTMLAudioElement
audio.loop = false
audio.volume = 0.8
audio.volume = 1
countdownAudios.add(audio)
const release = () => releaseCountdownAudio(audio)
......
......@@ -77,7 +77,9 @@ export function sendSocketMessage(cmd: string, data: any = {}): boolean {
if (!socket?.connected) {
return false;
}
if ($is_run_local()) {
console.log('===================>send', cmd, data);
}
socket.send(encode({ cmd, data }));
return true;
}
......
......@@ -167,7 +167,7 @@ onBeforeUnmount(() => {
height: 84px;
padding: 0 40px;
background: rgba(0, 0, 0, 0.42);
border: 1px dashed #ccc;
/* border: 1px solid #ccc; */
color: #fff;
font-size: 42px;
line-height: 84px;
......
......@@ -41,6 +41,10 @@ export function useAdminGameSocket(options: AdminGameSocketOptions) {
return sendSocketMessage(cmd, data)
}
function closeRoom(){
return sendSocketMessage('room_close', {})
}
onMounted(() => {
const { passphrase, token, socket_path, client_ns, domain } = $read_socket_storge()
initSocket({
......@@ -103,5 +107,6 @@ export function useAdminGameSocket(options: AdminGameSocketOptions) {
backRoom,
startGame,
sendAdminMessage,
closeRoom,
}
}
......@@ -40,6 +40,7 @@ const rank1Ref = ref<InstanceType<typeof Rank1> | null>(null)
let isPlayingStartAnimation = false
const confirmRefresh = (event: BeforeUnloadEvent) => {
// closeRoom();
event.preventDefault()
event.returnValue = ''
}
......@@ -136,7 +137,7 @@ function handleRoomState(data: any) {
}
}
const { startGame, createRoom, backRoom } = useAdminGameSocket({
const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
gameId: 'game1',
onRoomState: handleRoomState,
onRoomJoin: (data) => {
......@@ -169,6 +170,14 @@ const nextRoundWithMusic = () => {
nextRound()
}
const backHandler = () => {
if (confirm('是否关闭当前房间回到首页')) {
closeRoom();
stopGame1Music()
router.replace('/main');
}
}
onMounted(() => {
window.addEventListener('beforeunload', confirmRefresh)
playGame1Music()
......@@ -182,7 +191,7 @@ onUnmounted(() => {
<template>
<Loading v-if="screen === 'loading'" :players="loadingPlayers" :player-count="playerCount"
@start="startGameWithMusic" />
@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" />
<Rank2 v-else :rank-list="rankPlayers" @next="nextRoundWithMusic" @back="backHandler" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import router from '@/router';
import { $format_str } from '@/commons/utils.ts';
import DesignStage from '@/components/DesignStage.vue'
import { assetUrl, cssAssetUrl } from '@/commons/assets.ts';
......@@ -11,6 +12,7 @@ defineProps<{
const emit = defineEmits<{
start: [];
back: [];
}>();
const imageUrls = {
......@@ -24,8 +26,10 @@ const imageUrls = {
avatarAnimation: cssAssetUrl('avatar_animation.png'),
avatar: cssAssetUrl('avatar.png'),
line: cssAssetUrl('game1/line.png'),
start1: cssAssetUrl('game1/start-1.png'),
start2: cssAssetUrl('game1/start-2.png'),
start: cssAssetUrl('game1/start.png'),
back: cssAssetUrl('game1/back.png'),
// start1: cssAssetUrl('game1/start-1.png'),
// start2: cssAssetUrl('game1/start-2.png'),
};
const isStartPressed = ref(false);
......@@ -42,7 +46,7 @@ const releaseStartButton = () => {
const renderAvatar = (item: any | null) => {
if (item && item.avatar) {
return `background: url("${String(item.avatar).replace(/"/g, '\\"')}") center / cover no-repeat;`
}
}
return `background: ${imageUrls.avatar} center / cover no-repeat;`
}
</script>
......@@ -72,14 +76,11 @@ const renderAvatar = (item: any | null) => {
</div>
<div class="list-container-line"></div>
<div class="list-container-right">
<div
class="btn-start"
:class="{ pressed: isStartPressed }"
@pointerdown="pressStartButton"
@pointerup="releaseStartButton"
@pointerleave="releaseStartButton"
@pointercancel="releaseStartButton"
></div>
<!-- <div class="btn-start" :class="{ pressed: isStartPressed }" @pointerdown="pressStartButton"
@pointerup="releaseStartButton" @pointerleave="releaseStartButton"
@pointercancel="releaseStartButton"></div> -->
<div class="btn-start" @click="pressStartButton"></div>
<div class="btn-back" @click="emit('back')"></div>
</div>
</div>
</div>
......@@ -237,13 +238,22 @@ const renderAvatar = (item: any | null) => {
width: 316px;
height: 105px;
margin-left: 60px;
margin-top: 80px;
background: v-bind('imageUrls.start1');
margin-top: 10px;
background: v-bind('imageUrls.start');
cursor: pointer;
}
.btn-start.pressed {
/* .btn-start.pressed {
background: v-bind('imageUrls.start2');
} */
.btn-back {
width: 316px;
height: 105px;
margin-left: 60px;
margin-top: 30px;
background: v-bind('imageUrls.back');
cursor: pointer;
}
}
}
......
......@@ -10,6 +10,7 @@ const props = defineProps<{
const emit = defineEmits<{
next: [];
back: [];
}>();
const FINAL_RANK_LIMIT = 10;
......@@ -29,7 +30,9 @@ const imageUrls = {
pai3: cssAssetUrl('game1/pai3.png'),
rankIcon: cssAssetUrl('game1/no-icon.png'),
avatarAnimation: cssAssetUrl('avatar_animation.png'),
next: cssAssetUrl('game1/next-1.png'),
next: cssAssetUrl('game1/next.png'),
back: cssAssetUrl('game1/back.png'),
vip: cssAssetUrl('game1/vip.png'),
};
const emptyPlayer = (index: number): Player => ({
......@@ -58,8 +61,8 @@ watch(
const renderAvatar = (item: any | null) => {
if (item && item.avatar) {
return `background: url('${item.avatar}') center / cover no-repeat;`
}
return `background: v-bind('imageUrls.avatar') center / cover no-repeat;`
}
return `background: ${imageUrls.avatar} center / cover no-repeat;`
}
</script>
......@@ -71,29 +74,24 @@ const renderAvatar = (item: any | null) => {
<div class="img-title2"></div>
<div class="podium">
<div class="rank-vip"></div>
<div class="rank-no1">
<div class="gu-burst"></div>
<div class="avatar" :style="`${renderAvatar(list[0])}`">
</div>
<div class="nickname">{{ list[0]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
<div class="rank-no2">
<div class="gu-burst"></div>
<div class="avatar" :style="`${renderAvatar(list[1])}`">
</div>
<div class="nickname">{{ list[1]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
<div class="rank-no3">
<div class="gu-burst"></div>
<div class="avatar" :style="`${renderAvatar(list[2])}`">
</div>
<div class="nickname">{{ list[2]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
</div>
......@@ -102,7 +100,7 @@ const renderAvatar = (item: any | null) => {
<div class="no-icon">{{ index + 4 }}</div>
<div>
<div class="img-avatar-container">
<div class="img-avatar"></div>
<div class="img-avatar" :style="`${renderAvatar(list[index + 3])}`"></div>
</div>
<div class="txt-nickname">{{ item.nickname }}</div>
</div>
......@@ -110,6 +108,7 @@ const renderAvatar = (item: any | null) => {
</div>
<div class="btn-next" @click="emit('next')"></div>
<div class="btn-back" @click="emit('back')"></div>
</div>
</DesignStage>
</template>
......@@ -182,46 +181,28 @@ const renderAvatar = (item: any | null) => {
}
.avatar {
/* background: v-bind('imageUrls.avatar') center / cover no-repeat; */
width: 120px;
height: 120px;
border-radius: 60px;
width: 160px;
height: 160px;
border-radius: 80px;
position: absolute;
left: 610px;
top: -136px;
left: 575px;
top: -146px;
}
.nickname {
width: 167px;
height: 46px;
background: #FFCF44;
color: white;
background: linear-gradient(0deg, #FFBF5A 0%, #FFE47A 100%);
border: 1px solid #FFF9DC;
color: #4B1A14;
text-align: center;
line-height: 46px;
position: absolute;
left: 590px;
left: 570px;
top: -25px;
z-index: 1;
border-radius: 23px;
}
.guan {
background: v-bind('imageUrls.guan1');
width: 64px;
height: 64px;
position: absolute;
left: 580px;
top: -153px
}
.pai {
background: v-bind('imageUrls.pai1');
width: 212px;
height: 200px;
position: absolute;
left: 570px;
top: 40px;
}
}
.rank-no2 {
......@@ -233,20 +214,21 @@ const renderAvatar = (item: any | null) => {
}
.avatar {
background: v-bind('imageUrls.avatar') center / cover no-repeat;
width: 120px;
height: 120px;
border-radius: 60px;
width: 144px;
height: 144px;
border-radius: 72px;
position: absolute;
left: 180px;
top: -110px;
top: -113px;
}
.nickname {
width: 167px;
height: 46px;
background: #CA9600;
color: white;
background: linear-gradient(0deg, #AEA6A7 0%, #EAE4DF 100%);
border: 1px solid white;
color: #383636;
text-align: center;
line-height: 46px;
position: absolute;
......@@ -255,24 +237,6 @@ const renderAvatar = (item: any | null) => {
z-index: 1;
border-radius: 23px;
}
.guan {
background: v-bind('imageUrls.guan2') no-repeat center;
width: 96px;
height: 96px;
position: absolute;
left: 134px;
top: -144px;
}
.pai {
background: v-bind('imageUrls.pai2') no-repeat center;
width: 212px;
height: 200px;
position: absolute;
left: 140px;
top: 50px;
}
}
.rank-no3 {
......@@ -284,49 +248,42 @@ const renderAvatar = (item: any | null) => {
}
.avatar {
background: v-bind('imageUrls.avatar') center / cover no-repeat;
width: 120px;
height: 120px;
border-radius: 60px;
width: 144px;
height: 144px;
border-radius: 72px;
position: absolute;
left: 1046px;
top: -110px;
left: 987px;
top: -116px;
}
.nickname {
width: 167px;
height: 46px;
background: #E2E2E2;
color: #AFAFAF;
background: linear-gradient(0deg, #F3AE76 0%, #F9CDA3 100%);
color: #6F3A0E;
border: 1px solid #FEFEFD;
text-align: center;
line-height: 46px;
position: absolute;
left: 1028px;
left: 977px;
top: 2px;
z-index: 1;
border-radius: 23px;
}
.guan {
background: v-bind('imageUrls.guan3') no-repeat center;
width: 96px;
height: 96px;
position: absolute;
left: 1003px;
top: -146px;
}
.pai {
background: v-bind('imageUrls.pai3') no-repeat center;
width: 212px;
height: 200px;
position: absolute;
right: 130px;
top: 50px;
}
}
}
.rank-vip {
width: 969px;
height: 238px;
background: v-bind('imageUrls.vip');
position: absolute;
left: 171px;
top: -200px;
}
.rank-container {
display: flex;
align-items: center;
......@@ -393,10 +350,20 @@ const renderAvatar = (item: any | null) => {
.btn-next {
position: absolute;
bottom: 100px;
left: 820px;
left: 620px;
width: 316px;
height: 105px;
cursor: pointer;
background: v-bind('imageUrls.next') center / cover no-repeat;
}
.btn-back {
position: absolute;
bottom: 100px;
left: 1020px;
width: 316px;
height: 105px;
cursor: pointer;
background: v-bind('imageUrls.back') center / cover no-repeat;
}
</style>
......@@ -136,7 +136,7 @@ function handleRoomState(data: any) {
}
}
const { startGame, createRoom, backRoom } = useAdminGameSocket({
const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
gameId: 'game6',
onRoomState: handleRoomState,
onRoomJoin: (data) => {
......@@ -169,6 +169,14 @@ const nextRoundWithMusic = () => {
nextRound()
}
const backHandler = () => {
if (confirm('是否关闭当前房间回到首页')) {
closeRoom();
stopGame6Music()
router.replace('/main');
}
}
onMounted(() => {
window.addEventListener('beforeunload', confirmRefresh)
playGame6Music()
......@@ -181,12 +189,8 @@ onUnmounted(() => {
</script>
<template>
<!-- <Loading :players="loadingPlayers" :player-count="playerCount"
@start="startGameWithMusic" /> -->
<!-- <Rank1 ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic" /> -->
<!-- <Rank2 :rank-list="rankPlayers" @next="nextRoundWithMusic" /> -->
<Loading v-if="screen === 'loading'" :players="loadingPlayers" :player-count="playerCount"
@start="startGameWithMusic" />
@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" />
<Rank2 v-else :rank-list="rankPlayers" @next="nextRoundWithMusic" @back="backHandler" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import router from '@/router';
import { $format_str } from '@/commons/utils.ts';
import DesignStage from '@/components/DesignStage.vue'
import { assetUrl, cssAssetUrl } from '@/commons/assets.ts';
......@@ -11,6 +12,7 @@ defineProps<{
const emit = defineEmits<{
start: [];
back:[];
}>();
const imageUrls = {
......@@ -34,8 +36,11 @@ const imageUrls = {
avatarAnimation: cssAssetUrl('avatar-red_animation.png'),
avatar: cssAssetUrl('avatar-red.png'),
line: cssAssetUrl('game1/line.png'),
start1: cssAssetUrl('game1/start-1.png'),
start2: cssAssetUrl('game1/start-2.png'),
// start1: cssAssetUrl('game1/start-1.png'),
// start2: cssAssetUrl('game1/start-2.png'),
start: cssAssetUrl('game1/start.png'),
back: cssAssetUrl('game1/back.png'),
};
const isStartPressed = ref(false);
......@@ -83,9 +88,11 @@ const renderAvatar = (item: any | null) => {
</div>
<div class="list-container-line"></div>
<div class="list-container-right">
<div class="btn-start" :class="{ pressed: isStartPressed }" @pointerdown="pressStartButton"
<!-- <div class="btn-start" :class="{ pressed: isStartPressed }" @pointerdown="pressStartButton"
@pointerup="releaseStartButton" @pointerleave="releaseStartButton"
@pointercancel="releaseStartButton"></div>
@pointercancel="releaseStartButton"></div> -->
<div class="btn-start" @click="pressStartButton"></div>
<div class="btn-back" @click="emit('back')"></div>
</div>
</div>
</div>
......@@ -254,13 +261,22 @@ const renderAvatar = (item: any | null) => {
width: 316px;
height: 105px;
margin-left: 60px;
margin-top: 80px;
background: v-bind('imageUrls.start1');
margin-top: 10px;
background: v-bind('imageUrls.start');
cursor: pointer;
}
.btn-start.pressed {
/* .btn-start.pressed {
background: v-bind('imageUrls.start2');
} */
.btn-back {
width: 316px;
height: 105px;
margin-left: 60px;
margin-top: 30px;
background: v-bind('imageUrls.back');
cursor: pointer;
}
}
}
......
......@@ -10,6 +10,7 @@ const props = defineProps<{
const emit = defineEmits<{
next: [];
back: [];
}>();
const FINAL_RANK_LIMIT = 10;
......@@ -22,7 +23,8 @@ const imageUrls = {
avatar: cssAssetUrl('avatar-yellow.png'),
avatarAnimation: cssAssetUrl('avatar-yellow_animation.png'),
rankIcon: cssAssetUrl('game6/no4.png'),
next: cssAssetUrl('game6/next-1.png'),
next: cssAssetUrl('game1/next.png'),
back: cssAssetUrl('game1/back.png'),
};
const emptyPlayer = (index: number): Player => ({
......@@ -69,22 +71,16 @@ const renderAvatar = (item: any | null) => {
<div class="avatar" :style="`${renderAvatar(list[0])}`">
</div>
<div class="nickname">{{ list[0]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
<div class="rank-no2">
<div class="avatar" :style="`${renderAvatar(list[1])}`">
</div>
<div class="nickname">{{ list[1]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
<div class="rank-no3">
<div class="avatar" :style="`${renderAvatar(list[2])}`">
</div>
<div class="nickname">{{ list[2]?.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
</div>
......@@ -101,6 +97,7 @@ const renderAvatar = (item: any | null) => {
</div>
<div class="btn-next" @click="emit('next')"></div>
<div class="btn-back" @click="emit('back')"></div>
</div>
</DesignStage>
</template>
......@@ -322,10 +319,19 @@ const renderAvatar = (item: any | null) => {
.btn-next {
position: absolute;
bottom: 50px;
left: 820px;
width: 318px;
height: 95px;
left: 620px;
width: 316px;
height: 105px;
cursor: pointer;
background: v-bind('imageUrls.next') center / cover no-repeat;
}
.btn-back {
position: absolute;
bottom: 50px;
left: 1020px;
width: 316px;
height: 105px;
cursor: pointer;
background: v-bind('imageUrls.back') center / cover no-repeat;
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment