Commit 06a4f0c7 authored by 董政锦's avatar 董政锦

fix: 修复game4 第一头像渲染问题;第二页加马接收数据调试语句,结果页渲染头像问题;

parent 81471c00
...@@ -199,7 +199,7 @@ if (wechat) { ...@@ -199,7 +199,7 @@ if (wechat) {
} }
onMounted(() => { onMounted(() => {
document.title = '小游戏 - 策马奔腾' document.title = '小游戏 - 策马迎福'
if (token.value) { if (token.value) {
window.addEventListener('beforeunload', confirmRefresh) window.addEventListener('beforeunload', confirmRefresh)
} }
......
<svg width="338" height="119" viewBox="0 0 338 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.7189 17.3104C20.5419 12.5095 24.7043 9 29.5751 9H322.613C328.699 9 333.374 14.3899 332.513 20.4142L320.37 105.414C319.666 110.341 315.447 114 310.471 114H15.0037C8.80556 114 4.10023 108.419 5.14749 102.31L19.7189 17.3104Z" fill="#DDA706"/>
<path d="M322.613 6.5C330.22 6.5 336.064 13.2373 334.988 20.7676L322.845 105.768C321.965 111.926 316.691 116.5 310.471 116.5H15.0039C7.25622 116.5 1.37451 109.524 2.68359 101.888L17.2549 16.8877C18.2837 10.8867 23.4867 6.5 29.5752 6.5H322.613Z" stroke="#A27900" stroke-opacity="0.6" stroke-width="5"/>
<path d="M21.7189 8.31036C22.5419 3.5095 26.7043 0 31.5751 0H322.829C328.839 0 333.492 5.26398 332.753 11.2287L322.23 96.2287C321.609 101.238 317.353 105 312.305 105H17.0037C10.8056 105 6.10023 99.4194 7.14749 93.3104L21.7189 8.31036Z" fill="#FFCE3C"/>
<path d="M22.57 8.58873C23.4847 3.89102 27.5997 0.5 32.3857 0.5H322.99C328.943 0.5 333.578 5.6693 332.931 11.5873L328.057 56.1507C327.529 60.9784 323.608 64.7288 318.762 65.0425L173.514 74.4437C172.935 74.4812 172.354 74.4682 171.777 74.4049L23.9455 58.1852C18.1305 57.5472 14.1024 52.0757 15.2205 46.3336L22.57 8.58873Z" fill="white" fill-opacity="0.3"/>
<path d="M112.088 82.6V41.384H93.3836V33.768H144.904V41.384H119.816V82.6H112.088ZM123.68 48.608H131.632L141.824 72.52H133.872L123.68 48.608ZM149.944 59.36V51.632H200.344V59.36H149.944ZM232.432 82.04V50.624C230.864 52.136 229.128 53.648 227.168 54.936V60.816H222.8V66.976L228.4 65.968V72.408L222.8 73.416V82.6H215.632V74.648L205.384 76.44V70L215.632 68.208V60.816H205.272L209.864 42.336H205.944V36.176H211.376L212.384 32.2H219.832L218.88 36.176H227.168V42.336H216.808L213.84 54.656H216.416V46.2H222.8V54.656H226.272V46.48C226.272 46.48 233.328 40.432 236.576 32.2H247.16C247.16 32.2 250.408 40.432 257.464 46.48V55.552C257.464 55.552 248.56 49.896 243.016 39.48H240.608C238.816 42.84 236.184 46.872 232.544 50.512H239.712V58.464C242.96 57.904 247.832 56.504 253.096 53.144V60.368C253.096 60.368 248.392 63.784 239.712 65.464V74.76H256.904V82.04H232.432Z" fill="white"/>
<path d="M110.088 79.6V38.384H91.3836V30.768H142.904V38.384H117.816V79.6H110.088ZM121.68 45.608H129.632L139.824 69.52H131.872L121.68 45.608ZM147.944 56.36V48.632H198.344V56.36H147.944ZM230.432 79.04V47.624C228.864 49.136 227.128 50.648 225.168 51.936V57.816H220.8V63.976L226.4 62.968V69.408L220.8 70.416V79.6H213.632V71.648L203.384 73.44V67L213.632 65.208V57.816H203.272L207.864 39.336H203.944V33.176H209.376L210.384 29.2H217.832L216.88 33.176H225.168V39.336H214.808L211.84 51.656H214.416V43.2H220.8V51.656H224.272V43.48C224.272 43.48 231.328 37.432 234.576 29.2H245.16C245.16 29.2 248.408 37.432 255.464 43.48V52.552C255.464 52.552 246.56 46.896 241.016 36.48H238.608C236.816 39.84 234.184 43.872 230.544 47.512H237.712V55.464C240.96 54.904 245.832 53.504 251.096 50.144V57.368C251.096 57.368 246.392 60.784 237.712 62.464V71.76H254.904V79.04H230.432Z" fill="#A00000"/>
</svg>
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -48,6 +48,16 @@ let offHorseBoost: (() => void) | undefined; ...@@ -48,6 +48,16 @@ let offHorseBoost: (() => void) | undefined;
// 监听 WebSocket 获取 H5 玩家操控的马匹加速度 // 监听 WebSocket 获取 H5 玩家操控的马匹加速度
offHorseBoost = onSocketMessage((evt, payload) => { offHorseBoost = onSocketMessage((evt, payload) => {
const data = payload?.data ?? payload; const data = payload?.data ?? payload;
// 调试日志:打印 WebSocket 原始数据
console.log("[Game4 WebSocket] 收到消息:", {
event: evt,
payloadType: typeof payload,
dataType: typeof data,
isArray: Array.isArray(data),
rawPayload: payload,
});
if (!Array.isArray(data)) return; if (!Array.isArray(data)) return;
const boosts: Record<string, number> = {}; const boosts: Record<string, number> = {};
...@@ -67,6 +77,7 @@ offHorseBoost = onSocketMessage((evt, payload) => { ...@@ -67,6 +77,7 @@ offHorseBoost = onSocketMessage((evt, payload) => {
}); });
if (hasBoost) { if (hasBoost) {
console.log("[Game4 WebSocket] 解析到加速数据:", boosts);
horseBoosts.value = { ...boosts }; horseBoosts.value = { ...boosts };
} }
}); });
...@@ -169,7 +180,13 @@ onUnmounted(() => { ...@@ -169,7 +180,13 @@ onUnmounted(() => {
:player-count="playerCount" :player-count="playerCount"
@start="startGame" @start="startGame"
/> />
<!-- v-else-if="screen === 'rank1'" --> <Rank1
<Rank1 ref="rank1Ref" :rank-list="rankPlayers" :horse-boosts="horseBoosts" @start="startGame" /> v-if="screen === 'rank1'"
<!-- <Rank2 v-else :rank-list="rankPlayers" @next="nextRound" /> --> ref="rank1Ref"
:rank-list="rankPlayers"
:horse-boosts="horseBoosts"
@start="startGame"
@next="screen = 'rank2'"
/>
<Rank2 v-else-if="screen === 'rank2'" :rank-list="rankPlayers" @next="nextRound" />
</template> </template>
...@@ -66,7 +66,7 @@ const releaseStartButton = () => { ...@@ -66,7 +66,7 @@ const releaseStartButton = () => {
> >
<div> <div>
<div class="img-avatar-container"> <div class="img-avatar-container">
<div class="img-avatar"></div> <div class="img-avatar" :style="`background:url('${item.avatar}') center / cover no-repeat;`"></div>
</div> </div>
<div class="txt-nickname"> <div class="txt-nickname">
{{ $format_str(item.nickname, 12) }} {{ $format_str(item.nickname, 12) }}
......
...@@ -13,6 +13,7 @@ const props = defineProps<{ ...@@ -13,6 +13,7 @@ const props = defineProps<{
const emit = defineEmits<{ const emit = defineEmits<{
start: []; start: [];
next: [];
}>(); }>();
const designStage = ref<InstanceType<typeof DesignStage> | null>(null); const designStage = ref<InstanceType<typeof DesignStage> | null>(null);
...@@ -24,7 +25,18 @@ const imageUrls = { ...@@ -24,7 +25,18 @@ const imageUrls = {
username: cssAssetUrl("game4/username.svg"), username: cssAssetUrl("game4/username.svg"),
avatar: cssAssetUrl("game4/avator.svg"), avatar: cssAssetUrl("game4/avator.svg"),
resultBg: cssAssetUrl("game4/resultBg.svg"), resultBg: cssAssetUrl("game4/resultBg.svg"),
next: cssAssetUrl("game1/next-1.png"), next: cssAssetUrl("game4/next-1.svg"),
// 结果弹窗 - podium 相关资源(复用 game1)
podium: cssAssetUrl("game4/podium.svg"),
fireworks: cssAssetUrl("game1/fireworks.png"),
guan1: cssAssetUrl("game1/guan1.png"),
pai1: cssAssetUrl("game4/pai1.svg"),
guan2: cssAssetUrl("game1/guan2.png"),
pai2: cssAssetUrl("game4/pai2.svg"),
guan3: cssAssetUrl("game1/guan3.png"),
pai3: cssAssetUrl("game4/pai3.svg"),
rankIcon: cssAssetUrl("game1/no-icon.png"),
avatarAnimation: cssAssetUrl("avatar_animation.png"),
}; };
// ========== 速度基准: 60秒从屏幕左侧跑到右侧 ========== // ========== 速度基准: 60秒从屏幕左侧跑到右侧 ==========
...@@ -111,11 +123,18 @@ const horseTranslateX = (xPercent: number) => { ...@@ -111,11 +123,18 @@ const horseTranslateX = (xPercent: number) => {
watch( watch(
() => props.horseBoosts, () => props.horseBoosts,
(boosts) => { (boosts) => {
if (!boosts) return; if (!boosts || Object.keys(boosts).length === 0) return;
console.log(
`[Rank1View] 收到加速度数据 (${new Date().toLocaleTimeString()}):`,
JSON.parse(JSON.stringify(boosts)),
);
horses.value.forEach((horse) => { horses.value.forEach((horse) => {
const boost = boosts[horse.id]; const boost = boosts[horse.id];
if (boost !== undefined) { if (boost !== undefined) {
horse.boost = boost; horse.boost = boost;
console.log(` 🐴 ${horse.nickname} (${horse.id}): boost=${boost}`);
} }
}); });
}, },
...@@ -253,6 +272,32 @@ const horseAvatarStyle = (horse: Horse) => { ...@@ -253,6 +272,32 @@ const horseAvatarStyle = (horse: Horse) => {
return { backgroundImage: `url(${horse.avatar})`, backgroundSize: "cover" }; return { backgroundImage: `url(${horse.avatar})`, backgroundSize: "cover" };
}; };
// 结果弹窗头像渲染(参考 game1 Rank2View)
const renderAvatar = (item: any) => {
if (item && item.avatar) {
return `background: url('${item.avatar}') center / cover no-repeat;`;
}
return `background: v-bind('imageUrls.avatar') center / cover no-repeat;`;
};
// 获取 podium 上三名选手(不足补空)
const podiumPlayers = (): RankItem[] => {
const result: RankItem[] = [];
for (let i = 0; i < 3; i++) {
result.push(
finalRankList.value[i] ?? {
rank: i + 1,
userid: `empty-${i}`,
nickname: "虚位以待",
avatar: "",
score: 0,
},
);
}
// 按 podium 视觉顺序:2 1 3
return [result[1]!, result[0]!, result[2]!];
};
onMounted(() => { onMounted(() => {
if ($is_run_local()) { if ($is_run_local()) {
mockHorses(); mockHorses();
...@@ -302,29 +347,39 @@ defineExpose({ ...@@ -302,29 +347,39 @@ defineExpose({
</div> </div>
<div v-if="showResult" class="result-overlay"> <div v-if="showResult" class="result-overlay">
<div class="result-mask"></div> <div class="result-mask"></div>
<div class="result-bg">
<!-- 排名列表 --> <!-- 领奖台 podium(参考 game1 Rank2View) -->
<div class="rank-list"> <div class="podium">
<div <div
v-for="item in finalRankList" v-for="(item, idx) in podiumPlayers()"
:key="item.userid" :key="item.userid || `podium-${idx}`"
class="rank-row" :class="['rank-no', `rank-no${idx === 1 ? 1 : idx === 0 ? 2 : 3}`]"
:class="{ 'rank-top-3': item.rank <= 3 }"
> >
<span class="rank-num">{{ item.rank }}</span> <div class="gu-burst"></div>
<div class="rank-avatar-wrap"> <div class="avatar" :style="renderAvatar(item)"></div>
<div class="nickname">{{ item.nickname }}</div>
<div class="guan"></div>
<div class="pai"></div>
</div>
</div>
<!-- 第4-10名 rank-container -->
<div class="rank-container">
<div <div
class="rank-avatar" v-for="(item, index) in finalRankList.slice(3, 10)"
:style="item.avatar ? { backgroundImage: `url(${item.avatar})`, backgroundSize: 'cover' } : {}" :key="item.userid || `rank-${index}`"
></div> >
<div class="no-icon">{{ index + 4 }}</div>
<div>
<div class="img-avatar-container">
<div class="img-avatar" :style="renderAvatar(item)"></div>
</div> </div>
<span class="rank-nickname">{{ item.nickname }}</span> <div class="txt-nickname">{{ item.nickname }}</div>
<span class="rank-score">{{ item.score }}</span>
</div> </div>
<div v-if="finalRankList.length === 0" class="rank-empty">暂无排名数据</div>
</div> </div>
</div> </div>
<div class="btn-next"></div>
<div class="btn-next" @click="emit('next')"></div>
</div> </div>
</div> </div>
</DesignStage> </DesignStage>
...@@ -483,6 +538,7 @@ defineExpose({ ...@@ -483,6 +538,7 @@ defineExpose({
} }
} }
/* ========== 结果弹窗 ========== */
.result-overlay { .result-overlay {
width: 1920px; width: 1920px;
height: 1080px; height: 1080px;
...@@ -491,8 +547,8 @@ defineExpose({ ...@@ -491,8 +547,8 @@ defineExpose({
left: 0; left: 0;
z-index: 100; z-index: 100;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center;
} }
.result-mask { .result-mask {
...@@ -502,99 +558,198 @@ defineExpose({ ...@@ -502,99 +558,198 @@ defineExpose({
top: 0; top: 0;
left: 0; left: 0;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
z-index: -1; z-index: 0;
} }
.result-bg { /* ========== podium 领奖台 ========== */
.podium {
background: v-bind("imageUrls.podium") no-repeat center;
width: 1347px;
height: 269px;
position: absolute; position: absolute;
top: 96px; top: 427px;
width: 1270px; left: 287px;
height: 717px;
background: v-bind("imageUrls.resultBg") center / cover no-repeat;
z-index: 1; z-index: 1;
display: flex;
align-items: center;
justify-content: center;
} }
.rank-list { .gu-burst {
width: 90%; width: 200px;
max-height: 500px; height: 200px;
overflow-y: auto; position: absolute;
display: flex; z-index: 1;
flex-direction: column; border-radius: 50%;
gap: 8px; opacity: 1;
padding: 20px 40px; transform: scale(0.6);
transform-origin: center center;
background: v-bind("imageUrls.fireworks") center / cover no-repeat;
pointer-events: none;
animation: gu-burst-expand 1.2s ease-out infinite;
} }
.rank-row { @keyframes gu-burst-expand {
display: flex; 0% {
align-items: center; opacity: 1;
height: 52px; transform: scale(0.6);
background: rgba(255, 255, 255, 0.08); }
border-radius: 8px; 100% {
padding: 0 16px; opacity: 0;
gap: 12px; transform: scale(1);
}
} }
.rank-row.rank-top-3 { .rank-no {
background: rgba(255, 215, 0, 0.15); position: relative;
border: 1px solid rgba(255, 215, 0, 0.3);
} }
.rank-num { /* 第1名 (中间) */
width: 36px; .rank-no1 {
height: 36px; .gu-burst { left: 580px; top: -200px; }
border-radius: 50%; .avatar {
background: rgba(255, 255, 255, 0.2); width: 120px; height: 120px; border-radius: 60px;
color: #fff; position: absolute; left: 610px; top: -136px;
font-size: 18px; }
font-weight: bold; .nickname {
width: 167px; height: 46px;
background: #FFCF44; color: white;
text-align: center; line-height: 46px;
position: absolute; left: 590px; 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;
}
}
/* 第2名 (左边) */
.rank-no2 {
.gu-burst { left: 140px; top: -170px; }
.avatar {
width: 120px; height: 120px; border-radius: 60px;
position: absolute; left: 180px; top: -110px;
}
.nickname {
width: 167px; height: 46px;
background: #CA9600; color: white;
text-align: center; line-height: 46px;
position: absolute; left: 157px; top: 2px;
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;
}
}
/* 第3名 (右边) */
.rank-no3 {
.gu-burst { left: 1020px; top: -170px; }
.avatar {
width: 120px; height: 120px; border-radius: 60px;
position: absolute; left: 1046px; top: -110px;
}
.nickname {
width: 167px; height: 46px;
background: #E2E2E2; color: #AFAFAF;
text-align: center; line-height: 46px;
position: absolute; left: 1028px; 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-container 第4-10名 ========== */
.rank-container {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; width: 1270px;
flex-shrink: 0; height: 115px;
position: absolute;
bottom: 243px;
left: 325px;
z-index: 1;
}
.rank-container > div {
flex: 1;
display: grid;
width: 100px;
height: 100%;
} }
.rank-avatar-wrap { .rank-container .no-icon {
background: v-bind("imageUrls.rankIcon") no-repeat center;
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 50%; position: absolute;
overflow: hidden; text-align: center;
flex-shrink: 0; line-height: 40px;
background: v-bind("imageUrls.avatar") center / cover no-repeat; color: white;
font-weight: bold;
} }
.rank-avatar { .rank-container .img-avatar-container {
width: 100%; position: relative;
height: 100%; margin: 0 auto;
border-radius: 50%; margin-top: 10px;
width: 72px;
height: 72px;
border-radius: 36px;
} }
.rank-nickname { .rank-container .img-avatar-container::before {
flex: 1; content: "";
color: #fff; position: absolute;
font-size: 22px; inset: 0;
font-weight: 500; border-radius: inherit;
overflow: hidden; background: v-bind("imageUrls.avatarAnimation");
text-overflow: ellipsis; animation: avatar-rotate 10s linear infinite;
white-space: nowrap;
} }
.rank-score { @keyframes avatar-rotate {
color: #ffcf44; 0% { transform: rotate(0deg); }
font-size: 20px; 100% { transform: rotate(360deg); }
font-weight: bold;
flex-shrink: 0;
} }
.rank-empty { .rank-container .img-avatar {
color: rgba(255, 255, 255, 0.5); position: relative;
font-size: 24px; top: 6px;
z-index: 1;
margin: 0 auto;
width: 60px;
height: 60px;
border-radius: 30px;
background: v-bind("imageUrls.avatar");
}
.rank-container .txt-nickname {
color: white;
font-size: 20px;
text-align: center; text-align: center;
padding: 40px;
} }
/* ========== btn-next ========== */
.btn-next { .btn-next {
position: absolute; position: absolute;
bottom: 100px; bottom: 100px;
......
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