Files
shoot-miniprograms/src/pages/melee-match.vue

216 lines
6.3 KiB
Vue
Raw Normal View History

2025-05-16 15:56:54 +08:00
<script setup>
2025-06-05 21:32:51 +08:00
import { ref, onMounted, onUnmounted } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
2025-05-16 15:56:54 +08:00
import BowTarget from "@/components/BowTarget.vue";
import ShootProgress from "@/components/ShootProgress.vue";
2025-06-09 12:24:01 +08:00
import Guide from "@/components/Guide.vue";
import BattleHeader from "@/components/BattleHeader.vue";
2025-06-05 21:32:51 +08:00
import Timer from "@/components/Timer.vue";
2025-06-09 01:17:18 +08:00
import PlayerScore from "@/components/PlayerScore.vue";
2025-06-05 21:32:51 +08:00
import SButton from "@/components/SButton.vue";
2025-06-17 16:02:29 +08:00
import Avatar from "@/components/Avatar.vue";
2025-06-20 11:22:41 +08:00
import ScreenHint from "@/components/ScreenHint.vue";
2025-06-25 21:54:18 +08:00
import Matching from "@/components/Matching.vue";
2025-06-05 21:32:51 +08:00
import { matchGameAPI, readyGameAPI } from "@/apis";
2025-06-17 16:02:29 +08:00
import { MESSAGETYPES, getMessageTypeName } from "@/constants";
2025-06-09 01:17:18 +08:00
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
2025-06-05 21:32:51 +08:00
const gameType = ref(0);
const teamSize = ref(0);
const start = ref(false);
2025-06-22 01:41:51 +08:00
const startCount = ref(false);
2025-06-05 21:32:51 +08:00
const battleId = ref("");
const currentRound = ref(1);
const totalRounds = ref(0);
const power = ref(0);
const scores = ref([]);
const tips = ref("即将开始...");
2025-06-15 20:55:34 +08:00
const seq = ref(0);
2025-06-05 21:32:51 +08:00
const timerSeq = ref(0);
2025-06-09 01:17:18 +08:00
const players = ref([]);
const playersScores = ref({});
2025-06-20 11:22:41 +08:00
const halfTimeTip = ref(false);
2025-06-25 21:54:18 +08:00
const onComplete = ref(null);
2025-06-05 21:32:51 +08:00
2025-06-25 21:54:18 +08:00
onLoad(async (options) => {
2025-06-05 21:32:51 +08:00
gameType.value = options.gameType;
teamSize.value = options.teamSize;
2025-06-25 21:54:18 +08:00
if (gameType.value && teamSize.value) {
await matchGameAPI(true, gameType.value, teamSize.value);
}
2025-06-05 21:32:51 +08:00
});
async function stopMatch() {
2025-06-25 21:54:18 +08:00
uni.navigateBack();
2025-06-05 21:32:51 +08:00
}
async function readyToGo() {
if (battleId.value) {
await readyGameAPI(battleId.value);
2025-06-17 19:35:21 +08:00
scores.value = [];
2025-06-05 21:32:51 +08:00
start.value = true;
timerSeq.value = 0;
}
}
2025-06-19 21:03:33 +08:00
async function onReceiveMessage(messages = []) {
2025-06-05 21:32:51 +08:00
messages.forEach((msg) => {
if (
!msg.id ||
(battleId.value && msg.id === battleId.value) ||
msg.constructor === MESSAGETYPES.WaitForAllReady
) {
2025-06-17 16:02:29 +08:00
console.log("收到消息:", getMessageTypeName(msg.constructor), msg);
2025-06-05 21:32:51 +08:00
}
if (msg.constructor === MESSAGETYPES.WaitForAllReady) {
2025-06-25 21:54:18 +08:00
onComplete.value = () => {
// 这里会掉多次;
timerSeq.value += 1;
battleId.value = msg.id;
players.value = [
...msg.groupUserStatus.redTeam,
...msg.groupUserStatus.blueTeam,
];
players.value.forEach((p) => {
playersScores.value[p.id] = [];
});
};
2025-06-09 01:17:18 +08:00
}
if (!start.value && msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) {
scores.value.push(msg.target);
power.value = msg.target.battery;
2025-06-05 21:32:51 +08:00
}
if (msg.id !== battleId.value) return;
2025-06-09 01:17:18 +08:00
if (msg.constructor === MESSAGETYPES.MeleeAllReady) {
2025-06-05 21:32:51 +08:00
start.value = true;
2025-06-22 01:41:51 +08:00
startCount.value = true;
2025-06-15 20:55:34 +08:00
seq.value += 1;
2025-06-05 21:32:51 +08:00
timerSeq.value = 0;
2025-06-17 16:02:29 +08:00
tips.value = "请连续射出6支箭";
2025-06-05 21:32:51 +08:00
scores.value = [];
}
if (msg.constructor === MESSAGETYPES.ShootResult) {
2025-06-09 01:17:18 +08:00
if (msg.userId === user.value.id) {
2025-06-15 20:55:34 +08:00
scores.value.push(msg.target);
2025-06-09 01:17:18 +08:00
power.value = msg.target.battery;
2025-06-05 21:32:51 +08:00
}
2025-06-09 01:17:18 +08:00
playersScores.value[msg.userId].push(msg.target);
2025-06-05 21:32:51 +08:00
}
2025-06-17 21:34:41 +08:00
if (msg.constructor === MESSAGETYPES.HalfTimeOver) {
2025-06-22 01:41:51 +08:00
startCount.value = false;
2025-06-20 11:22:41 +08:00
halfTimeTip.value = true;
tips.value = "准备下半场";
2025-06-17 21:34:41 +08:00
}
2025-06-05 21:32:51 +08:00
if (msg.constructor === MESSAGETYPES.MatchOver) {
uni.redirectTo({
2025-06-17 16:02:29 +08:00
url: `/pages/battle-result?battleId=${msg.id}`,
2025-06-05 21:32:51 +08:00
});
}
});
}
onMounted(() => {
uni.$on("socket-inbox", onReceiveMessage);
});
onUnmounted(() => {
uni.$off("socket-inbox", onReceiveMessage);
2025-06-25 21:54:18 +08:00
if (gameType.value && teamSize.value) {
matchGameAPI(true, gameType.value, teamSize.value);
2025-06-05 21:32:51 +08:00
}
});
2025-05-16 15:56:54 +08:00
</script>
<template>
2025-06-25 21:54:18 +08:00
<Container :title="battleId ? '大乱斗排位赛' : '搜索对手...'" :bgType="1">
2025-06-05 21:32:51 +08:00
<view class="container">
2025-06-25 21:54:18 +08:00
<block v-if="battleId">
<BattleHeader v-if="players.length" :players="players" />
<Guide noBg v-if="!start && battleId">
<view :style="{ display: 'flex', justifyContent: 'space-between' }">
<view :style="{ display: 'flex', flexDirection: 'column' }">
<text :style="{ color: '#fed847' }">请预先射几箭测试</text>
<text>请确保射击距离只有5米</text>
</view>
<BowPower :power="45" />
2025-06-09 12:24:01 +08:00
</view>
2025-06-25 21:54:18 +08:00
</Guide>
<ShootProgress
v-if="start"
:seq="seq"
:start="startCount"
:tips="tips"
/>
<view v-if="start" class="infos">
<Avatar :src="user.avatar" :size="35" />
<BowPower :power="power" />
2025-06-09 12:24:01 +08:00
</view>
2025-06-25 21:54:18 +08:00
<BowTarget
v-if="battleId"
:showE="start"
:currentRound="scores.length"
:totalRound="start ? 12 : 0"
:scores="scores"
/>
2025-06-26 22:54:17 +08:00
<view :style="{ paddingBottom: '20px' }">
<PlayerScore
v-if="start"
v-for="(player, index) in players"
:key="index"
:name="player.name"
:avatar="player.avatar"
:scores="playersScores[player.id]"
:done="playersScores[player.id].length === 12"
/>
</view>
2025-06-25 21:54:18 +08:00
<Timer :seq="timerSeq" :callBack="readyToGo" />
<ScreenHint
:show="halfTimeTip"
mode="small"
:onClose="() => (halfTimeTip = false)"
>
<view class="half-time-tip">
<text>上半场结束休息一下吧:</text>
<text>20秒后开始下半场</text>
</view>
</ScreenHint>
</block>
<block v-else>
<Matching
v-if="!battleId"
:stopMatch="stopMatch"
:onComplete="onComplete"
/>
</block>
2025-06-05 21:32:51 +08:00
</view>
2025-06-18 21:30:54 +08:00
<view :style="{ marginBottom: '20px' }">
2025-06-15 15:53:57 +08:00
<SButton v-if="battleId && !start" :onClick="readyToGo">准备完毕</SButton>
</view>
2025-06-05 21:32:51 +08:00
</Container>
2025-05-16 15:56:54 +08:00
</template>
<style scoped>
.container {
width: 100%;
2025-06-25 21:54:18 +08:00
height: 100%;
2025-05-16 15:56:54 +08:00
}
2025-06-17 16:02:29 +08:00
.infos {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15px;
padding-top: 15px;
}
2025-06-20 11:22:41 +08:00
.half-time-tip {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding-top: 52px;
}
.half-time-tip > text:last-child {
margin-top: 20px;
color: #fff9;
}
2025-05-16 15:56:54 +08:00
</style>