Commit 83aad560 authored by 董政锦's avatar 董政锦

Merge branch 'game3-PC马数据和位置问题、开始游戏时的闪灰底问题;' into 'main'

fix: game3 游戏页闪灰底问题; See merge request !14
parents 3ad7c03b c7cf6e57
......@@ -440,43 +440,40 @@ const rankCloseHandler = () => {
</template>
<style scoped>
.rule-container {
.rule-txt-container {
background: v-bind("imageUrls.rule") center / cover no-repeat;
width: 692px;
height: 797px;
margin-top: -20%;
transform: scale(0.5);
.rule-title {
text-align: center;
color: white;
font-weight: bold;
font-size: 26pt;
line-height: 50pt;
letter-spacing: 4px;
}
.rule-txt-container {
background: v-bind('imageUrls.rule') center / cover no-repeat;
width: 692px;
height: 797px;
margin-top: -20%;
transform: scale(0.5);
.rule-title {
text-align: center;
color: white;
font-weight: bold;
font-size: 26pt;
line-height: 50pt;
letter-spacing: 4px;
}
.rule-close {
width: 57px;
height: 57px;
background: v-bind('imageUrls.close') center / cover no-repeat;
transform: translateX(-50%) scale(1.5);
position: absolute;
top: -73px;
left: 100%;
margin-left: -48px;
}
}
.rule-txt {
font-size: 26pt;
padding: 40px;
margin-top: 10px;
color: #AA0000;
}
.rule-close {
width: 57px;
height: 57px;
background: v-bind("imageUrls.close") center / cover no-repeat;
transform: translateX(-50%) scale(1.4);
position: absolute;
bottom: -75px;
left: 50%;
}
.rule-close {
width: 57px;
height: 57px;
background: v-bind('imageUrls.close') center / cover no-repeat;
transform: translateX(-50%) scale(1.5);
position: absolute;
top: -73px;
left: 100%;
margin-left: -48px;
}
}
}
.ranklist-container {
......
......@@ -86,6 +86,34 @@ export function $is_run_local(): boolean {
return false;
}
const LOCAL_MODE_KEY = 'fc6_local_mode';
/** 获取当前模式:localStorage 优先 > 自动检测 */
export function $is_local_mode(): boolean {
const stored = localStorage.getItem(LOCAL_MODE_KEY);
if (stored === '1') return true;
if (stored === '0') return false;
return $is_run_local();
}
/** 设置模式:'1'=本地模拟, '0'=线上WS, 其他=清除恢复自动 */
export function $set_local_mode(val: string) {
if (val === '1' || val === '0') {
localStorage.setItem(LOCAL_MODE_KEY, val);
} else {
localStorage.removeItem(LOCAL_MODE_KEY);
}
location.reload();
}
// 暴露到 window 方便开发调试
if (typeof window !== 'undefined') {
(window as any).__fc6LocalMode = (val?: string) => {
if (val !== undefined) $set_local_mode(val);
return $is_local_mode() ? '本地模拟' : '线上WS';
};
}
export function $query(q: string | string[]): string | string[] {
const query = location.href.match(/\?([^#]*)/)?.[1]?.replace(/\/$/, '');
const params = new URLSearchParams(query);
......
......@@ -145,7 +145,8 @@ onBeforeUnmount(() => {
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.2);
/* 用径向渐变:只在数字周围微暗,四角完全透明 → 保留背景图可见 */
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.15) 0%, transparent 70%);
pointer-events: none;
}
......
......@@ -7,7 +7,7 @@ import Rank2 from './views/Rank2View.vue'
import { useAdminGameSocket } from '@/composables/useAdminGameSocket'
import type Player from '@/commons/player.ts'
import { playApplauseMusic, playGame6Music, stopAllMusic, stopGame6Music } from '@/commons/music'
import { $confirm, $remove_socket_storage, $notify, $toast } from '@/commons/utils.ts'
import { $confirm, $is_local_mode, $remove_socket_storage, $notify, $toast } from '@/commons/utils.ts'
const router = useRouter()
......@@ -231,8 +231,12 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
})
const startGameWithMusic = () => {
// 本地调试模式:跳过 WebSocket,直接进入赛马画面
if ($is_local_mode()) {
gotoRank1WithIntro()
return
}
if (playerCount.value == 0) {
// alert('房间中没有玩家')
$toast('房间中没有玩家');
return;
}
......
......@@ -2,7 +2,7 @@
import { ref, watch, onMounted, onUnmounted } from 'vue'
import DesignStage from '../../../components/DesignStage.vue'
import type Player from '../../../commons/player.ts'
import { $format_str, $is_run_local } from '@/commons/utils.ts'
import { $format_str, $is_local_mode } from '@/commons/utils.ts'
import { assetUrl, cssAssetUrl } from '@/commons/assets.ts'
import { playApplauseMusic, stopApplauseMusic } from '@/commons/music'
......@@ -44,7 +44,7 @@ const imageUrls = {
const HORSE_SIZE = 280;
const HORSE_START_X = -HORSE_SIZE;
const HORSE_END_X = 1920;
const HORSE_Y_OFFSET = 80; // 马匹整体向下偏移,补偿帧图片中马匹偏上的空白区域
const HORSE_Y_OFFSET = 50; // 马匹整体偏移
const horseFrameConfigs = [
{ type: 1, dir: 'game3/ma1', prefix: '1ma_', startIndex: 24, count: 12 },
......@@ -127,9 +127,11 @@ const detectScoreChanges = (players: Player[]) => {
if (newScore > prev) {
const current = updated[key] || 0;
updated[key] = Math.min(current + BOOST_PULSE, MAX_BOOST);
// boost 量与分数增量成正比,让领先者拉得更快,制造视觉差距
const delta = newScore - prev;
updated[key] = Math.min(current + BOOST_PULSE * Math.max(delta, 1), MAX_BOOST);
hasNewBoost = true;
console.log(`[game3 Rank1View] 🚀 ${p.nickname} score ${prev}${newScore}, boost: ${updated[key].toFixed(1)}`);
console.log(`[game3 Rank1View] 🚀 ${p.nickname} score ${prev}${newScore}${delta}), boost: ${updated[key].toFixed(1)}`);
}
prevScores[key] = newScore;
......@@ -143,6 +145,8 @@ const detectScoreChanges = (players: Player[]) => {
watch(
() => props.rankList,
(rankList) => {
// 本地模式:无 WS 数据时不覆盖本地模拟数据
if ($is_local_mode() && (!rankList || rankList.length === 0)) return;
console.log('[game3 Rank1View] websocket rankList 数据:', JSON.parse(JSON.stringify(rankList?.slice(0, 3))));
updateRankList(rankList);
// 检测积分增长 → 触发瞬时加速脉冲(对齐 game4)
......@@ -276,7 +280,7 @@ const stopHorseLoop = () => {
};
// ========== 生成/更新马匹(对齐 game4 updateHorses 模式,保留已有马匹进度) ==========
const LANE_TOP_POSITIONS = [480, 640, 800];
const LANE_TOP_POSITIONS = [310, 510, 720];
const updateHorses = (players: Player[]) => {
const validPlayers = players.filter(p => {
......@@ -340,7 +344,6 @@ const startIntro = async () => {
// 重置加速状态
transientBoosts.value = {};
Object.keys(prevScores).forEach(k => delete prevScores[k]);
stopApplauseMusic();
preloadHorseFrames();
const countdownPromise = designStage.value?.startCountdown(3, 60);
......@@ -386,31 +389,56 @@ const renderAvatar = (item: any | null) => {
onMounted(() => {
preloadHorseFrames();
if ($is_run_local()) {
// 本地模式:用模拟玩家填充 list,驱动马匹渲染
if ($is_local_mode()) {
// 本地模式:预填10个模拟玩家数据,由 startIntro 流程驱动赛马
const mockAvatars = [
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Felix',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Aneka',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Salem',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Midnight',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Lucky',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Bandit',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Misty',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Pepper',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Oreo',
'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Tiger',
];
list.value = [
{ userid: 'local-1', nickname: '骑手一', avatar: '', score: 45 },
{ userid: 'local-2', nickname: '骑手二', avatar: '', score: 38 },
{ userid: 'local-3', nickname: '骑手三', avatar: '', score: 30 },
{ userid: 'local-4', nickname: '骑手四', avatar: '', score: 22 },
{ userid: 'local-5', nickname: '骑手五', avatar: '', score: 15 },
{ userid: 'local-1', nickname: '疾风骑士', avatar: mockAvatars[0], score: 45 },
{ userid: 'local-2', nickname: '闪电侠', avatar: mockAvatars[1], score: 38 },
{ userid: 'local-3', nickname: '追风者', avatar: mockAvatars[2], score: 30 },
{ userid: 'local-4', nickname: '千里马', avatar: mockAvatars[3], score: 22 },
{ userid: 'local-5', nickname: '飞毛腿', avatar: mockAvatars[4], score: 15 },
{ userid: 'local-6', nickname: '烈焰驹', avatar: mockAvatars[5], score: 52 },
{ userid: 'local-7', nickname: '暴风战士', avatar: mockAvatars[6], score: 41 },
{ userid: 'local-8', nickname: '神行者', avatar: mockAvatars[7], score: 35 },
{ userid: 'local-9', nickname: '银鞍客', avatar: mockAvatars[8], score: 28 },
{ userid: 'local-10', nickname: '踏雪无痕', avatar: mockAvatars[9], score: 18 },
];
gameStarted.value = true;
isGameRunning.value = true;
updateHorses(list.value);
startHorseLoop();
// 模拟分数变化 → 驱动 detectScoreChanges
let simTick = 0;
const simInterval = setInterval(() => {
if (!isGameRunning.value) { clearInterval(simInterval); return; }
simTick++;
for (const p of list.value) {
if (typeof p.score === 'number') {
p.score += Math.floor(Math.random() * 3);
}
// 每匹马不同的基础增速:领先者(高分)增速更高,自然拉开差距
const growthRates: Record<string, number> = {};
list.value.forEach((p, i) => {
// 高分马增速 1.4~1.8x,低分马 0.6~1.0x,制造持久速度差异
growthRates[p.userid!] = 0.4 + (i / (list.value.length - 1)) * 1.4;
});
// 跟随 isGameRunning 自动管理模拟分数组件
let simInterval: ReturnType<typeof setInterval> | undefined;
watch(isGameRunning, (running) => {
if (simInterval) { clearInterval(simInterval); simInterval = undefined; }
if (running) {
simInterval = setInterval(() => {
if (!isGameRunning.value) { clearInterval(simInterval); simInterval = undefined; return; }
for (const p of list.value) {
if (typeof p.score === 'number' && p.score < 120 && p.userid) {
const rate = growthRates[p.userid] || 1.0;
const growth = Math.max(1, Math.floor((Math.random() * 3 + 1) * rate));
p.score += growth;
}
}
detectScoreChanges(list.value);
}, 1500);
}
detectScoreChanges(list.value);
}, 1500);
}, { immediate: true });
}
});
......
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