新版房间1v1对战数据调试完成

This commit is contained in:
kron
2026-02-04 17:45:57 +08:00
parent a2674aae5b
commit 7f73f3ebb3
18 changed files with 524 additions and 843 deletions

View File

@@ -6,7 +6,7 @@ try {
switch (envVersion) { switch (envVersion) {
case "develop": // 开发版 case "develop": // 开发版
// BASE_URL = "http://192.168.1.242:8000/api/shoot"; // BASE_URL = "http://192.168.1.30:8000/api/shoot";
BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
break; break;
case "trial": // 体验版 case "trial": // 体验版
@@ -418,9 +418,9 @@ export const getUserGameState = () => {
}; };
export const getCurrentGameAPI = async () => { export const getCurrentGameAPI = async () => {
uni.$emit("update-header-loading", true); // uni.$emit("update-header-loading", true);
const result = await request("GET", "/user/join/battle"); // const result = await request("GET", "/user/join/battle");
return result.currentGame || {}; // return result.currentGame || {};
}; };
export const getPointBookConfigAPI = async () => { export const getPointBookConfigAPI = async () => {
@@ -552,3 +552,10 @@ export const getReadyAPI = (roomId) => {
roomId, roomId,
}); });
}; };
export const getBattleAPI = async (battleId) => {
const result = await request("POST", "/user/match/info", {
id: battleId,
});
return result;
};

View File

