update:优化比赛

This commit is contained in:
2026-07-09 11:43:06 +08:00
parent af07d09ab6
commit f8efe4c4a4
9 changed files with 130 additions and 86 deletions
+33 -2
View File
@@ -13,8 +13,9 @@ import TestDistance from "@/components/TestDistance.vue";
import SModal from "@/components/SModal.vue";
import audioManager from "@/audioManager";
import { getBattleAPI, laserCloseAPI } from "@/apis";
import { connectMatchWebSocket } from "@/matchWebsocket";
import { closeMatchWebSocket, connectMatchWebSocket } from "@/matchWebsocket";
import { MESSAGETYPESV2 } from "@/constants";
import { takeMatchReturnSnapshot } from "@/utils/matchReturn";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
@@ -46,6 +47,8 @@ let halfRestTimer = null;
const showOfflineModal = ref(false);
/** 记录每位玩家当前半场连续 10 环及以上次数,key 为 playerId,用于触发 tententen 音效 */
const xRingStreaks = ref({});
let battleEnded = false;
let skipNextRestoreOnShow = false;
function clearHalfRestCountdown() {
if (halfRestTimer) {
@@ -164,6 +167,11 @@ function reconnectMatchServer(battleInfo) {
});
}
function closeBattleServer(reason) {
if (battleEnded) return;
closeMatchWebSocket({ reason });
}
/**
* 监听设备在线状态,大乱斗比赛进行中设备离线时弹窗提示用户
*/
@@ -176,6 +184,9 @@ watch(online, (newVal, oldVal) => {
function recoverData(battleInfo, { force = false } = {}) {
battleInfo = normalizeBattleInfo(battleInfo);
if (!battleInfo) return;
if (battleInfo.status !== undefined) {
battleEnded = [2, 4].includes(Number(battleInfo.status));
}
try {
if (battleInfo.way === 1) title.value = "好友约战 - 大乱斗";
if (battleInfo.way === 2) title.value = "排位赛 - 大乱斗";
@@ -250,7 +261,16 @@ function recoverData(battleInfo, { force = false } = {}) {
}
onLoad(async (options) => {
if (options.battleId) battleId.value = options.battleId;
const returnSnapshot = options.fromReturn ? takeMatchReturnSnapshot() : null;
skipNextRestoreOnShow = false;
if (returnSnapshot?.matchId) battleId.value = returnSnapshot.matchId;
else if (options.battleId) battleId.value = options.battleId;
if (returnSnapshot) {
skipNextRestoreOnShow = true;
reconnectMatchServer(returnSnapshot);
recoverData(returnSnapshot, { force: true });
return;
}
const readySnapshot = takeReadySnapshot(battleId.value);
if (readySnapshot?.status === 0) recoverData(readySnapshot);
// uni.enableAlertBeforeUnload({
@@ -325,6 +345,7 @@ async function onReceiveMessage(msg) {
tips.value = "准备下半场";
startHalfRestCountdown();
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
battleEnded = true;
setTimeout(() => {
// 全部跳转到新结算页
uni.redirectTo({
@@ -346,14 +367,24 @@ onBeforeUnmount(() => {
});
clearHalfRestCountdown();
uni.$off("socket-inbox", onReceiveMessage);
closeBattleServer("melee-battle-unmount");
audioManager.stopAll();
});
onHide(() => {
closeBattleServer("melee-battle-hide");
});
onShow(async () => {
if (skipNextRestoreOnShow) {
skipNextRestoreOnShow = false;
return;
}
if (battleId.value) {
const result = normalizeBattleInfo(await getBattleAPI(battleId.value));
if (!result) return;
if (result.status === 2) {
battleEnded = true;
uni.showToast({
title: "比赛已结束",
icon: "none",
@@ -4,6 +4,7 @@ import { onShow } from "@dcloudio/uni-app";
import { getBattleAPI, getUserGameState } from "@/apis";
import { debounce } from "@/util";
import { returnToBattle } from "@/utils/matchReturn";
import useStore from "@/store";
import { storeToRefs } from "pinia";
@@ -67,11 +68,7 @@ const onClick = debounce(async () => {
const result = await getBattleAPI();
if (result && result.matchId) {
await uni.$checkAudio();
if (result.mode <= 3) {
await navigateOnce(`/pages/team-battle/index?battleId=${result.matchId}`);
} else {
await navigateOnce(`/pages/melee-battle?battleId=${result.matchId}`);
}
await returnToBattle(result, navigateOnce);
return;
}
if (game.value.roomID) {
+11 -9
View File
@@ -7,6 +7,7 @@ import ScreenHint from "./ScreenHint.vue";
import BackToGame from "./BackToGame.vue";
import {laserAimAPI, getBattleAPI, matchGameAPI} from "@/apis";
import { capsuleHeight, debounce } from "@/util";
import { returnToBattle } from "@/utils/matchReturn";
import AudioManager from "@/audioManager";
const props = defineProps({
title: {
@@ -120,6 +121,15 @@ onShow(() => {
showHint.value = false;
});
const navigateTo = (url) =>
new Promise((resolve, reject) => {
uni.navigateTo({
url,
success: resolve,
fail: reject,
});
});
const backToGame = debounce(async () => {
if (isLoading.value) return; // 防止重复点击
@@ -128,15 +138,7 @@ const backToGame = debounce(async () => {
const result = await getBattleAPI();
if (result && result.matchId) {
await checkAudioProgress();
if (result.mode <= 3) {
uni.navigateTo({
url: `/pages/team-battle/index?battleId=${result.matchId}`,
});
} else {
uni.navigateTo({
url: `/pages/melee-battle?battleId=${result.matchId}`,
});
}
await returnToBattle(result, navigateTo);
}
} catch (error) {
console.error("获取当前游戏失败:", error);
+27 -2
View File
@@ -13,9 +13,14 @@ import TeamAvatars from "./components/TeamAvatars.vue";
import ShootProgress2 from "./components/ShootProgress2.vue";
import SModal from "./components/SModal.vue";
import { laserCloseAPI, getBattleAPI } from "@/apis";
import { connectMatchWebSocket, MATCH_WS_AUDIO_ACK_EVENT } from "@/matchWebsocket";
import {
closeMatchWebSocket,
connectMatchWebSocket,
MATCH_WS_AUDIO_ACK_EVENT,
} from "@/matchWebsocket";
import { MESSAGETYPESV2 } from "@/constants";
import { getDirectionText } from "@/util";
import { takeMatchReturnSnapshot } from "@/utils/matchReturn";
import audioManager, {
AUDIO_INTERRUPTION_BEGIN_EVENT,
AUDIO_INTERRUPTION_END_EVENT,
@@ -98,6 +103,7 @@ let restoreLoadingTimer = null;
let pendingRoundAudio = false;
// 一旦收到 BattleEnd,后续普通消息就不再进入队列。
let battleEnded = false;
let skipNextRestoreOnShow = false;
const handledMessageKeys = new Set();
const handledMessageKeyOrder = [];
const queuedMessageKeys = new Set();
@@ -557,6 +563,11 @@ function handleBattleRecovered() {
scheduleRestoreLatestBattle();
}
function closeBattleServer(reason) {
if (battleEnded) return;
closeMatchWebSocket({ reason });
}
// 队伍信息优先用接口返回值;接口缺失时使用本地缓存,避免重进页面时头像为空。
function loadTeamPlayers(teamInfo, storageKey) {
if (Array.isArray(teamInfo?.players)) return [...teamInfo.players];
@@ -1205,10 +1216,12 @@ function onReceiveMessage(message) {
// 新对局入口:彻底清空上一局残留的状态、队列和缓存。
onLoad((options) => {
console.log('重新进入了')
const returnSnapshot = options.fromReturn ? takeMatchReturnSnapshot() : null;
skipNextRestoreOnShow = false;
// 新对局入口:把所有会串场的状态、队列、时间戳和缓存一次性清空。
start.value = null;
tips.value = "";
battleId.value = options.battleId || "";
battleId.value = returnSnapshot?.matchId || options.battleId || "";
currentRound.value = 0;
roundTipRound.value = 0;
goldenRound.value = 0;
@@ -1246,6 +1259,12 @@ onLoad((options) => {
store.updateShotInfo(0, 0);
store.updateTips("");
latestShotFlash.value = null;
if (returnSnapshot) {
skipNextRestoreOnShow = true;
applyBattleSnapshot(returnSnapshot, { restore: true });
reconnectMatchServer(returnSnapshot);
return;
}
const readySnapshot = takeReadySnapshot(battleId.value);
if (readySnapshot?.status === 0) {
applyBattleSnapshot(readySnapshot, { restore: true });
@@ -1282,6 +1301,7 @@ onBeforeUnmount(() => {
}
hideRestoreLoading();
invalidateBattleQueue({ stopAudio: true, stopProgress: true });
closeBattleServer("team-battle-unmount");
console.log('onBeforeUnmount', '页面卸载前')
audioManager.stopAll();
uni.$off(AUDIO_INTERRUPTION_BEGIN_EVENT, handleBattleCovered);
@@ -1291,11 +1311,16 @@ onBeforeUnmount(() => {
onHide(()=>{
console.log('onHide', '页面大退')
handleBattleCovered();
closeBattleServer("team-battle-hide");
})
// 每次回到前台都重新拉最新比赛快照,确保画面与后端一致。
onShow(() => {
console.log('onshow')
if (skipNextRestoreOnShow) {
skipNextRestoreOnShow = false;
return;
}
scheduleRestoreLatestBattle();
});
</script>