Commit 301b840f authored by 董政锦's avatar 董政锦

Merge branch 'gmae5-h5-second' into 'main'

Gmae5 h5 second See merge request !6
parents 484300e4 a227740b
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue' import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { cssAssetUrl } from '@/commons/assets.ts' import { cssAssetUrl } from '@/commons/assets.ts'
import MobileStage from '@/components/MobileStage.vue' import MobileStage from '@/components/MobileStage.vue'
import { useGameSocket, joinSharedRoom, sendGameMessage, userJoinStatus } from '@/composables/useGameSocket' import { useGameSocket, joinSharedRoom, sendGameMessage, userJoinStatus } from '@/composables/useGameSocket'
...@@ -10,9 +10,16 @@ import { $getWechat } from '@/commons/utils.ts' ...@@ -10,9 +10,16 @@ import { $getWechat } from '@/commons/utils.ts'
import { playGame1Music } from '@/commons/music' import { playGame1Music } from '@/commons/music'
type GameView = 'loading' | 'playing' | 'score' type GameView = 'loading' | 'playing' | 'score'
type RankPlayer = {
rank: number
nickname: string
avatar: string
score: number | string
}
const imageUrls = { const imageUrls = {
bg: cssAssetUrl('game5/bg.webp'), bg: cssAssetUrl('game5/bg.webp'),
playingBg: cssAssetUrl('game5/second-bg.webp'),
bg2: cssAssetUrl('game1/bg2.png'), bg2: cssAssetUrl('game1/bg2.png'),
logo: cssAssetUrl('logo.png'), logo: cssAssetUrl('logo.png'),
title: cssAssetUrl('game5/title.webp'), title: cssAssetUrl('game5/title.webp'),
...@@ -28,12 +35,24 @@ const imageUrls = { ...@@ -28,12 +35,24 @@ const imageUrls = {
back: cssAssetUrl('game1/back.png'), back: cssAssetUrl('game1/back.png'),
replay: cssAssetUrl('game1/replay.png'), replay: cssAssetUrl('game1/replay.png'),
close: cssAssetUrl('game1/close.png'), close: cssAssetUrl('game1/close.png'),
rank: cssAssetUrl('game6/rank.png'),
ranklist: cssAssetUrl('game6/ranklist.png'),
paodao: cssAssetUrl('game5/paodao.webp'),
circleBg: cssAssetUrl('game5/circle-bg.webp'),
circle: cssAssetUrl('game5/circle.webp'),
centerTile: cssAssetUrl('game5/biaoti.webp'),
rule: cssAssetUrl('game1/rule.png') rule: cssAssetUrl('game1/rule.png')
} }
const wechat = $getWechat() const wechat = $getWechat()
const currentView = ref<GameView>('loading') const currentView = ref<GameView>('loading')
const stageBackground = computed(() => {
if (currentView.value === 'playing') {
return `${imageUrls.playingBg} center/cover`
}
return `${imageUrls.bg} center/cover`
})
const countdownInterval = ref(60) const countdownInterval = ref(60)
const isDivDescVisible = ref(false) const isDivDescVisible = ref(false)
const tick = ref(0) //点击次数 const tick = ref(0) //点击次数
...@@ -45,6 +64,20 @@ const token = ref(wechat?.token ?? '') ...@@ -45,6 +64,20 @@ const token = ref(wechat?.token ?? '')
const nickname = ref(wechat?.nickname ?? '') const nickname = ref(wechat?.nickname ?? '')
const avatar = ref(wechat?.avatar ?? '') const avatar = ref(wechat?.avatar ?? '')
const showGameRule = ref(false) const showGameRule = ref(false)
const showGameRank = ref(false)
const rankList = ref<RankPlayer[]>([])
const displayRankList = computed<RankPlayer[]>(() => {
const list = rankList.value.slice(0, 10)
return Array.from({ length: 10 }, (_, index) => {
return list[index] ?? {
rank: index + 1,
nickname: '-',
avatar: '',
score: '-',
}
})
})
const mobileStageRef = ref<InstanceType<typeof MobileStage> | null>(null) const mobileStageRef = ref<InstanceType<typeof MobileStage> | null>(null)
const _offSocketMessage = ref<(() => void) | undefined>() const _offSocketMessage = ref<(() => void) | undefined>()
...@@ -98,7 +131,7 @@ function startGameCountdown(seconds = 60) { ...@@ -98,7 +131,7 @@ function startGameCountdown(seconds = 60) {
gameCountdownTimer = undefined gameCountdownTimer = undefined
setDivDescVisible(false) setDivDescVisible(false)
submitScore(true) submitScore(true)
showScoreView() showGameOverRank()
return return
} }
...@@ -122,10 +155,12 @@ function resetToLoadingView() { ...@@ -122,10 +155,12 @@ function resetToLoadingView() {
} }
tick.value = 0 tick.value = 0
rank.value = 0 rank.value = 0
rankList.value = []
countdownInterval.value = 60 countdownInterval.value = 60
currentGu.value = guFrames[0] currentGu.value = guFrames[0]
isGuPlaying.value = false isGuPlaying.value = false
userJoinStatus.value = false userJoinStatus.value = false
showGameRank.value = false
currentView.value = 'loading' currentView.value = 'loading'
setDivDescVisible(false) setDivDescVisible(false)
} }
...@@ -133,15 +168,19 @@ function resetToLoadingView() { ...@@ -133,15 +168,19 @@ function resetToLoadingView() {
function startGameView() { function startGameView() {
stopGameCountdown() stopGameCountdown()
tick.value = 0 tick.value = 0
rank.value = 0
rankList.value = []
currentGu.value = guFrames[0] currentGu.value = guFrames[0]
showGameRank.value = false
currentView.value = 'playing' currentView.value = 'playing'
startGameCountdown() startGameCountdown()
} }
function showScoreView() { function showGameOverRank() {
stopGameCountdown() stopGameCountdown()
setDivDescVisible(false) setDivDescVisible(false)
currentView.value = 'score' currentView.value = 'loading'
showGameRank.value = true
} }
...@@ -204,6 +243,20 @@ if (wechat) { ...@@ -204,6 +243,20 @@ if (wechat) {
if (Number.isFinite(nextRank) && nextRank > 0) { if (Number.isFinite(nextRank) && nextRank > 0) {
rank.value = nextRank rank.value = nextRank
} }
} 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),
nickname: String(item?.nickname ?? ''),
avatar: String(item?.avatar ?? ''),
score: Number(item?.score ?? 0),
}))
}
const nextRank = Number(data.rank)
if (Number.isFinite(nextRank) && nextRank > 0) {
rank.value = nextRank
}
} }
}, },
onRescoreSubmitted: (_recount) => { onRescoreSubmitted: (_recount) => {
...@@ -236,11 +289,50 @@ onBeforeUnmount(() => { ...@@ -236,11 +289,50 @@ onBeforeUnmount(() => {
const showGameRuleHandler = () => { const showGameRuleHandler = () => {
showGameRule.value = !showGameRule.value; showGameRule.value = !showGameRule.value;
} }
const rankCloseHandler = () => {
showGameRank.value = false
}
</script> </script>
<template> <template>
<MobileStage v-if="token" :showGameRule="showGameRule" ref="mobileStageRef" <MobileStage v-if="token" :showGameRule="showGameRule" :showGameRank="showGameRank" ref="mobileStageRef"
:background="`${imageUrls.bg} center/cover`"> :background="stageBackground">
<template #gameRank>
<div class="ranklist-container">
<div class="txt-title">排行</div>
<div class="list-container">
<div class="row row-1">
<div class="col-1">排名</div>
<div class="col-2">用户</div>
<div class="col-3">成绩</div>
</div>
<div class="row-2">
<div class="row rank-row" v-for="(item, index) in displayRankList"
:key="`${item.rank}-${index}`">
<div class="col-1">
<div>{{ item.rank }}</div>
</div>
<div class="col-2">
<div class="avatar"
:style="item.avatar ? { backgroundImage: `url(${item.avatar})` } : {}"></div>
<div>{{ item.nickname }}</div>
</div>
<div class="col-3">{{ item.score }}</div>
</div>
</div>
<div class="row row-3">
<div class="col-1">{{ rank > 0 ? rank : '未上榜' }}</div>
<div class="col-2">
<div class="avatar" :style="{ backgroundImage: `url(${avatar})` }"></div>
<div>{{ nickname }}</div>
</div>
<div class="col-3">{{ tick }}</div>
</div>
</div>
</div>
<div class="img-close" @click="rankCloseHandler"></div>
</template>
<template #gameRule> <template #gameRule>
<div class="rule-container"> <div class="rule-container">
<div class="rule-txt-container"> <div class="rule-txt-container">
...@@ -261,7 +353,8 @@ const showGameRuleHandler = () => { ...@@ -261,7 +353,8 @@ const showGameRuleHandler = () => {
<PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="tick" :rank="rank" <PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="tick" :rank="rank"
:current-gu="currentGu" :countdown-interval="countdownInterval" :is-div-desc-visible="isDivDescVisible" :current-gu="currentGu" :countdown-interval="countdownInterval" :is-div-desc-visible="isDivDescVisible"
@touch="touchHandler" /> @touch="touchHandler" />
<ScoreView v-else :image-urls="imageUrls" :rank="rank" :tick="tick" /> <!-- <PlayingView v-else :image-urls="imageUrls" :tick="tick" :rank="rank" -->
<!-- <ScoreView v-else :image-urls="imageUrls" :rank="rank" :tick="tick" /> -->
</MobileStage> </MobileStage>
<div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;"> <div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;">
请使用微信扫码进入游戏 请使用微信扫码进入游戏
...@@ -305,4 +398,95 @@ const showGameRuleHandler = () => { ...@@ -305,4 +398,95 @@ const showGameRuleHandler = () => {
transform: scale(0.8); transform: scale(0.8);
} }
} }
.ranklist-container {
width: 747px;
height: 1084px;
background: v-bind('imageUrls.ranklist');
transform: translate(-50%, -50%) scale(0.45);
left: 50%;
top: 50%;
position: absolute;
.txt-title {
width: 100%;
text-align: center;
font-size: 50px;
margin-top: 35px;
font-weight: bold;
color: #AA0000;
letter-spacing: 2px;
}
.list-container {
width: calc(100% - 90px);
height: calc(100% - 210px);
position: absolute;
left: 40px;
top: 140px;
text-align: center;
height: 73px;
line-height: 73px;
font-size: 32px;
.row {
display: grid;
grid-template-columns: 150px auto 150px;
align-items: center;
}
.row-1 {
color: #AA0000;
font-weight: bold;
background: linear-gradient(-84deg, #FFD396 0%, #FFF3D1 53%, #FFD59C 100%);
border-radius: 20px 20px 0px 0px;
}
.row-2 {
color: #633911;
.rank-row:nth-child(odd) {
background: #F2E2AE;
}
.rank-row:nth-child(even) {
background: #FCEEBF;
}
.col-1 {
position: relative;
}
}
.row-3 {
background: linear-gradient(0deg, #F4B64C 0%, #F7C96F 100%);
border-radius: 0px 0px 20px 20px;
}
.col-2 {
display: flex;
align-items: center;
justify-content: center;
gap: 18px;
.avatar {
width: 48px;
height: 48px;
flex: 0 0 auto;
border-radius: 50%;
background-position: center;
background-size: cover;
}
}
}
}
.img-close {
width: 57px;
height: 57px;
border-radius: 29px;
background: v-bind('imageUrls.close')center/cover;
transform: scale(0.7);
margin-top: 500px;
}
</style> </style>
\ No newline at end of file
...@@ -22,13 +22,23 @@ defineEmits<{ ...@@ -22,13 +22,23 @@ defineEmits<{
</div> </div>
</Transition> </Transition>
<div class="img-logo"></div> <div class="img-logo"></div>
<div class="play-content"> <div class="img-center-title"></div>
<div>当前击鼓积分</div> <div class="rank-content">
<div>{{ tick }}</div> <div class="txt-left">
<div>当前排名: &nbsp;&nbsp;<label>{{ rank }}</label>&nbsp;</div> <div>排名</div>
<div class="txt-bold">{{ rank }}</div>
</div> </div>
<div class="bg-bottom"></div> <div class="txt-right">
<div class="play-gu" :style="{ background: `${currentGu} center/cover` }" @click="$emit('touch')"></div> <div>实时积分</div>
<div class="txt-bold">{{ tick }}</div>
</div>
</div>
<!-- <div class="bg-bottom"></div> -->
<div class="paodao-runway"></div>
<div class="circle-outer" @click="$emit('touch')">
<div class="circle-inner"></div>
</div>
<div class="play-click">点击按钮,开始套圈</div>
</div> </div>
</template> </template>
...@@ -118,47 +128,104 @@ defineEmits<{ ...@@ -118,47 +128,104 @@ defineEmits<{
transform: translateX(-50%); transform: translateX(-50%);
} }
.play-content { .img-center-title {
margin-top: 240px; position: absolute;
margin-left: 40px; top: 158px;
margin-right: 40px; left: 185px;
padding: 30px 0; width: 380px;
border-radius: 25px; height: 114px;
background: rgba(40, 12, 8, 0.52); background: v-bind('imageUrls.centerTile') center/cover;
color: white;
font-size: 28pt;
text-align: center;
} }
.play-content>div:nth-child(2) { .rank-content {
display: inline-block; width: 600px;
margin: 10px 0; height: 140px;
background: linear-gradient(180deg, #FFE68D 0%, #FAD500 100%); background: v-bind('imageUrls.rank') center/cover;
background-clip: text; position: absolute;
color: transparent; left: 50%;
font-size: 48pt; top: 380px;
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; font-weight: bold;
transform: scaleY(1.2); }
transform-origin: center;
-webkit-background-clip: text; >div {
display: flex;
width: 50%;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
}
} }
.play-content>div:nth-child(3) { .paodao-runway {
position: relative; position: absolute;
top: -10px; left: 0;
top: 696px;
width: 750px;
height: 306px;
background: v-bind('imageUrls.paodao') repeat-x;
background-size: auto 100%;
animation: runway-scroll 8s linear infinite;
} }
.play-content>div:nth-child(3) label { @keyframes runway-scroll {
color: white; 0% {
font-size: 42pt; background-position-x: 0;
}
100% {
background-position-x: -750px;
}
}
.circle-outer {
position: absolute;
left: 50%;
bottom: 72px;
width: 345px;
height: 345px;
background: v-bind('imageUrls.circleBg') center/cover;
transform: translateX(-50%);
animation: circle-spin 3s linear infinite;
}
@keyframes circle-spin {
0% {
transform: translateX(-50%) rotate(0deg);
}
100% {
transform: translateX(-50%) rotate(360deg);
}
}
.circle-inner {
position: absolute;
left: 50%;
top: 50%;
width: 165px;
height: 165px;
background: v-bind('imageUrls.circle') center/cover;
transform: translate(-50%, -50%);
} }
.play-gu { .play-click {
position: absolute; position: absolute;
bottom: 350px; bottom: 0px;
left: 50%; left: 50%;
width: 400px; width: 235px;
height: 400px; height: 26px;
transform: translateX(-50%) scale(2.4); transform: translateX(-50%) translateY(-190%);
font-weight: 400;
font-size: 26px;
color: #FFFFFF;
} }
</style> </style>
...@@ -182,10 +182,10 @@ onUnmounted(() => { ...@@ -182,10 +182,10 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<Loading v-if="screen !== 'loading'" :players="loadingPlayers" :player-count="playerCount" <Loading v-if="screen === 'loading'" :players="loadingPlayers" :player-count="playerCount"
@start="startGameWithMusic" /> @start="startGameWithMusic" />
<!-- <Rank1 v-else-if="screen === 'rank1'" ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic" --> <Rank1 v-else-if="screen === 'rank1'" ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic"
<Rank1 v-else ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic"
@next="nextRoundWithMusic" /> @next="nextRoundWithMusic" />
<!-- <Rank2 v-else :rank-list="rankPlayers" @next="nextRoundWithMusic" /> --> <!-- <Rank1 v-else ref="rank1Ref" :rank-list="rankPlayers" @start="startGameWithMusic" -->
<Rank2 v-else :rank-list="rankPlayers" @next="nextRoundWithMusic" />
</template> </template>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import { ref, watch, onMounted, onUnmounted } from "vue"; import { ref, watch, onMounted, onUnmounted } from "vue";
import DesignStage from "../../../components/DesignStage.vue"; import DesignStage from "../../../components/DesignStage.vue";
import type Player from "@/commons/player.ts"; import type Player from "@/commons/player.ts";
import { $is_run_local } from "@/commons/utils.ts"; import { $format_str, $is_run_local } from "@/commons/utils.ts";
import { cssAssetUrl, assetUrl } from "@/commons/assets.ts"; import { cssAssetUrl, assetUrl } from "@/commons/assets.ts";
const props = defineProps<{ const props = defineProps<{
...@@ -24,16 +24,13 @@ const imageUrls = { ...@@ -24,16 +24,13 @@ const imageUrls = {
bg: cssAssetUrl("game5/bg.svg"), bg: cssAssetUrl("game5/bg.svg"),
logo: cssAssetUrl("game1/logo.png"), logo: cssAssetUrl("game1/logo.png"),
title: cssAssetUrl("game5/title3.webp"), title: cssAssetUrl("game5/title3.webp"),
titleRank: cssAssetUrl("game1/title-rank.png"), rankNo4: cssAssetUrl("game6/no4.png"),
rankNo4: cssAssetUrl("game1/no4.png"), rankNo1: cssAssetUrl("game6/no1.png"),
rankNo1: cssAssetUrl("game1/no1.png"), rankNo2: cssAssetUrl("game6/no2.png"),
rankNo2: cssAssetUrl("game1/no2.png"), rankNo3: cssAssetUrl("game6/no3.png"),
rankNo3: cssAssetUrl("game1/no3.png"), avatar: cssAssetUrl("avatar-yellow.png"),
rankIcon: cssAssetUrl("game1/no-icon.png"), avatarAnimation: cssAssetUrl("avatar-yellow_animation.png"),
rankNo1Icon: cssAssetUrl("game1/no1-icon.png"), rankContainer: cssAssetUrl("game6/rank-container.png"),
rankNo2Icon: cssAssetUrl("game1/no2-icon.png"),
rankNo3Icon: cssAssetUrl("game1/no3-icon.png"),
avatar: assetUrl("avatar.png"),
}; };
// ========== 马匹相关 ========== // ========== 马匹相关 ==========
...@@ -247,20 +244,40 @@ defineExpose({ ...@@ -247,20 +244,40 @@ defineExpose({
}); });
// ========== 头像渲染 ========== // ========== 头像渲染 ==========
const avatarStyle = (item: Player) => { const renderAvatar = (item: any | null) => {
const avatar = item.avatar || imageUrls.avatar; if (item && item.avatar) {
return `background: url("${String(item.avatar).replace(/"/g, '\\"')}") center / cover no-repeat;`
}
return `background: ${imageUrls.avatar} center / cover no-repeat;`
}
// ========== rank icon 样式 ==========
const rankIcon = (index: number) => {
const icons = [
imageUrls.rankNo1,
imageUrls.rankNo2,
imageUrls.rankNo3,
];
let w = 42;
let h = 47;
let l = -20;
let t = -20;
if (index <= 2) {
w = 65;
h = 48;
l = -30;
t = -20;
}
return { return {
backgroundImage: `url("${avatar}")`, background: `${icons[index] ?? imageUrls.rankNo4} center / cover no-repeat`,
width: w + 'px',
height: h + 'px',
left: l + 'px',
top: t + 'px',
lineHeight: h + 'px',
color: index <= 2 ? 'white' : '#CC7F36',
}; };
}; };
// ========== rank item 样式 class ==========
const rankItemClass = (index: number) => {
if (index === 0) return "rank-top-1";
if (index === 1) return "rank-top-2";
if (index === 2) return "rank-top-3";
return "";
};
</script> </script>
<template> <template>
...@@ -271,28 +288,22 @@ const rankItemClass = (index: number) => { ...@@ -271,28 +288,22 @@ const rankItemClass = (index: number) => {
<div class="img-logo"></div> <div class="img-logo"></div>
<div class="img-title"></div> <div class="img-title"></div>
<!-- 排名列表 --> <div class="rank-container">
<!-- <div class="rank-container"> <div v-for="(item, index) in list" :key="playerKey(item, index)">
<div class="rank-txt"></div> <div>
<div class="rank-list"> <div class="rank-icon" :style="rankIcon(index)">{{ index + 1 }}</div>
<TransitionGroup name="rank"> <div class="rank-item">
<div <div>
v-for="(item, index) in list" <div class="img-avatar-container">
:key="playerKey(item, index)" <div class="img-avatar" :style="`${renderAvatar(item)}`"></div>
:class="[ </div>
'rank-item', <div class="txt-nickname">{{ $format_str(item.nickname, 12) }}</div>
rankItemClass(index), <div class="txt-score">{{ item.score }}</div>
rankEffects[playerKey(item, index)] || '', </div>
]" </div>
> </div>
<div class="rank-icon">{{ index + 1 }}</div>
<div class="rank-avatar" :style="avatarStyle(item)"></div>
<div class="rank-nickname">{{ item.nickname }}</div>
<div class="rank-score">{{ item.score }}</div>
</div> </div>
</TransitionGroup>
</div> </div>
</div> -->
<!-- 底部跑道背景(倒计时结束后滚动) --> <!-- 底部跑道背景(倒计时结束后滚动) -->
<div class="runway-track"> <div class="runway-track">
...@@ -364,136 +375,95 @@ const rankItemClass = (index: number) => { ...@@ -364,136 +375,95 @@ const rankItemClass = (index: number) => {
z-index: 20; z-index: 20;
} }
/* ========== 排名容器 ========== */ /* ========== 排名容器 (game6 风格水平布局) ========== */
.rank-container { .rank-container {
width: 503px; background: v-bind("imageUrls.rankContainer") center / cover no-repeat;
height: 810px; display: grid;
background: #fff; grid-template-columns: repeat(10, minmax(0, 1fr));
opacity: 0.9; align-items: center;
border-radius: 30px; column-gap: 42px;
box-sizing: border-box;
padding: 30px;
width: 1832px;
height: 244px;
position: absolute; position: absolute;
left: 50%; left: 44px;
top: 210px; top: 280px;
transform: translateX(-50%);
z-index: 10; z-index: 10;
overflow: hidden;
}
.rank-txt {
background: v-bind("imageUrls.titleRank");
width: 304px;
height: 40px;
margin: 10px auto auto auto;
}
.rank-list { > div {
box-sizing: border-box;
text-align: center;
width: 100%;
height: 100%;
> div {
box-sizing: border-box;
width: 100%;
height: 100%;
background: #A10A06;
border-radius: 5px;
position: relative; position: relative;
}
.rank-item { .rank-icon {
background: v-bind("imageUrls.rankNo4"); position: absolute;
width: 468px; color: #CC7F36;
height: 68px;
margin: 6px auto 0 auto;
display: grid;
grid-template-columns: 95px 68px 1fr 100px;
align-items: center;
color: #e00000;
font-weight: bold; font-weight: bold;
} }
}
}
.rank-item.rank-top-1 { .img-avatar-container {
background: v-bind("imageUrls.rankNo1"); position: relative;
} margin: 0 auto;
width: 90px;
height: 90px;
border-radius: 36px;
top: 18px;
}
.rank-item.rank-top-2 { .img-avatar-container::before {
background: v-bind("imageUrls.rankNo2"); content: "";
} position: absolute;
inset: 0;
border-radius: inherit;
background: v-bind("imageUrls.avatarAnimation");
animation: avatar-rotate 10s linear infinite;
}
.rank-item.rank-top-3 { .img-avatar {
background: v-bind("imageUrls.rankNo3"); width: 80px;
} height: 80px;
border-radius: 40px;
position: absolute;
left: 6px;
top: 5px;
}
.rank-icon { .txt-nickname {
background: v-bind("imageUrls.rankIcon") center / cover no-repeat; position: absolute;
width: 40px; bottom: 40px;
height: 40px;
margin: auto auto auto 20px;
text-align: center; text-align: center;
color: white; width: 100%;
font-weight: bold; color: #F9EBCB;
font-size: 22px; }
line-height: 40px;
}
.rank-item.rank-top-1 .rank-icon {
background: v-bind("imageUrls.rankNo1Icon") center / cover no-repeat;
width: 60px;
height: 38px;
margin: auto auto auto 10px;
}
.rank-item.rank-top-2 .rank-icon {
background: v-bind("imageUrls.rankNo2Icon") center / cover no-repeat;
width: 60px;
height: 38px;
margin: auto auto auto 10px;
}
.rank-item.rank-top-3 .rank-icon {
background: v-bind("imageUrls.rankNo3Icon") center / cover no-repeat;
width: 60px;
height: 38px;
margin: auto auto auto 10px;
}
.rank-avatar {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
width: 48px;
height: 48px;
border-radius: 24px;
margin-left: 10px;
}
.rank-nickname {
text-indent: 10px;
}
.rank-score {
text-align: right;
margin-right: 30px;
}
/* ========== 过渡动画 ========== */
.rank-move {
transition: transform 0.45s ease;
}
.rank-enter-active,
.rank-leave-active {
transition: opacity 0.25s ease, transform 0.25s ease;
}
.rank-leave-active { .txt-score {
position: absolute; position: absolute;
left: 17px; bottom: 5px;
} text-align: center;
width: 100%;
.rank-enter-from, color: #F9EBCB;
.rank-leave-to { }
opacity: 0;
transform: translateY(90px);
}
.rank-item.up,
.rank-item.new {
animation: rank-up-flash 0.8s ease;
} }
.rank-item.down { @keyframes avatar-rotate {
animation: rank-down-flash 0.8s ease; from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} }
/* ========== 底部跑道背景 ========== */ /* ========== 底部跑道背景 ========== */
...@@ -532,7 +502,7 @@ const rankItemClass = (index: number) => { ...@@ -532,7 +502,7 @@ const rankItemClass = (index: number) => {
width: 330px; width: 330px;
height: 300px; height: 300px;
will-change: transform; will-change: transform;
z-index: 5; z-index: 15;
} }
.horse-wrapper.horse-lane-top { .horse-wrapper.horse-lane-top {
......
...@@ -16,8 +16,8 @@ const FINAL_RANK_LIMIT = 10; ...@@ -16,8 +16,8 @@ const FINAL_RANK_LIMIT = 10;
const imageUrls = { const imageUrls = {
bg: cssAssetUrl('game5/bg.svg'), bg: cssAssetUrl('game5/bg.svg'),
logo: cssAssetUrl('game1/logo.png'), logo: cssAssetUrl('game1/logo.png'),
title: cssAssetUrl('game1/title3.png'), title: cssAssetUrl('game5/title.webp'),
title2: cssAssetUrl('game1/title4.png'), title2: cssAssetUrl('game5/title2.webp'),
podium: cssAssetUrl('game5/podium.webp'), podium: cssAssetUrl('game5/podium.webp'),
fireworks: cssAssetUrl('game1/fireworks.png'), fireworks: cssAssetUrl('game1/fireworks.png'),
avatar: cssAssetUrl('game5/avatar.webp'), avatar: cssAssetUrl('game5/avatar.webp'),
...@@ -69,7 +69,7 @@ const renderAvatar = (item: any | null) => { ...@@ -69,7 +69,7 @@ const renderAvatar = (item: any | null) => {
<div class="bg"> <div class="bg">
<div class="img-logo"></div> <div class="img-logo"></div>
<div class="img-title"></div> <div class="img-title"></div>
<!-- <div class="img-title2"></div> --> <div class="img-title2"></div>
<div class="podium"> <div class="podium">
<div class="rank-no1"> <div class="rank-no1">
...@@ -137,11 +137,11 @@ const renderAvatar = (item: any | null) => { ...@@ -137,11 +137,11 @@ const renderAvatar = (item: any | null) => {
} }
.img-title { .img-title {
background: v-bind('imageUrls.title'); background: v-bind('imageUrls.title')no-repeat center;
width: 967px; width: 967px;
height: 122px; height: 122px;
margin: 0 auto; margin: 0 auto;
margin-top: 37px; margin-top: 44px;
} }
.img-title2 { .img-title2 {
...@@ -149,7 +149,7 @@ const renderAvatar = (item: any | null) => { ...@@ -149,7 +149,7 @@ const renderAvatar = (item: any | null) => {
width: 457px; width: 457px;
height: 57px; height: 57px;
margin: 0 auto; margin: 0 auto;
margin-top: 37px; margin-top: 12px;
} }
.podium { .podium {
......
...@@ -134,13 +134,13 @@ const renderAvatar = (item: any | null) => { ...@@ -134,13 +134,13 @@ const renderAvatar = (item: any | null) => {
margin-top: 64px; margin-top: 64px;
} }
.img-title2 { /* .img-title2 {
background: v-bind('imageUrls.title2') no-repeat center; background: v-bind('imageUrls.title2') no-repeat center;
width: 457px; width: 457px;
height: 57px; height: 57px;
margin: 0 auto; margin: 0 auto;
margin-top: 37px; margin-top: 37px;
} } */
.podium { .podium {
background: v-bind('imageUrls.podium') no-repeat center; background: v-bind('imageUrls.podium') no-repeat center;
......
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