@@ -2,7 +2,7 @@
import { ref, watch, onMounted, onBeforeUnmount } from "vue"; import { ref, watch, onMounted, onBeforeUnmount } from "vue";
import { onShow } from "@dcloudio/uni-app"; import { onShow } from "@dcloudio/uni-app";
import { getCurrentGameAPI, getUserGameState } from "@/apis"; import { getBattleAPI, getUserGameState } from "@/apis";
import { debounce } from "@/util"; import { debounce } from "@/util";
import useStore from "@/store"; import useStore from "@/store";
@@ -44,10 +44,21 @@ const onClick = debounce(async () => {
if (loading.value) return; if (loading.value) return;
try { try {
loading.value = true; loading.value = true;
if (game.value.inBattle) { const result = await getBattleAPI();
await uni.$checkAudio(); if (result && result.matchId) {
const result = await getCurrentGameAPI(); // await uni.$checkAudio();
} else if (game.value.roomID) { if (result.way === 1) {
uni.navigateTo({
url: `/pages/team-battle?battleId=${result.matchId}`,
});
} else if (result.way === 2) {
uni.navigateTo({
url: `/pages/melee-match?battleId=${result.matchId}`,
});
}
return;
}
if (game.value.roomID) {
uni.navigateTo({ uni.navigateTo({
url: "/pages/battle-room?roomNumber=" + game.value.roomID, url: "/pages/battle-room?roomNumber=" + game.value.roomID,
}); });

View File

@@ -22,9 +22,10 @@ const props = defineProps({
}, },
}); });
const normalRounds = computed( const normalRounds = computed(() => {
() => props.roundResults.length - props.goldenRound const count = props.roundResults.findIndex((item) => !!item.ifGold);
); return count > 0 ? count : props.roundResults.length;
});
</script> </script>
<template> <template>
@@ -59,8 +60,8 @@ const normalRounds = computed(
</block> </block>
<view> <view>
<text>{{ <text>{{
result.blueArrows.length result.shoots[1] && result.shoots[1].length
? result.blueArrows ? result.shoots[1]
.map((item) => item.ring) .map((item) => item.ring)
.reduce((last, next) => last + next, 0) .reduce((last, next) => last + next, 0)
: "" : ""
@@ -94,8 +95,8 @@ const normalRounds = computed(
</block> </block>
<view> <view>
<text>{{ <text>{{
result.redArrows.length result.shoots[2] && result.shoots[2].length
? result.redArrows ? result.shoots[2]
.map((item) => item.ring) .map((item) => item.ring)
.reduce((last, next) => last + next, 0) .reduce((last, next) => last + next, 0)
: "" : ""

View File

@@ -2,7 +2,7 @@
import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue"; import { ref, watch, onMounted, onBeforeUnmount, computed } from "vue";
import PointSwitcher from "@/components/PointSwitcher.vue"; import PointSwitcher from "@/components/PointSwitcher.vue";
import { MESSAGETYPES } from "@/constants"; import { MESSAGETYPES, MESSAGETYPESV2 } from "@/constants";
import { simulShootAPI } from "@/apis"; import { simulShootAPI } from "@/apis";
import useStore from "@/store"; import useStore from "@/store";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
@@ -108,28 +108,26 @@ const arrowStyle = computed(() => {
}; };
}); });
async function onReceiveMessage(messages = []) { async function onReceiveMessage(message) {
messages.forEach((msg) => { if (Array.isArray(message)) return;
if (message.type === MESSAGETYPESV2.ShootResult && message.shootData) {
if ( if (
msg.constructor === MESSAGETYPES.ShootSyncMeArrowID || message.shootData.playerId === user.value.id &&
msg.constructor === MESSAGETYPES.ShootResult !message.shootData.ring &&
message.shootData.angle >= 0
) { ) {
if ( angle.value = null;
msg.userId === user.value.id && setTimeout(() => {
!msg.target.ring && if (props.scores[0]) {
msg.target.angle >= 0 circleColor.value =
) { message.shootData.playerId === props.scores[0].playerId
angle.value = null; ? "#ff4444"
setTimeout(() => { : "#1840FF";
if (props.scores[0]) { }
circleColor.value = angle.value = message.shootData.angle;
msg.userId === props.scores[0].playerId ? "#ff4444" : "#1840FF"; }, 200);
}
angle.value = msg.target.angle;
}, 200);
}
} }
}); }
} }
onMounted(() => { onMounted(() => {

View File

@@ -32,18 +32,21 @@ const createRoom = debounce(async () => {
if (battleMode.value === 2) size = 10; if (battleMode.value === 2) size = 10;
if (battleMode.value === 3) size = 4; if (battleMode.value === 3) size = 4;
if (battleMode.value === 4) size = 6; if (battleMode.value === 4) size = 6;
const result = await createRoomAPI( try {
battleMode.value === 2 ? 2 : 1, const result = await createRoomAPI(
battleMode.value === 2 ? 10 : size battleMode.value === 2 ? 2 : 1,
); battleMode.value === 2 ? 10 : size
if (result.number) { );
props.onConfirm(); if (result.number) {
await joinRoomAPI(result.number); props.onConfirm();
uni.navigateTo({ await joinRoomAPI(result.number);
url: "/pages/battle-room?roomNumber=" + result.number, uni.navigateTo({
}); url: "/pages/battle-room?roomNumber=" + result.number,
});
}
} finally {
loading.value = false;
} }
loading.value = false;
}); });
</script> </script>
<template> <template>

View File

@@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref, watch, onMounted, onBeforeUnmount } from "vue"; import { ref, watch, onMounted, onBeforeUnmount } from "vue";
import audioManager from "@/audioManager"; import audioManager from "@/audioManager";
import { MESSAGETYPES } from "@/constants"; import { MESSAGETYPES, MESSAGETYPESV2 } from "@/constants";
import { getDirectionText } from "@/util"; import { getDirectionText } from "@/util";
import useStore from "@/store"; import useStore from "@/store";
@@ -26,9 +26,8 @@ watch(
let key = []; let key = [];
if (newVal.includes("重回")) return; if (newVal.includes("重回")) return;
if (currentRoundEnded.value) { if (currentRoundEnded.value) {
currentRound.value += 1;
// 播放当前轮次语音 // 播放当前轮次语音
key.push(`${["一", "二", "三", "四", "五"][currentRound.value - 1]}`); key.push(`${["一", "二", "三", "四", "五"][currentRound.value]}`);
} }
key.push( key.push(
newVal.includes("你") newVal.includes("你")
@@ -47,80 +46,112 @@ const updateSound = () => {
audioManager.setMuted(!sound.value); audioManager.setMuted(!sound.value);
}; };
async function onReceiveMessage(messages = []) { async function onReceiveMessage(message) {
if (ended.value) return; if (ended.value) return;
messages.forEach((msg) => { if (Array.isArray(message)) {
if (msg.constructor === MESSAGETYPES.ShootResult) { message.forEach((msg) => {
if (melee.value && msg.userId !== user.value.id) return; // if (msg.constructor === MESSAGETYPES.ShootResult) {
if (msg.userId === user.value.id) currentShot.value++; // if (melee.value && msg.userId !== user.value.id) return;
if (msg.battleInfo && msg.userId === user.value.id) { // if (msg.userId === user.value.id) currentShot.value++;
const players = [ // if (msg.battleInfo && msg.userId === user.value.id) {
...(msg.battleInfo.blueTeam || []), // const players = [
...(msg.battleInfo.redTeam || []), // ...(msg.battleInfo.blueTeam || []),
]; // ...(msg.battleInfo.redTeam || []),
const currentPlayer = players.find((p) => p.id === msg.userId); // ];
currentShot.value = 0; // const currentPlayer = players.find((p) => p.id === msg.userId);
try { // currentShot.value = 0;
if ( // try {
currentPlayer && // if (
currentPlayer.shotHistory && // currentPlayer &&
currentPlayer.shotHistory[msg.battleInfo.currentRound] // currentPlayer.shotHistory &&
) { // currentPlayer.shotHistory[msg.battleInfo.currentRound]
currentShot.value = // ) {
currentPlayer.shotHistory[msg.battleInfo.currentRound].length; // currentShot.value =
} // currentPlayer.shotHistory[msg.battleInfo.currentRound].length;
} catch (_) {} // }
} // } catch (_) {}
if (!halfTime.value && msg.target) { // }
let key = []; // if (!halfTime.value && msg.target) {
key.push(msg.target.ring ? `${msg.target.ring}` : "未上靶"); // let key = [];
if (!msg.target.ring) // key.push(msg.target.ring ? `${msg.target.ring}环` : "未上靶");
key.push(`${getDirectionText(msg.target.angle)}调整`); // if (!msg.target.ring)
audioManager.play(key); // key.push(`向${getDirectionText(msg.target.angle)}调整`);
} // audioManager.play(key);
} else if (msg.constructor === MESSAGETYPES.InvalidShot) { // }
if (msg.userId === user.value.id) { // } else
uni.showToast({ // if (msg.constructor === MESSAGETYPES.InvalidShot) {
title: "距离不足,无效", // if (msg.userId === user.value.id) {
icon: "none", // uni.showToast({
}); // title: "距离不足,无效",
audioManager.play("射击无效"); // icon: "none",
} // });
} else if (msg.constructor === MESSAGETYPES.AllReady) { // audioManager.play("射击无效");
const { config } = msg.groupUserStatus; // }
if (config && config.mode === 1) { // }
totalShot.value = config.teamSize === 2 ? 3 : 2; // else if (msg.constructor === MESSAGETYPES.AllReady) {
} // const { config } = msg.groupUserStatus;
currentRoundEnded.value = true; // if (config && config.mode === 1) {
audioManager.play("比赛开始"); // totalShot.value = config.teamSize === 2 ? 3 : 2;
} else if (msg.constructor === MESSAGETYPES.MeleeAllReady) { // }
melee.value = true; // currentRoundEnded.value = true;
halfTime.value = false; // audioManager.play("比赛开始");
audioManager.play("比赛开始"); // } else if (msg.constructor === MESSAGETYPES.MeleeAllReady) {
} else if (msg.constructor === MESSAGETYPES.CurrentRoundEnded) { // melee.value = true;
currentShot.value = 0; // halfTime.value = false;
if (msg.preRoundResult && msg.preRoundResult.currentRound) { // audioManager.play("比赛开始");
currentRound.value = msg.preRoundResult.currentRound; // } else if (msg.constructor === MESSAGETYPES.CurrentRoundEnded) {
currentRoundEnded.value = true; // currentShot.value = 0;
} // if (msg.preRoundResult && msg.preRoundResult.currentRound) {
} else if (msg.constructor === MESSAGETYPES.HalfTimeOver) { // currentRound.value = msg.preRoundResult.currentRound;
halfTime.value = true; // currentRoundEnded.value = true;
audioManager.play("中场休息"); // }
} else if (msg.constructor === MESSAGETYPES.MatchOver) { // } else if (msg.constructor === MESSAGETYPES.HalfTimeOver) {
audioManager.play("比赛结束"); // halfTime.value = true;
} else if (msg.constructor === MESSAGETYPES.FinalShoot) { // audioManager.play("中场休息");
totalShot.value = 0; // } else if (msg.constructor === MESSAGETYPES.MatchOver) {
audioManager.play("决金箭轮"); // audioManager.play("比赛结束");
tips.value = "即将开始..."; // } else if (msg.constructor === MESSAGETYPES.FinalShoot) {
currentRoundEnded.value = false; // totalShot.value = 0;
} else if (msg.constructor === MESSAGETYPES.MatchOver) { // audioManager.play("决金箭轮");
ended.value = true; // tips.value = "即将开始...";
} else if (msg.constructor === MESSAGETYPES.BackToGame) { // currentRoundEnded.value = false;
if (msg.battleInfo) { // } else if (msg.constructor === MESSAGETYPES.MatchOver) {
melee.value = msg.battleInfo.config.mode === 2; // ended.value = true;
} // } else if (msg.constructor === MESSAGETYPES.BackToGame) {
// if (msg.battleInfo) {
// melee.value = msg.battleInfo.config.mode === 2;
// }
// }
});
return;
}
if (message.type === MESSAGETYPESV2.BattleStart) {
melee.value = Boolean(message.mode);
totalShot.value = message.mode === 1 ? 3 : 2;
currentRoundEnded.value = true;
audioManager.play("比赛开始");
}
if (message.type === MESSAGETYPESV2.BattleEnd) {
audioManager.play("比赛结束");
}
if (message.type === MESSAGETYPESV2.ShootResult) {
if (melee.value && message.current.playerId !== user.value.id) return;
if (message.current.playerId === user.value.id) currentShot.value++;
if (message.shootData) {
let key = [];
key.push(
message.shootData.ring ? `${message.shootData.ring}` : "未上靶"
);
if (!message.shootData.ring)
key.push(`${getDirectionText(message.shootData.angle)}调整`);
audioManager.play(key, false);
} }
}); }
if (message.type === MESSAGETYPESV2.NewRound) {
currentShot.value = 0;
currentRound.value = message.current.round;
currentRoundEnded.value = true;
}
} }
const playSound = (key) => { const playSound = (key) => {

View File

@@ -52,14 +52,14 @@ onBeforeUnmount(() => {
<view class="point-view1" v-if="bluePoint !== 0 || redPoint !== 0"> <view class="point-view1" v-if="bluePoint !== 0 || redPoint !== 0">
<text>本轮蓝队</text> <text>本轮蓝队</text>
<text>{{ <text>{{
(roundData.blueArrows || []).reduce( (roundData.shoots[1] || []).reduce(
(last, next) => last + next.ring, (last, next) => last + next.ring,
0 0
) )
}}</text> }}</text>
<text>红队</text> <text>红队</text>
<text>{{ <text>{{
(roundData.redArrows || []).reduce( (roundData.shoots[2] || []).reduce(
(last, next) => last + next.ring, (last, next) => last + next.ring,
0 0
) )

View File

@@ -179,13 +179,13 @@ const playSound = (key) => {
}; };
onMounted(() => { onMounted(() => {
uni.$on("update-ramain", resetTimer); uni.$on("update-remain", resetTimer);
uni.$on("socket-inbox", onReceiveMessage); uni.$on("socket-inbox", onReceiveMessage);
uni.$on("play-sound", playSound); uni.$on("play-sound", playSound);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
uni.$off("update-ramain", resetTimer); uni.$off("update-remain", resetTimer);
uni.$off("socket-inbox", onReceiveMessage); uni.$off("socket-inbox", onReceiveMessage);
uni.$off("play-sound", playSound); uni.$off("play-sound", playSound);
if (timer.value) clearInterval(timer.value); if (timer.value) clearInterval(timer.value);

View File

@@ -19,6 +19,18 @@ const props = defineProps({
const barColor = ref(""); const barColor = ref("");
const remain = ref(15); const remain = ref(15);
const timer = ref(null); const timer = ref(null);
const laoding = ref(false);
const updateRemain = (value) => {
// if (Math.ceil(value) === remain.value || Math.floor(value) === remain.value)
// return;
if (timer.value) clearInterval(timer.value);
remain.value = Math.round(value);
timer.value = setInterval(() => {
laoding.value = remain.value === 0;
if (remain.value > 0) remain.value--;
}, 1000);
};
watch( watch(
() => props.tips, () => props.tips,
@@ -29,11 +41,7 @@ watch(
barColor.value = "linear-gradient( 180deg, #9AB3FF 0%, #4288FF 100%)"; barColor.value = "linear-gradient( 180deg, #9AB3FF 0%, #4288FF 100%)";
if (newVal.includes("重回")) return; if (newVal.includes("重回")) return;
if (newVal.includes("红队") || newVal.includes("蓝队")) { if (newVal.includes("红队") || newVal.includes("蓝队")) {
if (timer.value) clearInterval(timer.value); updateRemain(props.total);
remain.value = props.total;
timer.value = setInterval(() => {
if (remain.value > 0) remain.value--;
}, 1000);
} }
}, },
{ {
@@ -41,22 +49,12 @@ watch(
} }
); );
const updateRemain = (value) => {
if (Math.ceil(value) === remain.value || Math.floor(value) === remain.value)
return;
if (timer.value) clearInterval(timer.value);
remain.value = Math.round(value);
timer.value = setInterval(() => {
if (remain.value > 0) remain.value--;
}, 1000);
};
onMounted(() => { onMounted(() => {
uni.$on("update-ramain", updateRemain); uni.$on("update-remain", updateRemain);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
uni.$off("update-ramain", updateRemain); uni.$off("update-remain", updateRemain);
if (timer.value) clearInterval(timer.value); if (timer.value) clearInterval(timer.value);
}); });
</script> </script>
@@ -76,7 +74,8 @@ onBeforeUnmount(() => {
right: tips.includes('红队') ? 0 : 'unset', right: tips.includes('红队') ? 0 : 'unset',
}" }"
/> />
<text>剩余{{ remain }}</text> <text v-if="!laoding">剩余{{ remain }}</text>
<text v-else>···</text>
</view> </view>
</view> </view>
</template> </template>

View File

@@ -19,12 +19,16 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
count: {
type: Number,
default: 15,
},
}); });
const arrow = ref({}); const arrow = ref({});
const distance = ref(0); const distance = ref(0);
const debugInfo = ref(""); const debugInfo = ref("");
const showsimul = ref(false); const showsimul = ref(false);
const count = ref(15); const count = ref(props.count);
const timer = ref(null); const timer = ref(null);
const updateTimer = (value) => { const updateTimer = (value) => {
@@ -44,6 +48,7 @@ onBeforeUnmount(() => {
}); });
async function onReceiveMessage(messages = []) { async function onReceiveMessage(messages = []) {
if (!Array.isArray(messages)) return;
messages.forEach((msg) => { messages.forEach((msg) => {
if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) { if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) {
arrow.value = msg.target; arrow.value = msg.target;

View File

@@ -30,12 +30,24 @@ export const MESSAGETYPES = {
SomeoneIsReady: 4168086628, SomeoneIsReady: 4168086628,
}; };
export const MESSAGETYPESV2 = {
AboutToStart: 1,
BattleStart: 2,
ToSomeoneShoot: 3,
ShootResult: 4,
NewRound: 5,
BattleEnd: 6,
};
export const topThreeColors = ["#FFD947", "#D2D2D2", "#FFA515"]; export const topThreeColors = ["#FFD947", "#D2D2D2", "#FFA515"];
export const getMessageTypeName = (id) => { export const getMessageTypeName = (id) => {
for (let key in MESSAGETYPES) { for (let key in MESSAGETYPES) {
if (MESSAGETYPES[key] === id) return key; if (MESSAGETYPES[key] === id) return key;
} }
for (let key in MESSAGETYPESV2) {
if (MESSAGETYPESV2[key] === id) return key;
}
return null; return null;
}; };

View File

@@ -1,9 +1,9 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, computed, onMounted } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import Avatar from "@/components/Avatar.vue"; import Avatar from "@/components/Avatar.vue";
import UserUpgrade from "@/components/UserUpgrade.vue"; import UserUpgrade from "@/components/UserUpgrade.vue";
import { getGameAPI } from "@/apis"; import { getBattleAPI } from "@/apis";
import { topThreeColors, getBattleResultTips } from "@/constants"; import { topThreeColors, getBattleResultTips } from "@/constants";
import audioManager from "@/audioManager"; import audioManager from "@/audioManager";
import useStore from "@/store"; import useStore from "@/store";
@@ -18,12 +18,7 @@ const totalPoints = ref(0);
const rank = ref(0); const rank = ref(0);
function exit() { function exit() {
const battleInfo = uni.getStorageSync("last-battle"); if (data.value.roomId) {
if (battleInfo && battleInfo.roomId) {
uni.redirectTo({
url: `/pages/battle-room?roomNumber=${battleInfo.roomId}`,
});
} else if (data.value.roomId) {
uni.redirectTo({ uni.redirectTo({
url: `/pages/battle-room?roomNumber=${data.value.roomId}`, url: `/pages/battle-room?roomNumber=${data.value.roomId}`,
}); });
@@ -33,128 +28,87 @@ function exit() {
} }
onLoad(async (options) => { onLoad(async (options) => {
if (!options.battleId) return;
const myId = user.value.id; const myId = user.value.id;
if (options.battleId) { const result = await getBattleAPI(options.battleId || "58351917302157312");
const result = await getGameAPI( data.value = result;
options.battleId || "BATTLE-1758270367040321900-868" if (result.winTeam) {
ifWin.value = result.teams[result.winTeam].players.some(
(p) => p.id === myId
); );
data.value = {
...result,
battleMode: result.gameMode,
};
if (result.mode === 1) {
data.value.redPlayers = Object.values(result.redPlayers);
data.value.bluePlayers = Object.values(result.bluePlayers);
if (result.redPlayers[myId]) {
totalPoints.value = result.redPlayers[myId].totalScore;
data.value.myTeam = result.redPlayers[myId].team;
ifWin.value = result.winner === 0;
}
if (result.bluePlayers[myId]) {
totalPoints.value = result.bluePlayers[myId].totalScore;
data.value.myTeam = result.bluePlayers[myId].team;
ifWin.value = result.winner === 1;
}
}
if (result.mode === 2) {
data.value.playerStats = result.players.map((p) => ({
...p,
id: p.playerId,
}));
const mine = result.players.find((p) => p.playerId === myId);
if (mine) totalPoints.value = mine.totalScore;
rank.value = result.players.findIndex((p) => p.playerId === myId) + 1;
}
} else {
const battleInfo = uni.getStorageSync("last-battle");
if (!battleInfo) return;
data.value = {
mvps: [],
...battleInfo,
};
if (battleInfo.mode === 1) {
battleInfo.playerStats.forEach((p) => {
if (p.team === 1) data.value.bluePlayers = [p];
if (p.team === 0) data.value.redPlayers = [p];
if (p.mvp) data.value.mvps.push(p);
});
data.value.mvps.sort((a, b) => b.totalRings - a.totalRings);
}
rank.value = 0;
const mine = battleInfo.playerStats.find((p, index) => {
rank.value = index + 1;
return p.id === myId;
});
if (mine) {
data.value.myTeam = mine.team;
totalPoints.value = mine.totalScore;
if (battleInfo.mode === 1) {
ifWin.value = mine.team === battleInfo.winner;
}
}
} }
if (data.value.mode === 1) { if (result.way === 1) {
audioManager.play(ifWin.value ? "胜利" : "失败"); audioManager.play(ifWin.value ? "胜利" : "失败");
} else if (data.value.mode === 2) { } else if (result.way === 2) {
if (data.value.battleMode === 1) { // if (data.value.battleMode === 1) {
if (rank.value <= data.value.playerStats.length * 0.3) { // if (rank.value <= data.value.playerStats.length * 0.3) {
audioManager.play("胜利"); // audioManager.play("胜利");
} // }
} else if (data.value.battleMode === 2) { // } else if (data.value.battleMode === 2) {
if (totalPoints.value > 0) { // if (totalPoints.value > 0) {
audioManager.play("胜利"); // audioManager.play("胜利");
} else if (totalPoints.value < 0) { // } else if (totalPoints.value < 0) {
audioManager.play("失败"); // audioManager.play("失败");
} // }
} // }
} }
}); });
const myTeam = computed(() => {
const teams = data.value.teams;
if (teams && teams.length) {
if (teams[1].players.some((p) => p.id === user.value.id)) return 1;
}
return 2;
});
const checkBowData = () => { const checkBowData = () => {
uni.navigateTo({ uni.navigateTo({
url: `/pages/match-detail?id=${data.value.id}`, url: `/pages/match-detail?id=${data.value.matchId}`,
}); });
}; };
</script> </script>
<template> <template>
<view class="container"> <view class="container">
<block v-if="data.mode === 1"> <block v-if="data.way === 1">
<view class="header-team" :style="{ marginTop: '25%' }"> <view class="header-team" :style="{ marginTop: '25%' }">
<image src="../static/battle-result.png" mode="widthFix" /> <image src="../static/battle-result.png" mode="widthFix" />
<view class="header-solo" v-if="data.teamSize === 2"> <view class="header-solo" v-if="data.mode === 1">
<text <text
:style="{ :style="{
background: background:
data.winner === 1 data.winTeam === 1
? 'linear-gradient(270deg, #3597ff 0%, rgba(0,0,0,0) 100%);' ? 'linear-gradient(270deg, #3597ff 0%, rgba(0,0,0,0) 100%);'
: 'linear-gradient(270deg, #fd4444 0%, rgba(0, 0, 0, 0) 100%)', : 'linear-gradient(270deg, #fd4444 0%, rgba(0, 0, 0, 0) 100%)',
}" }"
>{{ data.winner === 1 ? "蓝队" : "红队" }}获胜</text >{{ data.winTeam === 1 ? "蓝队" : "红队" }}获胜</text
> >
<Avatar <Avatar
:size="32" :size="32"
:src=" :src="
data.winner === 1 data.winTeam === 1
? data.bluePlayers[0].avatar ? data.teams[1].players[0].avatar
: data.redPlayers[0].avatar : data.teams[2].players[0].avatar
" "
:borderColor="data.winner === 1 ? '#5FADFF' : '#FF5656'" :borderColor="data.winTeam === 1 ? '#5FADFF' : '#FF5656'"
mode="widthFix" mode="widthFix"
/> />
</view> </view>
</view> </view>
<view class="header-mvp" v-if="data.teamSize !== 2"> <view class="header-mvp" v-if="data.mode === 2 || data.mode === 3">
<image <image
:src="`../static/${data.winner === 1 ? 'blue' : 'red'}-team-win.png`" :src="`../static/${data.winTeam === 1 ? 'blue' : 'red'}-team-win.png`"
mode="widthFix" mode="widthFix"
/> />
<view <view
:style="{ :style="{
transform: `translateY(50px) rotate(-${5 + data.mvps.length}deg)`, transform: `translateY(50px) rotate(-${
5 + (data.mvp || []).length
}deg)`,
}" }"
> >
<view v-if="data.mvps && data.mvps[0].totalRings"> <view v-if="data.mvp && data.mvp[0].totalRings">
<image src="../static/title-mvp.png" mode="widthFix" /> <image src="../static/title-mvp.png" mode="widthFix" />
<text <text
>斩获<text >斩获<text
@@ -164,22 +118,22 @@ const checkBowData = () => {
margin: '0 3px', margin: '0 3px',
fontWeight: '600', fontWeight: '600',
}" }"
>{{ data.mvps[0].totalRings }}</text >{{ data.mvp[0].totalRings }}</text
></text ></text
> >
</view> </view>
<view v-if="data.mvps && data.mvps.length"> <view v-if="data.mvp && data.mvp.length">
<view v-for="(player, index) in data.mvps" :key="index"> <view v-for="(player, index) in data.mvp" :key="index">
<view class="team-avatar"> <view class="team-avatar">
<Avatar <Avatar
:src="player.avatar" :src="player.avatar"
:size="40" :size="40"
:borderColor="data.myTeam === 1 ? '#5fadff' : '#ff6060'" :borderColor="myTeam === 1 ? '#5fadff' : '#ff6060'"
/> />
<text <text
v-if="player.id === user.id" v-if="player.id === user.id"
:style="{ :style="{
backgroundColor: data.myTeam === 1 ? '#5fadff' : '#ff6060', backgroundColor: myTeam === 1 ? '#5fadff' : '#ff6060',
}" }"
>自己</text >自己</text
> >
@@ -198,7 +152,7 @@ const checkBowData = () => {
/> />
<image <image
:src=" :src="
getBattleResultTips(data.battleMode, data.mode, { getBattleResultTips(data.way, data.mode, {
win: ifWin, win: ifWin,
}) })
" "
@@ -207,7 +161,7 @@ const checkBowData = () => {
/> />
</view> </view>
</block> </block>
<block v-if="data.mode === 2"> <block v-if="data.way === 2">
<view class="header-melee"> <view class="header-melee">
<view /> <view />
<image src="../static/battle-result.png" mode="widthFix" /> <image src="../static/battle-result.png" mode="widthFix" />
@@ -283,36 +237,36 @@ const checkBowData = () => {
</block> </block>
<view <view
class="battle-e" class="battle-e"
:style="{ marginTop: data.mode === 2 ? '20px' : '20vw' }" :style="{ marginTop: data.way === 2 ? '20px' : '20vw' }"
> >
<image src="../static/row-yellow-bg.png" mode="widthFix" /> <image src="../static/row-yellow-bg.png" mode="widthFix" />
<view class="team-avatar"> <view class="team-avatar">
<Avatar <Avatar
:src="user.avatar" :src="user.avatar"
:size="40" :size="40"
:borderColor="data.myTeam === 1 ? '#5fadff' : '#ff6060'" :borderColor="myTeam === 1 ? '#5fadff' : '#ff6060'"
/> />
<text <text
:style="{ backgroundColor: '#5fadff' }" :style="{ backgroundColor: '#5fadff' }"
v-if="data.mode === 1 && data.myTeam === 1" v-if="data.way === 1 && myTeam === 1"
>蓝队</text >蓝队</text
> >
<text <text
:style="{ backgroundColor: '#ff6060' }" :style="{ backgroundColor: '#ff6060' }"
v-if="data.mode === 1 && data.myTeam === 0" v-if="data.way === 1 && myTeam === 2"
>红队</text >红队</text
> >
</view> </view>
<text v-if="data.battleMode === 1"> <text v-if="data.way === 1">
你的经验 {{ totalPoints > 0 ? "+" + totalPoints : totalPoints }} 你的经验 {{ totalPoints > 0 ? "+" + totalPoints : totalPoints }}
</text> </text>
<text v-if="data.battleMode === 2"> <text v-if="data.way === 2">
你的积分 {{ totalPoints > 0 ? "+" + totalPoints : totalPoints }} 你的积分 {{ totalPoints > 0 ? "+" + totalPoints : totalPoints }}
</text> </text>
</view> </view>
<text v-if="data.mode === 2" class="description"> <text v-if="data.way === 2" class="description">
{{ {{
getBattleResultTips(data.battleMode, data.mode, { getBattleResultTips(data.way, data.mode, {
win: ifWin, win: ifWin,
score: totalPoints, score: totalPoints,
rank, rank,

View File

@@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref, watch, onMounted, onBeforeUnmount } from "vue"; import { ref, watch, onMounted, onBeforeUnmount } from "vue";
import { onLoad, onShareAppMessage } from "@dcloudio/uni-app"; import { onShow, onLoad, onShareAppMessage } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue"; import Container from "@/components/Container.vue";
import PlayerSeats from "@/components/PlayerSeats.vue"; import PlayerSeats from "@/components/PlayerSeats.vue";
import Guide from "@/components/Guide.vue"; import Guide from "@/components/Guide.vue";
@@ -16,7 +16,7 @@ import {
getReadyAPI, getReadyAPI,
} from "@/apis"; } from "@/apis";
import { MESSAGETYPES } from "@/constants"; import { MESSAGETYPES, MESSAGETYPESV2 } from "@/constants";
import useStore from "@/store"; import useStore from "@/store";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
const store = useStore(); const store = useStore();
@@ -38,6 +38,7 @@ const allReady = ref(false);
const timer = ref(null); const timer = ref(null);
async function refreshRoomData() { async function refreshRoomData() {
if (!roomNumber.value) return;
const result = await getRoomAPI(roomNumber.value); const result = await getRoomAPI(roomNumber.value);
if (result.started) return; if (result.started) return;
room.value = result; room.value = result;
@@ -94,7 +95,7 @@ async function refreshRoomData() {
refreshMembers(result.members); refreshMembers(result.members);
} }
if (timer.value) clearInterval(timer.value); if (timer.value) clearInterval(timer.value);
timer.value = setTimeout(refreshRoomData, 1000); // timer.value = setTimeout(refreshRoomData, 2000);
} }
const startGame = async () => { const startGame = async () => {
@@ -122,9 +123,10 @@ const refreshMembers = (members = []) => {
} }
}; };
async function onReceiveMessage(messages = []) { async function onReceiveMessage(message) {
messages.forEach((msg) => { if (Array.isArray(message)) {
if (msg.roomNumber === roomNumber.value) { message.forEach((msg) => {
if (msg.roomNumber !== roomNumber.value) return;
if (msg.constructor === MESSAGETYPES.UserEnterRoom) { if (msg.constructor === MESSAGETYPES.UserEnterRoom) {
if (battleType.value === 1) { if (battleType.value === 1) {
if (msg.userId === room.value.creator) { if (msg.userId === room.value.creator) {
@@ -193,29 +195,45 @@ async function onReceiveMessage(messages = []) {
} else if (msg.constructor === MESSAGETYPES.SomeoneIsReady) { } else if (msg.constructor === MESSAGETYPES.SomeoneIsReady) {
refreshRoomData(); refreshRoomData();
} }
} else if (msg.constructor === MESSAGETYPES.WaitForAllReady) { // else if (msg.constructor === MESSAGETYPES.WaitForAllReady) {
if (msg.groupUserStatus) { // if (msg.groupUserStatus) {
uni.setStorageSync("red-team", msg.groupUserStatus.redTeam); // uni.setStorageSync("red-team", msg.groupUserStatus.redTeam);
uni.setStorageSync("blue-team", msg.groupUserStatus.blueTeam); // uni.setStorageSync("blue-team", msg.groupUserStatus.blueTeam);
uni.setStorageSync("melee-players", [ // uni.setStorageSync("melee-players", [
...msg.groupUserStatus.redTeam, // ...msg.groupUserStatus.redTeam,
...msg.groupUserStatus.blueTeam, // ...msg.groupUserStatus.blueTeam,
]); // ]);
uni.removeStorageSync("current-battle"); // uni.removeStorageSync("current-battle");
// 避免离开页面,触发退出房间 // // 避免离开页面,触发退出房间
roomNumber.value = ""; // roomNumber.value = "";
if (msg.groupUserStatus.config.mode == 1) { // if (msg.groupUserStatus.config.mode == 1) {
uni.redirectTo({ // uni.redirectTo({
url: `/pages/team-battle?battleId=${msg.id}&gameMode=1`, // url: `/pages/team-battle?battleId=${msg.id}&gameMode=1`,
}); // });
} else if (msg.groupUserStatus.config.mode == 2) { // } else if (msg.groupUserStatus.config.mode == 2) {
uni.redirectTo({ // uni.redirectTo({
url: `/pages/melee-match?battleId=${msg.id}&gameMode=1`, // url: `/pages/melee-match?battleId=${msg.id}&gameMode=1`,
}); // });
} // }
} // }
// }
});
} else if (message.type === MESSAGETYPESV2.AboutToStart) {
uni.setStorageSync("blue-team", message.teams[1].players || []);
uni.setStorageSync("red-team", message.teams[2].players || []);
uni.removeStorageSync("current-battle");
roomNumber.value = "";
let params = `?gameMode=1&battleId=${message.matchId}`;
if (message.way == 1) {
uni.redirectTo({
url: "/pages/team-battle" + params,
});
} else if (message.way == 2) {
uni.redirectTo({
url: "/pages/melee-match" + params,
});
} }
}); }
} }
const chooseTeam = async (team) => { const chooseTeam = async (team) => {
@@ -254,11 +272,12 @@ onShareAppMessage(() => {
}; };
}); });
onShow(() => {
refreshRoomData();
});
onLoad(async (options) => { onLoad(async (options) => {
if (options.roomNumber) { if (options.roomNumber) roomNumber.value = options.roomNumber;
roomNumber.value = options.roomNumber;
refreshRoomData();
}
}); });
onMounted(() => { onMounted(() => {

View File

@@ -23,6 +23,7 @@ const warnning = ref("");
const roomNumber = ref(""); const roomNumber = ref("");
const data = ref({}); const data = ref({});
const roomID = ref(""); const roomID = ref("");
const loading = ref(false);
const enterRoom = debounce(async (number) => { const enterRoom = debounce(async (number) => {
if (!canEenter(user.value, device.value, online.value)) return; if (!canEenter(user.value, device.value, online.value)) return;
@@ -33,27 +34,32 @@ const enterRoom = debounce(async (number) => {
if (!number) { if (!number) {
warnning.value = "请输入房间号"; warnning.value = "请输入房间号";
showModal.value = true; showModal.value = true;
} else { return;
}
try {
const room = await getRoomAPI(number); const room = await getRoomAPI(number);
if (room.number) { if (!room.number) {
const alreadyIn = room.members.find(
(item) => item.userInfo.id === user.value.id
);
if (!alreadyIn) {
const result = await joinRoomAPI(number);
if (result.full) {
warnning.value = "房间已满员";
showModal.value = true;
return;
}
}
uni.navigateTo({
url: "/pages/battle-room?roomNumber=" + number,
});
} else {
warnning.value = room.started ? "该房间对战已开始,无法加入" : "查无此房"; warnning.value = room.started ? "该房间对战已开始,无法加入" : "查无此房";
showModal.value = true; showModal.value = true;
return;
} }
const alreadyIn = room.members.find(
(item) => item.userInfo.id === user.value.id
);
if (!alreadyIn) {
const result = await joinRoomAPI(number);
if (result.full) {
warnning.value = "房间已满员";
showModal.value = true;
return;
}
}
loading.value = true;
uni.navigateTo({
url: "/pages/battle-room?roomNumber=" + number,
});
} finally {
loading.value = false;
} }
}); });
const onCreateRoom = async () => { const onCreateRoom = async () => {

View File

@@ -5,7 +5,7 @@ import Container from "@/components/Container.vue";
import BattleHeader from "@/components/BattleHeader.vue"; import BattleHeader from "@/components/BattleHeader.vue";
import Avatar from "@/components/Avatar.vue"; import Avatar from "@/components/Avatar.vue";
import PlayerScore2 from "@/components/PlayerScore2.vue"; import PlayerScore2 from "@/components/PlayerScore2.vue";
import { getGameAPI } from "@/apis"; import { getBattleAPI } from "@/apis";
const blueTeam = ref([]); const blueTeam = ref([]);
const redTeam = ref([]); const redTeam = ref([]);
@@ -13,79 +13,23 @@ const roundsData = ref([]);
const goldenRoundsData = ref([]); const goldenRoundsData = ref([]);
const battleId = ref(""); const battleId = ref("");
const data = ref({ const data = ref({
players: [], teams: [],
rounds: [],
}); });
onLoad(async (options) => { onLoad(async (options) => {
if (options.id) { if (!options.id) return;
battleId.value = options.id || "BATTLE-1755484626207409508-955"; battleId.value = options.id || "57943107462893568";
const result = await getGameAPI(battleId.value); const result = await getBattleAPI(battleId.value);
data.value = result; data.value = result;
if (result.mode === 1) {
blueTeam.value = Object.values(result.bluePlayers || {});
redTeam.value = Object.values(result.redPlayers || {});
Object.values(result.roundsData).forEach((item) => {
let bluePoint = 1;
let redPoint = 1;
let blueTotalRings = 0;
let redTotalRings = 0;
let blueArrows = [];
let redArrows = [];
blueTeam.value.forEach((p) => {
if (!item[p.playerId]) return;
blueTotalRings += item[p.playerId].reduce((a, b) => a + b.ring, 0);
blueArrows = [...blueArrows, ...item[p.playerId]];
});
redTeam.value.forEach((p) => {
if (!item[p.playerId]) return;
redTotalRings += item[p.playerId].reduce((a, b) => a + b.ring, 0);
redArrows = [...redArrows, ...item[p.playerId]];
});
if (blueTotalRings > redTotalRings) {
bluePoint = 2;
redPoint = 0;
} else if (blueTotalRings < redTotalRings) {
bluePoint = 0;
redPoint = 2;
}
roundsData.value.push({
blue: {
avatars: blueTeam.value.map((p) => p.avatar),
arrows: blueArrows,
totalRing: blueTotalRings,
totalScore: bluePoint,
},
red: {
avatars: redTeam.value.map((p) => p.avatar),
arrows: redArrows,
totalRing: redTotalRings,
totalScore: redPoint,
},
});
});
result.goldenRounds.forEach((round) => {
goldenRoundsData.value.push({
blue: {
avatars: blueTeam.value.map((p) => p.avatar),
arrows: round.arrowHistory.filter((a) => a.team === 1),
},
red: {
avatars: redTeam.value.map((p) => p.avatar),
arrows: round.arrowHistory.filter((a) => a.team === 0),
},
winner: round.winner,
});
});
}
}
}); });
const checkBowData = () => { const checkBowData = (selected) => {
if (data.value.mode === 1) { if (data.value.way === 1) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/team-bow-data?battleId=${battleId.value}`, url: `/pages/team-bow-data?battleId=${battleId.value}&selected=${selected}`,
}); });
} else if (data.value.mode === 2) { } else if (data.value.way === 2) {
uni.navigateTo({ uni.navigateTo({
url: `/pages/melee-bow-data?battleId=${battleId.value}`, url: `/pages/melee-bow-data?battleId=${battleId.value}`,
}); });
@@ -97,13 +41,13 @@ const checkBowData = () => {
<Container title="详情"> <Container title="详情">
<view class="container"> <view class="container">
<BattleHeader <BattleHeader
:winner="data.winner" :winner="data.winTeam"
:blueTeam="blueTeam" :blueTeam="data.teams[1] ? data.teams[1].players : []"
:redTeam="redTeam" :redTeam="data.teams[2] ? data.teams[2].players : []"
:players="data.players" :players="data.players"
/> />
<view <view
v-if="data.players && data.players.length" v-if="data.mode > 3"
class="score-header" class="score-header"
:style="{ border: 'none', padding: '5px 15px' }" :style="{ border: 'none', padding: '5px 15px' }"
> >
@@ -114,7 +58,7 @@ const checkBowData = () => {
</view> </view>
</view> </view>
<PlayerScore2 <PlayerScore2
v-if="data.players && data.players.length" v-if="data.mode > 3"
v-for="(player, index) in data.players" v-for="(player, index) in data.players"
:key="index" :key="index"
:name="player.name" :name="player.name"
@@ -124,131 +68,47 @@ const checkBowData = () => {
:totalRing="player.totalRings" :totalRing="player.totalRings"
:rank="index + 1" :rank="index + 1"
/> />
<block v-for="(round, index) in goldenRoundsData" :key="index"> <view
v-for="(round, index) in data.rounds"
:key="index"
:style="{ marginBottom: '5px' }"
>
<view class="score-header"> <view class="score-header">
<text>决金箭轮环数</text> <text>{{ round.ifGold ? "决金箭" : `${index + 1}` }}</text>
<view @click="checkBowData"> <view @click="() => checkBowData(index)">
<text>查看靶纸</text> <text>查看靶纸</text>
<image src="../static/back.png" mode="widthFix" /> <image src="../static/back.png" mode="widthFix" />
</view> </view>
</view> </view>
<view class="score-row"> <view
class="score-row"
v-for="team in Object.keys(round.shoots)"
:key="team"
>
<view> <view>
<view> <view>
<image <image
v-for="(src, index) in round.blue.avatars" v-for="(p, index) in data.teams[team].players"
:style="{ :style="{
borderColor: '#64BAFF', borderColor: '#64BAFF',
transform: `translateX(-${index * 15}px)`, transform: `translateX(-${index * 15}px)`,
}" }"
:src="src" :src="p.avatar || '../static/user-icon.png'"
:key="index" :key="index"
mode="widthFix" mode="widthFix"
/> />
</view> </view>
<text v-for="(arrow, index) in round.blue.arrows" :key="index"> <text v-for="(arrow, index2) in round.shoots[team]" :key="index2">
{{ arrow.ring }} {{ arrow.ring }}
</text> </text>
</view> </view>
<image
v-if="round.winner === 1"
src="../static/winner-badge.png"
mode="widthFix"
/>
</view>
<view class="score-row" :style="{ marginBottom: '5px' }">
<view> <view>
<view> <text :style="{ color: team == 1 ? '#64BAFF' : '#FF6767' }">
<image {{ round.shoots[team].reduce((acc, cur) => acc + cur.ring, 0) }}
v-for="(src, index) in round.red.avatars"
:style="{
borderColor: '#FF6767',
transform: `translateX(-${index * 15}px)`,
}"
:src="src || '../static/user-icon.png'"
:key="index"
mode="widthFix"
/>
</view>
<text v-for="(arrow, index) in round.red.arrows" :key="index">
{{ arrow.ring }}
</text> </text>
<text>得分 {{ round.scores[team].totalRing }}</text>
</view> </view>
<image
v-if="round.winner === 0"
src="../static/winner-badge.png"
mode="widthFix"
/>
</view> </view>
</block>
<view
v-for="(round, index) in roundsData"
:key="index"
:style="{ marginBottom: '5px' }"
>
<block
v-if="
index < Object.keys(roundsData).length - goldenRoundsData.length
"
>
<view class="score-header">
<text>第{{ index + 1 }}轮</text>
<view @click="checkBowData">
<text>查看靶纸</text>
<image src="../static/back.png" mode="widthFix" />
</view>
</view>
<view class="score-row">
<view>
<view>
<image
v-for="(src, index) in round.blue.avatars"
:style="{
borderColor: '#64BAFF',
transform: `translateX(-${index * 15}px)`,
}"
:src="src || '../static/user-icon.png'"
:key="index"
mode="widthFix"
/>
</view>
<text v-for="(arrow, index2) in round.blue.arrows" :key="index2">
{{ arrow.ring }}环
</text>
</view>
<view>
<text :style="{ color: '#64BAFF' }">
{{ round.blue.totalRing }}环
</text>
<text>得分 {{ round.blue.totalScore }}</text>
</view>
</view>
<view class="score-row">
<view>
<view>
<image
v-for="(src, index) in round.red.avatars"
:style="{
borderColor: '#FF6767',
transform: `translateX(-${index * 15}px)`,
}"
:src="src || '../static/user-icon.png'"
:key="index"
mode="widthFix"
/>
</view>
<text v-for="(arrow, index2) in round.red.arrows" :key="index2">
{{ arrow.ring }}环
</text>
</view>
<view>
<text :style="{ color: '#FF6767' }">
{{ round.red.totalRing }}环
</text>
<text>得分 {{ round.red.totalScore }}</text>
</view>
</view>
</block>
</view> </view>
<view :style="{ height: '20px' }"></view> <view :style="{ height: '20px' }"></view>
</view> </view>

View File

@@ -75,13 +75,13 @@ function recoverData(battleInfo) {
? "下半场请再射6箭" ? "下半场请再射6箭"
: "上半场请先射6箭"; : "上半场请先射6箭";
setTimeout(() => { setTimeout(() => {
uni.$emit("update-ramain", 90 - remain); uni.$emit("update-remain", 90 - remain);
}, 200); }, 200);
} else if (battleInfo.status === 9) { } else if (battleInfo.status === 9) {
startCount.value = false; startCount.value = false;
tips.value = "准备下半场"; tips.value = "准备下半场";
setTimeout(() => { setTimeout(() => {
uni.$emit("update-ramain", 0); uni.$emit("update-remain", 0);
}, 200); }, 200);
} }
} }
@@ -131,7 +131,7 @@ async function onReceiveMessage(messages = []) {
playersScores.value[msg.userId].push({ ...msg.target }); playersScores.value[msg.userId].push({ ...msg.target });
} }
if (msg.constructor === MESSAGETYPES.HalfTimeOver) { if (msg.constructor === MESSAGETYPES.HalfTimeOver) {
uni.$emit("update-ramain", 0); uni.$emit("update-remain", 0);
[...msg.groupUserStatus.redTeam, ...msg.groupUserStatus.blueTeam].forEach( [...msg.groupUserStatus.redTeam, ...msg.groupUserStatus.blueTeam].forEach(
(player) => { (player) => {
playersScores.value[player.id] = [...player.arrows]; playersScores.value[player.id] = [...player.arrows];

View File

@@ -12,18 +12,18 @@ import RoundEndTip from "@/components/RoundEndTip.vue";
import TestDistance from "@/components/TestDistance.vue"; import TestDistance from "@/components/TestDistance.vue";
import TeamAvatars from "@/components/TeamAvatars.vue"; import TeamAvatars from "@/components/TeamAvatars.vue";
import ShootProgress2 from "@/components/ShootProgress2.vue"; import ShootProgress2 from "@/components/ShootProgress2.vue";
import { getCurrentGameAPI, laserCloseAPI } from "@/apis"; import { getCurrentGameAPI, laserCloseAPI, getBattleAPI } from "@/apis";
import { isGameEnded } from "@/util"; import { isGameEnded, formatTimestamp } from "@/util";
import { MESSAGETYPES, roundsName } from "@/constants"; import { MESSAGETYPES, MESSAGETYPESV2, roundsName } from "@/constants";
import audioManager from "@/audioManager"; import audioManager from "@/audioManager";
import useStore from "@/store"; import useStore from "@/store";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
const store = useStore(); const store = useStore();
const { user } = storeToRefs(store); const { user } = storeToRefs(store);
const start = ref(false); const start = ref(null);
const tips = ref(""); const tips = ref("");
const battleId = ref(""); const battleId = ref("");
const currentRound = ref(1); const currentRound = ref(0);
const goldenRound = ref(0); const goldenRound = ref(0);
const currentRedPoint = ref(0); const currentRedPoint = ref(0);
const currentBluePoint = ref(0); const currentBluePoint = ref(0);
@@ -37,246 +37,95 @@ const redPoints = ref(0);
const bluePoints = ref(0); const bluePoints = ref(0);
const showRoundTip = ref(false); const showRoundTip = ref(false);
const isFinalShoot = ref(false); const isFinalShoot = ref(false);
const isEnded = ref(false);
function recoverData(battleInfo) { const recoverData = (battleInfo, { force = false, arrowOnly = false } = {}) => {
uni.removeStorageSync("last-awake-time"); try {
battleId.value = battleInfo.id; battleId.value = battleInfo.matchId;
redTeam.value = battleInfo.redTeam; blueTeam.value = battleInfo.teams[1].players || [];
blueTeam.value = battleInfo.blueTeam; redTeam.value = battleInfo.teams[2].players || [];
if (battleInfo.status === 0) { if (battleInfo.status === 0) {
const readyRemain = Date.now() / 1000 - battleInfo.startTime; start.value = false;
console.log(`当前局已进行${readyRemain}`); const readyRemain = (Date.now() - battleInfo.createTime) / 1000;
if (readyRemain > 0) { console.log(`对局已进行${readyRemain}`);
setTimeout(() => { if (readyRemain > 0 && readyRemain < 15) {
uni.$emit("update-timer", 15 - readyRemain); setTimeout(() => {
}, 200); uni.$emit("update-timer", 15 - readyRemain - 0.2);
} }, 200);
} else {
start.value = true;
bluePoints.value = 0;
redPoints.value = 0;
currentRound.value = battleInfo.currentRound;
roundResults.value = [...battleInfo.roundResults];
// 算得分
battleInfo.roundResults.forEach((round) => {
const blueTotal = round.blueArrows.reduce(
(last, next) => last + next.ring,
0
);
const redTotal = round.redArrows.reduce(
(last, next) => last + next.ring,
0
);
if (blueTotal === redTotal) {
bluePoints.value += 1;
redPoints.value += 1;
} else if (blueTotal > redTotal) {
bluePoints.value += 2;
} else {
redPoints.value += 2;
} }
}); return;
if (battleInfo.goldenRoundNumber) {
currentRound.value += battleInfo.goldenRoundNumber;
goldenRound.value = battleInfo.goldenRoundNumber;
isFinalShoot.value = true;
for (let i = 1; i <= battleInfo.goldenRoundNumber; i++) {
const redArrows = [];
battleInfo.redTeam.forEach((item) => {
if (item.shotHistory[roundResults.value.length + 1]) {
item.shotHistory[roundResults.value.length + 1]
.filter((item) => !!item.playerId)
.forEach((item) => redArrows.push(item));
}
});
const blueArrows = [];
battleInfo.blueTeam.forEach((item) => {
if (item.shotHistory[roundResults.value.length + 1]) {
item.shotHistory[roundResults.value.length + 1]
.filter((item) => !!item.playerId)
.forEach((item) => blueArrows.push(item));
}
});
roundResults.value.push({
number: roundResults.value.length + 1,
blueArrows,
redArrows,
blueTotal: blueArrows.reduce((last, next) => last + next.ring, 0),
redTotal: redArrows.reduce((last, next) => last + next.ring, 0),
});
}
} else {
const hasCurrentRoundData =
battleInfo.redTeam.some(
(item) => !!item.shotHistory[battleInfo.currentRound]
) ||
battleInfo.blueTeam.some(
(item) => !!item.shotHistory[battleInfo.currentRound]
);
if (
battleInfo.currentRound > battleInfo.roundResults.length &&
hasCurrentRoundData
) {
const blueArrows = [];
const redArrows = [];
battleInfo.redTeam.forEach((item) =>
item.shotHistory[battleInfo.currentRound]
.filter((item) => !!item.playerId)
.forEach((item) => redArrows.push(item))
);
battleInfo.blueTeam.forEach((item) =>
item.shotHistory[battleInfo.currentRound]
.filter((item) => !!item.playerId)
.forEach((item) => blueArrows.push(item))
);
roundResults.value.push({
redArrows,
blueArrows,
});
}
[...battleInfo.redTeam, ...battleInfo.blueTeam].some((p) => {
if (p.id === user.value.id) {
const roundArrows = Object.values(p.shotHistory);
if (roundArrows.length) {
uni.$emit("update-shot", {
currentShot: roundArrows[roundArrows.length - 1].length,
totalShot: battleInfo.config.teamSize === 2 ? 3 : 2,
});
}
return true;
}
return false;
});
} }
const lastIndex = roundResults.value.length - 1; if (!arrowOnly) {
if (roundResults.value[lastIndex]) { start.value = true;
const redArrows = roundResults.value[lastIndex].redArrows; currentShooterId.value = battleInfo.current.playerId;
scores.value = [...redArrows] const redPlayer = battleInfo.teams[2].players.find(
.filter((item) => !!item.playerId) (item) => item.id === battleInfo.current.playerId
.sort((a, b) => a.shotTimeUnix - b.shotTimeUnix);
const blueArrows = roundResults.value[lastIndex].blueArrows;
blueScores.value = [...blueArrows]
.filter((item) => !!item.playerId)
.sort((a, b) => a.shotTimeUnix - b.shotTimeUnix);
}
if (battleInfo.firePlayerIndex) {
currentShooterId.value = battleInfo.firePlayerIndex;
const redPlayer = redTeam.value.find(
(item) => item.id === currentShooterId.value
); );
let nextTips = redPlayer ? "请红队射箭" : "请蓝队射箭"; let nextTips = redPlayer ? "请红队射箭" : "请蓝队射箭";
nextTips += "重回"; if (force) nextTips += "重回";
// if (battleInfo.firePlayerIndex === user.value.id) nextTips += "你"; if (
battleInfo.current.playerId === user.value.id &&
redTeam.value.length > 1
) {
nextTips += "你";
}
tips.value = nextTips; tips.value = nextTips;
uni.$emit("update-tips", nextTips); uni.$emit("update-tips", nextTips);
} if (force) {
if (battleInfo.fireTime > 0) { const remain = (Date.now() - battleInfo.current.startTime) / 1000;
const remain = Date.now() / 1000 - battleInfo.fireTime; console.log(
console.log(`当前箭已过${remain}`); `当前轮已进行${remain},${Date.now()},${
if (remain > 0 && remain <= 15) { battleInfo.current.startTimeText
// 等渲染好再通知 }`
setTimeout(() => {
uni.$emit("update-ramain", 15 - remain);
}, 300);
}
}
}
}
async function onReceiveMessage(messages = []) {
messages.forEach((msg) => {
if (msg.constructor === MESSAGETYPES.WaitForAllReady) {
redTeam.value = msg.groupUserStatus.redTeam;
blueTeam.value = msg.groupUserStatus.blueTeam;
}
if (msg.constructor === MESSAGETYPES.AllReady) {
start.value = true;
}
if (msg.constructor === MESSAGETYPES.ToSomeoneShoot) {
if (currentShooterId.value !== msg.userId) {
currentShooterId.value = msg.userId;
const redPlayer = redTeam.value.find(
(item) => item.id === currentShooterId.value
); );
if (remain > 0 && remain < 15) {
let nextTips = redPlayer ? "请红队射箭" : "请蓝队射箭"; setTimeout(() => {
if (msg.userId === user.value.id && redTeam.value.length > 1) { uni.$emit("update-remain", 15 - remain - 0.2);
nextTips += "你"; }, 200);
} }
if (nextTips !== tips.value) {
tips.value = nextTips;
uni.$emit("update-tips", tips.value);
} else {
uni.$emit("update-ramain", 15);
}
}
}
if (msg.constructor === MESSAGETYPES.ShootResult) {
if (msg.battleInfo) recoverData(msg.battleInfo);
}
if (msg.constructor === MESSAGETYPES.CurrentRoundEnded) {
const result = msg.preRoundResult;
scores.value = [];
blueScores.value = [];
currentShooterId.value = 0;
currentBluePoint.value = result.blueScore;
currentRedPoint.value = result.redScore;
bluePoints.value += result.blueScore;
redPoints.value += result.redScore;
if (!result.goldenRound) {
showRoundTip.value = true;
}
}
if (msg.constructor === MESSAGETYPES.FinalShoot) {
currentShooterId.value = 0;
currentBluePoint.value = bluePoints.value;
currentRedPoint.value = redPoints.value;
if (!isFinalShoot.value) {
isFinalShoot.value = true;
showRoundTip.value = true;
tips.value = "准备开始决金箭";
}
}
if (msg.constructor === MESSAGETYPES.MatchOver) {
if (msg.endStatus.noSaved) {
currentBluePoint.value = 0;
currentRedPoint.value = 0;
showRoundTip.value = true;
isFinalShoot.value = false;
setTimeout(() => {
uni.navigateBack();
}, 3000);
} else { } else {
isEnded.value = true; uni.$emit("update-remain", battleInfo.readyTime);
uni.setStorageSync("last-battle", msg.endStatus); }
setTimeout(() => { } else {
uni.redirectTo({ currentRound.value = battleInfo.current.round || 1;
url: "/pages/battle-result", const latestRound = battleInfo.rounds[currentRound.value - 1];
}); if (latestRound) {
}, 1000); blueScores.value = latestRound.shoots[1];
scores.value = latestRound.shoots[2];
} }
} }
if (msg.constructor === MESSAGETYPES.BackToGame) { roundResults.value = battleInfo.rounds || [];
uni.$emit("update-header-loading", false); isFinalShoot.value = battleInfo.current.goldRound;
if (msg.battleInfo) recoverData(msg.battleInfo); bluePoints.value = battleInfo.teams[1].score;
redPoints.value = battleInfo.teams[2].score;
} catch (err) {
console.log(err);
}
};
async function onReceiveMessage(msg) {
if (Array.isArray(msg)) return;
if (msg.type === MESSAGETYPESV2.BattleStart) {
start.value = true;
} else if (msg.type === MESSAGETYPESV2.ToSomeoneShoot) {
recoverData(msg);
} else if (msg.type === MESSAGETYPESV2.ShootResult) {
recoverData(msg, { arrowOnly: true });
} else if (msg.type === MESSAGETYPESV2.NewRound) {
showRoundTip.value = true;
const latestRound = msg.rounds[currentRound.value - 1];
if (latestRound) {
currentBluePoint.value = latestRound.scores[1].score;
currentRedPoint.value = latestRound.scores[2].score;
} }
}); } else if (msg.type === MESSAGETYPESV2.BattleEnd) {
uni.redirectTo({
url: "/pages/battle-result?battleId=" + msg.matchId,
});
}
} }
onLoad(async (options) => { onLoad(async (options) => {
if (options.battleId) { if (options.battleId) battleId.value = options.battleId;
battleId.value = options.battleId;
redTeam.value = uni.getStorageSync("red-team");
blueTeam.value = uni.getStorageSync("blue-team");
const battleInfo = uni.getStorageSync("current-battle");
if (battleInfo) {
await nextTick(() => {
recoverData(battleInfo);
});
setTimeout(getCurrentGameAPI, 2000);
}
}
uni.enableAlertBeforeUnload({ uni.enableAlertBeforeUnload({
message: "离开比赛可能导致比赛失败,是否继续?", message: "离开比赛可能导致比赛失败,是否继续?",
success: (res) => { success: (res) => {
@@ -301,30 +150,46 @@ onBeforeUnmount(() => {
const refreshTimer = ref(null); const refreshTimer = ref(null);
onShow(async () => { onShow(async () => {
if (battleId.value) { if (battleId.value) {
if (!isEnded.value && (await isGameEnded(battleId.value))) return; const result = await getBattleAPI(battleId.value);
getCurrentGameAPI(); if (result.status === 2) {
const refreshData = () => { uni.showToast({
const lastAwakeTime = uni.getStorageSync("last-awake-time"); title: "比赛已结束",
if (lastAwakeTime) { icon: "none",
getCurrentGameAPI(); });
} else { uni.navigateBack({
clearInterval(refreshTimer.value); delta: 2,
} });
}; } else {
refreshTimer.value = setInterval(refreshData, 2000); recoverData(result, { force: true });
}
// if (await isGameEnded(battleId.value)) return;
// getCurrentGameAPI();
// const refreshData = () => {
// const lastAwakeTime = uni.getStorageSync("last-awake-time");
// if (lastAwakeTime) {
// getCurrentGameAPI();
// } else {
// clearInterval(refreshTimer.value);
// }
// };
// refreshTimer.value = setInterval(refreshData, 2000);
} }
}); });
onHide(() => { // onHide(() => {
if (refreshTimer.value) clearInterval(refreshTimer.value); // if (refreshTimer.value) clearInterval(refreshTimer.value);
uni.setStorageSync("last-awake-time", Date.now()); // uni.setStorageSync("last-awake-time", Date.now());
}); // });
</script> </script>
<template> <template>
<Container :bgType="start ? 3 : 1"> <Container :bgType="start ? 3 : 1">
<view class="container"> <view class="container">
<BattleHeader v-if="!start" :redTeam="redTeam" :blueTeam="blueTeam" /> <BattleHeader
<TestDistance v-if="!start" :guide="false" :isBattle="true" /> v-if="start === false"
:redTeam="redTeam"
:blueTeam="blueTeam"
/>
<TestDistance v-if="start === false" :guide="false" :isBattle="true" />
<view v-if="start" class="players-row"> <view v-if="start" class="players-row">
<TeamAvatars <TeamAvatars
:team="blueTeam" :team="blueTeam"

View File

@@ -5,105 +5,42 @@ import Container from "@/components/Container.vue";
import BowTarget from "@/components/BowTarget.vue"; import BowTarget from "@/components/BowTarget.vue";
import Avatar from "@/components/Avatar.vue"; import Avatar from "@/components/Avatar.vue";
import { roundsName } from "@/constants"; import { roundsName } from "@/constants";
import { getGameAPI } from "@/apis"; import { getBattleAPI } from "@/apis";
const selected = ref(0); const selected = ref(0);
const redScores = ref([]); const redScores = ref([]);
const blueScores = ref([]); const blueScores = ref([]);
const tabs = ref(["所有轮次"]); const tabs = ref([]);
const players = ref([]); const players = ref([]);
const allRoundsScore = ref({}); const data = ref({});
const data = ref({
goldenRounds: [], const loadArrows = (round) => {
}); round.shoots[1].forEach((arrow) => {
blueScores.value.push(arrow);
});
round.shoots[2].forEach((arrow) => {
redScores.value.push(arrow);
});
};
onLoad(async (options) => { onLoad(async (options) => {
if (options.battleId) { if (!options.battleId) return;
const result = await getGameAPI( const result = await getBattleAPI(options.battleId || "57943107462893568");
options.battleId || "BATTLE-1756453741433684760-512" data.value = result;
); data.value.teams[1].players.forEach((p, index) => {
data.value = result; players.value.push(p);
Object.values(result.bluePlayers).forEach((p, index) => { players.value.push(data.value.teams[2].players[index]);
players.value.push(p); });
if ( Object.values(data.value.rounds).forEach((round, index) => {
Object.values(result.redPlayers) && if (round.ifGold) tabs.value.push(`决金箭`);
Object.values(result.redPlayers)[index] else tabs.value.push(`${roundsName[index + 1]}`);
) { });
players.value.push(Object.values(result.redPlayers)[index]); selected.value = Number(options.selected || 0);
} onClickTab(selected.value);
});
if (result.goldenRounds) {
result.goldenRounds.forEach(() => {
tabs.value.push("决金箭");
});
}
Object.keys(result.roundsData).forEach((key, index) => {
if (
index <
Object.keys(result.roundsData).length - result.goldenRounds.length
) {
tabs.value.push(`${roundsName[key]}`);
}
});
onClickTab(0);
}
}); });
const onClickTab = (index) => { const onClickTab = (index) => {
selected.value = index; selected.value = index;
redScores.value = []; redScores.value = [];
blueScores.value = []; blueScores.value = [];
const { bluePlayers, redPlayers, roundsData, goldenRounds } = data.value; loadArrows(data.value.rounds[index]);
let maxArrowLength = 0;
if (index === 0) {
Object.keys(bluePlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
if (!round[p]) return;
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
});
Object.keys(redPlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
if (!round[p]) return;
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
redScores.value.push(arrow);
});
});
});
} else if (index <= goldenRounds.length) {
const dataIndex =
Object.keys(roundsData).length - goldenRounds.length + index;
Object.keys(bluePlayers).forEach((p) => {
if (!roundsData[dataIndex][p]) return;
roundsData[dataIndex][p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
Object.keys(redPlayers).forEach((p) => {
if (!roundsData[dataIndex][p]) return;
roundsData[dataIndex][p].forEach((arrow) => {
redScores.value.push(arrow);
});
});
} else {
Object.keys(bluePlayers).forEach((p) => {
roundsData[index - goldenRounds.length][p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
Object.keys(redPlayers).forEach((p) => {
roundsData[index - goldenRounds.length][p].forEach((arrow) => {
redScores.value.push(arrow);
});
});
}
}; };
</script> </script>
@@ -134,41 +71,14 @@ const onClickTab = (index) => {
> >
<Avatar <Avatar
:src="player.avatar" :src="player.avatar"
:borderColor=" :borderColor="index % 2 === 0 ? '#64BAFF' : '#FF6767'"
data.bluePlayers[player.playerId] ? '#64BAFF' : '#FF6767'
"
:size="36" :size="36"
/> />
<view> <view>
<view <view
v-if="selected === 0" v-for="(score, index) in data.rounds[selected].shoots[
v-for="(ring, index) in allRoundsScore[player.playerId]" index % 2 === 0 ? 1 : 2
:key="index" ]"
class="score-item"
>
{{ ring }}
</view>
<view
v-if="
selected > 0 &&
selected >= data.goldenRounds.length &&
selected <= data.goldenRounds.length
"
v-for="(score, index) in data.roundsData[
Object.keys(data.roundsData).length -
data.goldenRounds.length +
selected
][player.playerId]"
:key="index"
class="score-item"
>
{{ score.ring }}
</view>
<view
v-if="selected > data.goldenRounds.length"
v-for="(score, index) in data.roundsData[
selected - data.goldenRounds.length
][player.playerId]"
:key="index" :key="index"
class="score-item" class="score-item"
> >