Commit 298716ce authored by 陈冲's avatar 陈冲

添加打地鼠

parent a2b36f00
...@@ -14,7 +14,7 @@ type GameView = 'loading' | 'playing' | 'score' ...@@ -14,7 +14,7 @@ type GameView = 'loading' | 'playing' | 'score'
const imageUrls = { const imageUrls = {
bg: cssAssetUrl('game1/bg.png'), bg: cssAssetUrl('game1/bg.png'),
bg2: cssAssetUrl('game1/bg2.png'), bg2: cssAssetUrl('game1/bg2.png'),
logo: cssAssetUrl('game1/logo.png'), logo: cssAssetUrl('logo.png'),
title: cssAssetUrl('game1/title.png'), title: cssAssetUrl('game1/title.png'),
avatar: cssAssetUrl('avatar.png'), avatar: cssAssetUrl('avatar.png'),
gu: cssAssetUrl('game1/gu.png'), gu: cssAssetUrl('game1/gu.png'),
...@@ -250,8 +250,7 @@ const showGameRuleHandler = () => { ...@@ -250,8 +250,7 @@ const showGameRuleHandler = () => {
<div class="rule-txt-container"> <div class="rule-txt-container">
<div class="rule-title">游戏规则</div> <div class="rule-title">游戏规则</div>
<div class="rule-txt"> <div class="rule-txt">
微信用户通过扫描大屏幕二维码 微信用户通过扫描大屏幕二维码参与,可容纳多人同时进行且比拼敲鼓,谁敲的最多即为获胜,游戏结束按分值高低先后排名,有机会获得新疆福彩定制周边礼品一份。
参与,可容纳多人同时进行且比拼敲鼓,谁敲的最多即为获胜,游戏结束按分值高低先后排名,有机会获得新疆福彩定制周边礼品一份。
</div> </div>
</div> </div>
<div class="rule-close"> <div class="rule-close">
......
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue'
import { cssAssetUrl } from '@/commons/assets.ts'
import MobileStage from '@/components/MobileStage.vue'
import { useGameSocket, joinSharedRoom, sendGameMessage, userJoinStatus } from '@/composables/useGameSocket'
import LoadingView from './views/LoadingView.vue'
import PlayingView from './views/PlayingView.vue'
import ScoreView from './views/ScoreView.vue'
import { $getWechat } from '@/commons/utils.ts'
import { playGame1Music } from '@/commons/music'
type GameView = 'loading' | 'playing' | 'score'
const imageUrls: Record<string, string> = {
bg: cssAssetUrl('game6/bg.png'),
logo: cssAssetUrl('logo.png'),
loadingBg1: cssAssetUrl('game6/loadingbg1.png'),
loadingBg2: cssAssetUrl('game6/loadingbg2.png'),
close: cssAssetUrl('game1/close.png'),
bg2: cssAssetUrl('game6/bg2.png'),
hydt: cssAssetUrl('game6/hydt.png'),
rank: cssAssetUrl('game6/rank.png'),
moleShowSprite: cssAssetUrl('game6/mole_show.png'),
moleHideSprite: cssAssetUrl('game6/mole_hide.png'),
moleHideprite: cssAssetUrl('game6/mole_hit.png'),
rabbitFaintprite: cssAssetUrl('game6/rabbit_faint.png'),
rabbitHideprite: cssAssetUrl('game6/rabbit_hide.png'),
rabbitshowprite: cssAssetUrl('game6/rabbit_show.png'),
land: cssAssetUrl('game6/land.png'),
hammer: cssAssetUrl('game6/hammer.png'),
}
const wechat = $getWechat()
const currentView = ref<GameView>('loading')
const countdownInterval = ref(60)
const isDivDescVisible = ref(false)
const score = ref(0)
const rank = ref(0) //排名
// const guFrames: [string, string, string] = [imageUrls.gu01, imageUrls.gu02, imageUrls.gu03]
// const currentGu = ref(imageUrls.gu01)
const isGuPlaying = ref(false)
const token = ref(wechat?.token ?? '')
const nickname = ref(wechat?.nickname ?? '')
const avatar = ref(wechat?.avatar ?? '')
const showGameRule = ref(false)
const mobileStageRef = ref<InstanceType<typeof MobileStage> | null>(null)
const _offSocketMessage = ref<(() => void) | undefined>()
let guFrameTimer: ReturnType<typeof window.setTimeout> | undefined
let gameCountdownTimer: ReturnType<typeof window.setTimeout> | undefined
const confirmRefresh = (event: BeforeUnloadEvent) => {
event.preventDefault()
event.returnValue = ''
}
function setDivDescVisible(visible: boolean) {
isDivDescVisible.value = visible
}
function stopGameCountdown() {
if (gameCountdownTimer) {
window.clearTimeout(gameCountdownTimer)
gameCountdownTimer = undefined
}
}
function submitScore(save: boolean = false) {
//最后提交保存在数据库中
if (save) {
//item_num 游戏项目(1到6)
//wechat 原始token
sendGameMessage('submit_score_save', {
score: score.value,
wechat: wechat.token_origin,
item_num: 1,
nickname: wechat.nickname,
avatar: wechat.avatar,
rank: rank.value,
})
} else {
sendGameMessage('submit_score', { score: score.value })
}
}
function startGameCountdown(seconds = 60) {
stopGameCountdown()
countdownInterval.value = seconds
setDivDescVisible(true)
const tickCountdown = () => {
countdownInterval.value -= 1
if (countdownInterval.value <= 0) {
countdownInterval.value = 0
gameCountdownTimer = undefined
setDivDescVisible(false)
submitScore(true)
showScoreView()
return
}
gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
}
gameCountdownTimer = window.setTimeout(tickCountdown, 1000)
}
function showLoadingView() {
stopGameCountdown()
currentView.value = 'loading'
setDivDescVisible(false)
}
function resetToLoadingView() {
stopGameCountdown()
if (guFrameTimer) {
window.clearTimeout(guFrameTimer)
guFrameTimer = undefined
}
score.value = 0
rank.value = 0
countdownInterval.value = 60
// currentGu.value = guFrames[0]
isGuPlaying.value = false
userJoinStatus.value = false
currentView.value = 'loading'
setDivDescVisible(false)
}
function startGameView() {
stopGameCountdown()
score.value = 0
// currentGu.value = guFrames[0]
currentView.value = 'playing'
startGameCountdown()
}
function showScoreView() {
stopGameCountdown()
setDivDescVisible(false)
currentView.value = 'score'
}
function replayGame() {
startGameView()
}
function backToWaiting() {
resetToLoadingView()
joinSharedRoom(nickname.value, token.value, avatar.value)
}
function handleRoomBack() {
resetToLoadingView()
window.setTimeout(() => {
joinSharedRoom(nickname.value, token.value, avatar.value)
}, 200)
}
const touchHandler = (scoreDelta: number) => {
score.value += scoreDelta
submitScore()
playGame1Music();
}
if (wechat) {
const { offSocketMessage } = useGameSocket({
gameId: 'game6',
auth: {
userid: wechat.token,
},
onConnect: () => {
window.setTimeout(() => {
const joined = joinSharedRoom(nickname.value, token.value, avatar.value)
}, 200)
},
onGameStart: async () => {
showGameRule.value = false;
await mobileStageRef.value?.startCountdown()
startGameView()
},
onScoreSubmitted: (is_save, data) => {
if (!is_save) {//非保存状态下
const nextRank = Number(typeof data === 'object' ? data?.rank : data)
if (Number.isFinite(nextRank) && nextRank > 0) {
rank.value = nextRank
}
}
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
},
onRoomClosed: showLoadingView,
onRoomBack: handleRoomBack,
})
_offSocketMessage.value = offSocketMessage
}
onMounted(() => {
document.title = '小游戏 - 福运当头'
if (token.value) {
window.addEventListener('beforeunload', confirmRefresh)
}
})
onBeforeUnmount(() => {
_offSocketMessage.value?.()
if (guFrameTimer) {
window.clearTimeout(guFrameTimer)
}
stopGameCountdown()
if (token.value) {
window.removeEventListener('beforeunload', confirmRefresh)
}
})
const showGameRuleHandler = () => {
showGameRule.value = !showGameRule.value;
}
</script>
<template>
<MobileStage v-if="token" :showGameRule="showGameRule" ref="mobileStageRef"
:background="`${imageUrls.bg2} center/cover`">
<template #gameRule>
<div class="rule-container">
<div class="rule-txt-container">
<div class="rule-title">游戏规则</div>
<div class="rule-txt">
微信用户通过扫描大屏幕二维码参与,可容纳多人同时进行且比拼打地鼠,谁打的最多即为获胜,游戏结束按分值高低先后排名,有机会获得新疆福彩定制周边礼品一份。
</div>
</div>
<div class="rule-close">
<div @click="showGameRuleHandler"></div>
</div>
</div>
</template>
<PlayingView :image-urls="imageUrls" :tick="score" :rank="rank" :countdown-interval="countdownInterval"
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler" />
<!-- <LoadingView v-if="currentView === 'loading'" :image-urls="imageUrls" :user-join-status="userJoinStatus"
@touchGameRule="showGameRuleHandler" />
<PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="score" :rank="rank"
:current-gu="currentGu" :countdown-interval="countdownInterval" :is-div-desc-visible="isDivDescVisible"
@touch="touchHandler" />
<ScoreView v-else :image-urls="imageUrls" :rank="rank" :tick="score" @replay="replayGame"
@back="backToWaiting" /> -->
</MobileStage>
<div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;">
请使用微信扫码进入游戏
</div>
</template>
<style scoped>
.rule-container {
.rule-txt-container {
background: #FFF9E4;
margin: 0 40px;
border-radius: 5px;
padding-top: 20px;
padding-bottom: 10px;
.rule-title {
text-align: center;
color: #850000;
font-weight: bold;
font-size: 15pt;
}
.rule-txt {
font-size: 12pt;
padding: 10px;
margin-top: 10px;
}
}
.rule-close {
width: 32px;
height: 130px;
margin: 0 auto;
background: v-bind('imageUrls.close') center/cover;
position: relative;
>div {
position: absolute;
bottom: 0;
width: 32px;
height: 32px;
border-radius: 16px;
}
}
}
</style>
<script setup lang="ts">
import { $getWechat } from '@/commons/utils.ts'
import { onMounted, ref } from 'vue';
defineProps<{
imageUrls: Record<string, string>
userJoinStatus: boolean
}>();
const nickname = ref('');
const avatar = ref('');
onMounted(() => {
const wechat = $getWechat();
nickname.value = wechat.nickname;
avatar.value = wechat.avatar;
});
</script>
<template>
<div class="h5-page game-stage">
<div class="game-desc" @click="$emit('touchGameRule')">游戏规则</div>
<div class="img-logo"></div>
<div class="img-loadingbg1">游戏等待开始倒计时60秒</div>
<div class="img-loadingbg2">游戏即将开始 敬请期待</div>
<div class="txt-bottom">您已成功加入游戏<br />等待主持人开始</div>
<!-- <div class="img-title"></div> -->
<!-- <div class="img-avatar" :style="`background: url(${avatar});border-radius:66px;width:132px;height:132px;`"></div> -->
<!-- <div class="txt-nickname">{{ nickname }}</div>
<div class="txt-loading">
<label v-if="userJoinStatus">您已成功加入游戏等待主持人开始</label>
<label v-else>正在加入游戏...</label>
</div> -->
<!-- <div class="bg-bottom"></div> -->
<!-- <div class="loading-gu"></div> -->
</div>
</template>
<style scoped>
.img-loadingbg1 {
font-size: 27pt;
width: 502px;
height: 90px;
background: v-bind('imageUrls.loadingBg1') center/cover;
border-radius: 45px;
position: absolute;
top: 474px;
left: 50%;
margin-left: -251px;
text-align: center;
line-height: 90px;
font-weight: bold;
color: #B90103;
letter-spacing: 2pt;
}
.img-loadingbg2 {
width: 100%;
height: 126px;
background: v-bind('imageUrls.loadingBg2') center/cover;
position: absolute;
top: 50%;
left: 50%;
font-size: 46px;
text-align: center;
line-height: 126px;
color: white;
letter-spacing: 2pt;
transform: translate(-50%, -50%);
}
.txt-bottom {
position: absolute;
bottom: 100px;
width: 100%;
line-height: 56px;
color: white;
font-size: 36px;
text-align: center;
animation: loading-text-scale 1.2s ease-in-out infinite;
}
.game-stage {
position: absolute;
width: 750px;
height: 1624px;
padding: 0;
}
.game-desc {
position: absolute;
z-index: 2;
top: 50%;
left: var(--stage-viewport-left, 0);
display: flex;
width: 86px;
height: 256px;
align-items: center;
justify-content: center;
border-radius: 0 12px 12px 0;
background: rgba(40, 12, 8, 0.52);
color: white;
font-size: 32pt;
letter-spacing: 10px;
line-height: 1.25;
text-align: center;
text-orientation: upright;
transform: translateY(-50%);
writing-mode: vertical-rl;
}
.bg-bottom {
position: absolute;
bottom: 0;
left: var(--stage-viewport-left, 0);
width: var(--stage-viewport-width, 750px);
height: 479px;
background: v-bind('imageUrls.bg2') center/cover;
opacity: 0.6;
}
.img-logo {
position: absolute;
top: 66px;
left: 20px;
width: 428px;
height: 77px;
background: v-bind('imageUrls.logo') center/cover;
}
.img-title {
position: absolute;
top: 200px;
left: 50%;
width: 609px;
height: 243px;
background: v-bind('imageUrls.title') center/cover;
transform: translateX(-50%);
}
.img-avatar {
position: absolute;
top: 480px;
left: 50%;
/* width: 148px;
height: 148px;
background: v-bind('avatar') center/cover; */
transform: translateX(-50%);
}
.txt-nickname {
position: absolute;
top: 640px;
left: 50%;
color: #E00000;
font-size: 25pt;
font-weight: bold;
transform: translateX(-50%);
}
.txt-loading {
position: absolute;
top: 710px;
left: 50%;
width: 288px;
color: #E00000;
font-size: 25pt;
font-weight: bold;
text-align: center;
transform: translateX(-50%);
}
.txt-loading label {
display: inline-block;
transform-origin: center;
animation: loading-text-scale 1.2s ease-in-out infinite;
}
@keyframes loading-text-scale {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.08);
}
}
.loading-gu {
position: absolute;
bottom: 100px;
left: 50%;
width: 600px;
height: 534px;
background: v-bind('imageUrls.gu') center/cover;
transform: translateX(-50%);
}
</style>
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
defineProps<{
imageUrls: Record<string, string>
countdownInterval: number
isDivDescVisible: boolean
tick: number
rank: number
// currentGu: string
}>()
const emit = defineEmits<{
touch: [scoreDelta: number]
}>()
type TargetKind = 'mole' | 'rabbit'
type TargetState = 'idle' | 'show' | 'hide' | 'hit'
type TargetItem = {
id: number
kind: TargetKind | null
state: TargetState
showMs: number
hideMs: number
hitMs: number
timer?: ReturnType<typeof window.setTimeout>
}
const list = ref<TargetItem[]>([]);
for (let i = 0; i < 9; i++) {
list.value.push({
id: i,
kind: null,
state: 'idle',
showMs: 650,
hideMs: 350,
hitMs: 700,
})
}
let spawnTimer: ReturnType<typeof window.setTimeout> | undefined
function clearTargetTimer(item: TargetItem) {
if (item.timer) {
window.clearTimeout(item.timer)
item.timer = undefined
}
}
function setTargetState(index: number, state: TargetState) {
const item = list.value[index]
if (!item) {
return
}
item.state = state
}
function resetTarget(index: number) {
const item = list.value[index]
if (!item) {
return
}
clearTargetTimer(item)
item.kind = null
item.state = 'idle'
}
function playTargetLifecycle(index: number, kind: TargetKind, duration = 1000) {
const item = list.value[index]
if (!item) {
return
}
clearTargetTimer(item)
item.kind = kind
item.state = 'show'
item.showMs = Math.round(duration * 0.65)
item.hideMs = Math.max(1, duration - item.showMs)
item.hitMs = kind === 'mole' ? 740 : 660
item.timer = window.setTimeout(() => {
setTargetState(index, 'hide')
item.timer = window.setTimeout(() => {
resetTarget(index)
}, item.hideMs)
}, item.showMs)
}
function randomTargetKind(): TargetKind {
return Math.random() < 0.65 ? 'mole' : 'rabbit'
}
function randomCount(min = 1, max = 3) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
function spawnRandomTargets(duration = 1000) {
const idleIndexes = list.value
.map((item, index) => item.state === 'idle' ? index : -1)
.filter(index => index >= 0)
.sort(() => Math.random() - 0.5)
const count = Math.min(randomCount(1, 3), idleIndexes.length)
for (const index of idleIndexes.slice(0, count)) {
playTargetLifecycle(index, randomTargetKind(), duration)
}
}
function scheduleRandomTargets() {
spawnRandomTargets(1000)
spawnTimer = window.setTimeout(scheduleRandomTargets, 1200)
}
function handleTargetTouch(index: number) {
const item = list.value[index]
if (!item || item.state === 'idle' || item.state === 'hit') {
return
}
const scoreDelta = item.kind === 'mole' ? 1 : -1
emit('touch', scoreDelta)
clearTargetTimer(item)
item.state = 'hit'
item.timer = window.setTimeout(() => {
resetTarget(index)
}, item.hitMs)
}
onMounted(() => {
scheduleRandomTargets()
})
onBeforeUnmount(() => {
if (spawnTimer) {
window.clearTimeout(spawnTimer)
}
for (const item of list.value) {
clearTargetTimer(item)
}
})
</script>
<template>
<div class="h5-page game-stage">
<Transition name="div-desc-slide" appear>
<div v-if="isDivDescVisible" class="div-desc">
<span class="desc-clock" aria-hidden="true"></span>
<span class="desc-time">{{ countdownInterval }}</span>
</div>
</Transition>
<div class="img-logo"></div>
<div class="img-hydt"></div>
<div class="rank-content">
<div class="txt-left">
<div>排名</div>
<div class="txt-bold">{{ rank }}</div>
</div>
<div class="txt-right">
<div>实时得分</div>
<div class="txt-bold">{{ tick }}</div>
</div>
</div>
<div class="mole-container">
<div v-for="(item, index) in list" :key="item.id">
<div class="img-land"></div>
<button v-if="item.kind" class="mole-hit-area" type="button" @click="handleTargetTouch(index)">
<span class="img-mole" :class="[`is-${item.kind}`, `is-${item.state}`]" :style="{
'--show-duration': `${item.showMs}ms`,
'--hide-duration': `${item.hideMs}ms`,
'--hit-duration': `${item.hitMs}ms`,
}"></span>
</button>
</div>
</div>
<div class="img-hammer"></div>
<!-- <div class="play-content">
<div>当前击鼓次数</div>
<div>{{ tick }}</div>
<div>当前排名: &nbsp;&nbsp;<label>{{ rank }}</label>&nbsp;</div>
</div> -->
<!-- <div class="bg-bottom"></div> -->
<!-- <div class="play-gu" :style="{ background: `${currentGu} center/cover` }" @click="$emit('touch')"></div> -->
</div>
</template>
<style scoped>
.game-stage {
position: absolute;
width: 750px;
height: 1624px;
padding: 0;
}
.img-hydt {
position: absolute;
width: 362px;
height: 104px;
top: 250px;
left: 50%;
transform: translate(-50%, -50%);
background: v-bind('imageUrls.hydt') center/cover;
}
.rank-content {
width: 600px;
height: 140px;
background: v-bind('imageUrls.rank') center/cover;
position: absolute;
left: 50%;
top: 480px;
display: flex;
align-items: center;
justify-content: space-between;
transform: translate(-50%, -50%);
font-size: 24px;
color: #A10A06;
.txt-bold {
font-size: 40px;
font-weight: bold;
}
>div {
display: flex;
width: 50%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
}
}
.img-hammer {
width: 148px;
height: 148px;
background: v-bind('imageUrls.hammer') center/cover;
position: absolute;
left: 50%;
bottom: 100px;
transform: translate(-50%, 0);
}
.mole-container {
position: absolute;
width: 750px;
height: 600px;
row-gap: 70px;
top: 560px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
place-items: center;
>div {
position: relative;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
}
}
.mole-hit-area {
position: absolute;
inset: 0;
}
.mole-hit-area {
z-index: 2;
padding: 0;
border: 0;
background: transparent;
}
.img-land,
.img-mole {
position: absolute;
top: 50%;
left: 50%;
width: 150px;
height: 150px;
transform: translate(-50%, -50%) scale(3);
transform-origin: center;
}
.img-mole {
display: block;
pointer-events: none;
}
.img-land,
.img-mole {
background-position: 0 0;
background-repeat: no-repeat;
background-size: auto 150px;
}
.img-land {
background-image: v-bind('imageUrls.land');
pointer-events: none;
}
.img-mole.is-mole.is-show {
background-image: v-bind('imageUrls.moleShowSprite');
animation: sprite-show var(--show-duration, 650ms) steps(31) forwards;
}
.img-mole.is-mole.is-hide {
background-image: v-bind('imageUrls.moleHideSprite');
animation: sprite-hide var(--hide-duration, 350ms) steps(16) forwards;
}
.img-mole.is-mole.is-hit {
background-image: v-bind('imageUrls.moleHideprite');
animation: sprite-mole-hit var(--hit-duration, 740ms) steps(37) forwards;
}
.img-mole.is-rabbit.is-show {
background-image: v-bind('imageUrls.rabbitshowprite');
animation: sprite-show var(--show-duration, 650ms) steps(31) forwards;
}
.img-mole.is-rabbit.is-hide {
background-image: v-bind('imageUrls.rabbitHideprite');
animation: sprite-hide var(--hide-duration, 350ms) steps(16) forwards;
}
.img-mole.is-rabbit.is-hit {
background-image: v-bind('imageUrls.rabbitFaintprite');
animation: sprite-rabbit-hit var(--hit-duration, 660ms) steps(33) forwards;
}
@keyframes sprite-show {
from {
background-position: 0 0;
}
to {
background-position: -4650px 0;
}
}
@keyframes sprite-hide {
from {
background-position: 0 0;
}
to {
background-position: -2400px 0;
}
}
@keyframes sprite-mole-hit {
from {
background-position: 0 0;
}
to {
background-position: -5550px 0;
}
}
@keyframes sprite-rabbit-hit {
from {
background-position: 0 0;
}
to {
background-position: -4950px 0;
}
}
.div-desc {
position: absolute;
top: 150px;
left: var(--stage-viewport-left, 0);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
width: 180px;
height: 80px;
border-radius: 0 56px 56px 0;
background: rgba(40, 12, 8, 0.48);
color: #fff;
.desc-clock {
position: absolute;
left: 20px;
width: 38px;
height: 44px;
border-radius: 50%;
background: v-bind('imageUrls.clock') center/cover;
}
.desc-time {
position: absolute;
right: 40px;
color: white;
font-size: 35pt;
line-height: 1;
}
}
.div-desc-slide-enter-active {
transition:
transform 360ms ease-out 220ms,
opacity 360ms ease-out 220ms;
}
.div-desc-slide-leave-active {
transition:
transform 260ms ease-in,
opacity 260ms ease-in;
}
.div-desc-slide-enter-from,
.div-desc-slide-leave-to {
opacity: 0;
transform: translateX(-110%);
}
.div-desc-slide-enter-to,
.div-desc-slide-leave-from {
opacity: 1;
transform: translateX(0);
}
.bg-bottom {
position: absolute;
bottom: 0;
left: var(--stage-viewport-left, 0);
width: var(--stage-viewport-width, 750px);
height: 479px;
background: v-bind('imageUrls.bg2') center/cover;
opacity: 0.6;
}
.img-logo {
position: absolute;
top: 46px;
left: 20px;
width: 428px;
height: 77px;
background: v-bind('imageUrls.logo') center/cover;
/* transform: translateX(-50%); */
}
.play-content {
margin-top: 240px;
margin-left: 40px;
margin-right: 40px;
padding: 30px 0;
border-radius: 25px;
background: rgba(40, 12, 8, 0.52);
color: white;
font-size: 28pt;
text-align: center;
}
.play-content>div:nth-child(2) {
display: inline-block;
margin: 10px 0;
background: linear-gradient(180deg, #FFE68D 0%, #FAD500 100%);
background-clip: text;
color: transparent;
font-size: 48pt;
font-weight: bold;
transform: scaleY(1.2);
transform-origin: center;
-webkit-background-clip: text;
}
.play-content>div:nth-child(3) {
position: relative;
top: -10px;
}
.play-content>div:nth-child(3) label {
color: white;
font-size: 42pt;
}
.play-gu {
position: absolute;
bottom: 350px;
left: 50%;
width: 400px;
height: 400px;
transform: translateX(-50%) scale(2.4);
}
</style>
<script setup lang="ts">
import { $getWechat } from '@/commons/utils';
import { onMounted, ref } from 'vue';
defineProps<{
imageUrls: Record<string, string>
tick: number
rank: number
}>()
defineEmits<{
replay: []
back: []
}>()
const nickname = ref('');
const avatar = ref('');
onMounted(() => {
const wechat = $getWechat();
nickname.value = wechat.nickname;
avatar.value = wechat.avatar;
});
</script>
<template>
<div class="h5-page game-stage">
<div class="img-logo"></div>
<div class="bg-bottom"></div>
<div class="img-score">
<div class="score-avatar"
:style="`background: url(${avatar});border-radius:66px;width:132px;height:132px;`"></div>
<div class="score-content">
<div>{{ nickname }}</div>
<div>您的成绩</div>
<div>击鼓次数(次)</div>
<div>{{ tick }}</div>
<div>最终排名</div>
<div><label>{{ rank }}</label></div>
</div>
</div>
<div class="btn-group">
<div class="btn-replay" @click="$emit('replay')"></div>
<div class="btn-back" @click="$emit('back')"></div>
</div>
</div>
</template>
<style scoped>
.game-stage {
position: absolute;
width: 750px;
height: 1624px;
padding: 0;
}
.bg-bottom {
position: absolute;
bottom: 0;
left: var(--stage-viewport-left, 0);
width: var(--stage-viewport-width, 750px);
height: 479px;
background: v-bind('imageUrls.bg2') center/cover;
opacity: 0.6;
}
.img-logo {
position: absolute;
top: 66px;
left: 50%;
width: 428px;
height: 77px;
background: v-bind('imageUrls.logo') center/cover;
transform: translateX(-50%);
}
.img-score {
position: absolute;
top: 450px;
left: 50%;
width: 465px;
height: 731px;
background: v-bind('imageUrls.scoreBg') center/cover;
transform: translateX(-50%) scale(1.2);
}
.score-avatar {
position: absolute;
top: -50px;
left: 50%;
width: 60px;
height: 60px;
background: v-bind('imageUrls.avatar') center/cover;
transform: translateX(-50%);
}
.score-content {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: calc(100% - 100px);
font-size: 28pt;
text-align: center;
}
.score-content>div:nth-child(1) {
color: #E00000;
font-size: 32pt;
font-weight: bold;
}
.score-content>div:nth-child(2) {
margin-top: 20px;
font-size: 32pt;
}
.score-content>div:nth-child(3) {
margin-top: 40px;
}
.score-content>div:nth-child(4) {
margin-top: 30px;
color: #E00000;
font-size: 32pt;
/* font-weight: bold; */
transform: scale(1.5);
}
.score-content>div:nth-child(5) {
margin-top: 40px;
}
.score-content>div:nth-child(6) {
margin-top: 20px;
color: #E00000;
font-size: 32pt;
font-weight: bold;
}
.score-content>div:nth-child(6) label {
color: #E00000;
font-size: 42pt;
margin: 0 10px;
}
.btn-group {
position: absolute;
top: 1320px;
left: 50%;
display: flex;
gap: 40px;
transform: translateX(-50%);
}
.btn-replay,
.btn-back {
width: 315px;
height: 100px;
}
.btn-replay {
background: v-bind('imageUrls.replay') center/cover;
}
.btn-back {
background: v-bind('imageUrls.back') center/cover;
}
</style>
import { createRouter, createWebHashHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import { $read } from '@/commons/utils' import { $read } from '@/commons/utils'
import Game1 from '@/pages/game1/Game1.vue' import Game1 from '@/pages/game1/Game.vue'
import Game6 from '@/pages/game6/Game.vue'
const getWechatId = () => { const getWechatId = () => {
return $read('token', '') return $read('token', '')
...@@ -21,6 +22,11 @@ const router = createRouter({ ...@@ -21,6 +22,11 @@ const router = createRouter({
// requiresAuth: true, // requiresAuth: true,
// }, // },
}, },
{
path: '/game6',
name: 'Game6',
component: Game6,
}
// { // {
// path: '/:pathMatch(.*)*', // path: '/:pathMatch(.*)*',
// redirect: '/', // redirect: '/',
......
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