添加2v2页面
This commit is contained in:
@@ -37,6 +37,12 @@ onMounted(() => {
|
||||
src="../static/app-bg3.png"
|
||||
:style="{ height: capsuleHeight + 'px' }"
|
||||
/>
|
||||
<image
|
||||
class="bg-image"
|
||||
v-if="type === 3"
|
||||
src="../static/app-bg4.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<view class="bg-overlay" v-if="type === 0"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup>
|
||||
import BowPower from "@/components/BowPower.vue";
|
||||
import { RoundImages } from "@/constants";
|
||||
defineProps({
|
||||
roundResults: {
|
||||
type: Array,
|
||||
@@ -17,6 +19,12 @@ defineProps({
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="guide-row">
|
||||
<image src="../static/shooter.png" mode="widthFix" />
|
||||
<view :style="{ marginBottom: '10px', transform: 'scale(0.8) translateX(10px)' }">
|
||||
<BowPower :power="20" />
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<image src="../static/battle-header-melee.png" mode="widthFix" />
|
||||
<text>蓝队({{ bluePoints }})</text>
|
||||
@@ -25,10 +33,7 @@ defineProps({
|
||||
<view class="players">
|
||||
<view>
|
||||
<view v-for="(result, index) in roundResults" :key="index">
|
||||
<text
|
||||
>{{ index > 4 ? "决金箭" : "Round" }}
|
||||
{{ index > 4 ? `R${index - 4}` : index + 1 }}</text
|
||||
>
|
||||
<image :src="RoundImages[`round${index + 1}`]" mode="widthFix" />
|
||||
<view>
|
||||
<text>{{
|
||||
result.blueArrows.length
|
||||
@@ -42,9 +47,9 @@ defineProps({
|
||||
</view>
|
||||
<block v-if="roundResults.length < 3">
|
||||
<view v-for="i in 3 - roundResults.length" :key="i">
|
||||
<text>Round</text>
|
||||
<image :src="RoundImages[`round${i}`]" mode="widthFix" />
|
||||
<view>
|
||||
<text></text>
|
||||
<text>{{ i }}</text>
|
||||
<text>环</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -52,10 +57,7 @@ defineProps({
|
||||
</view>
|
||||
<view>
|
||||
<view v-for="(result, index) in roundResults" :key="index">
|
||||
<text
|
||||
>{{ index > 4 ? "决金箭" : "Round" }}
|
||||
{{ index > 4 ? `R${index - 4}` : index + 1 }}</text
|
||||
>
|
||||
<image :src="RoundImages[`round${index + 1}`]" mode="widthFix" />
|
||||
<view>
|
||||
<text>{{
|
||||
result.redArrows.length
|
||||
@@ -69,7 +71,7 @@ defineProps({
|
||||
</view>
|
||||
<block v-if="roundResults.length < 3">
|
||||
<view v-for="i in 3 - roundResults.length" :key="i">
|
||||
<text>Round</text>
|
||||
<image :src="RoundImages[`round${i}`]" mode="widthFix" />
|
||||
<view>
|
||||
<text></text>
|
||||
<text>环</text>
|
||||
@@ -84,31 +86,25 @@ defineProps({
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
overflow: hidden;
|
||||
margin-top: -40px;
|
||||
}
|
||||
.container > view:first-child {
|
||||
.container > view:nth-child(2) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
.container > view:first-child > image:first-child {
|
||||
.container > view:nth-child(2) > image:first-child {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: -6px;
|
||||
}
|
||||
.container > view:first-child > text {
|
||||
.container > view:nth-child(2) > text {
|
||||
z-index: 1;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.container > view:first-child > text:nth-child(2) {
|
||||
color: #364469;
|
||||
}
|
||||
.container > view:first-child > text:nth-child(3) {
|
||||
color: #692735;
|
||||
}
|
||||
.players {
|
||||
display: flex;
|
||||
}
|
||||
@@ -121,35 +117,42 @@ defineProps({
|
||||
color: #fff;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.players > view:first-child {
|
||||
background-color: #364469;
|
||||
.players > view:first-child > view {
|
||||
background: linear-gradient(270deg, #172a86 0%, #0006 100%);
|
||||
}
|
||||
.players > view:last-child {
|
||||
background-color: #692735;
|
||||
.players > view:last-child > view {
|
||||
background: linear-gradient(270deg, #0006 0%, #6a1212 100%);
|
||||
}
|
||||
.players > view > view {
|
||||
min-height: 28px;
|
||||
width: 85%;
|
||||
padding: 5px 20px;
|
||||
min-height: 25px;
|
||||
width: calc(100% - 40px);
|
||||
padding: 2px 20px;
|
||||
margin-bottom: 5px;
|
||||
background-image: url("../static/row-bg.png");
|
||||
background-size: 90% 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.players > view > view > text {
|
||||
font-size: 14px;
|
||||
.players > view > view > image:first-child {
|
||||
width: 72px;
|
||||
}
|
||||
.players > view > view > view:last-child {
|
||||
font-size: 14px;
|
||||
padding-right: 20px;
|
||||
font-size: 10px;
|
||||
}
|
||||
.players > view > view > view:last-child > text:first-child {
|
||||
font-size: 20px;
|
||||
font-size: 16px;
|
||||
color: #fed847;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.guide-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
padding: 0 5vw;
|
||||
margin-bottom: -4px;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
.guide-row > image {
|
||||
width: 18%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,11 +18,11 @@ defineProps({
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #b9b9b9;
|
||||
color: #ffffffa8;
|
||||
font-size: 13px;
|
||||
}
|
||||
.container > image {
|
||||
width: 22px;
|
||||
width: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import HeaderProgress from "@/components/HeaderProgress.vue";
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
@@ -24,6 +25,7 @@ const onClick = () => {
|
||||
const loading = ref(false);
|
||||
const showLoader = ref(false);
|
||||
const pointBook = ref(null);
|
||||
const showProgress = ref(false);
|
||||
const updateLoading = (value) => {
|
||||
loading.value = value;
|
||||
};
|
||||
@@ -42,6 +44,9 @@ onMounted(() => {
|
||||
showLoader.value = true;
|
||||
}
|
||||
uni.$on("update-header-loading", updateLoading);
|
||||
if (currentPage.route === "pages/team-battle") {
|
||||
showProgress.value = true;
|
||||
}
|
||||
});
|
||||
onUnmounted(() => {
|
||||
uni.$off("update-header-loading", updateLoading);
|
||||
@@ -110,6 +115,9 @@ onUnmounted(() => {
|
||||
}}</text
|
||||
>
|
||||
</view>
|
||||
<view v-if="showProgress" class="battle-progress">
|
||||
<HeaderProgress />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -176,4 +184,11 @@ onUnmounted(() => {
|
||||
padding: 5px 10px;
|
||||
margin: 3px;
|
||||
}
|
||||
.battle-progress {
|
||||
position: fixed;
|
||||
width: 60%;
|
||||
left: 20%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
134
src/components/HeaderProgress.vue
Normal file
134
src/components/HeaderProgress.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from "vue";
|
||||
import audioManager from "@/audioManager";
|
||||
import { MESSAGETYPES } from "@/constants";
|
||||
import useStore from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
const store = useStore();
|
||||
const { user } = storeToRefs(store);
|
||||
|
||||
const tips = ref("请蓝队射击");
|
||||
const battleId = ref("");
|
||||
const isMelee = ref("");
|
||||
const timer = ref(null);
|
||||
const sound = ref(true);
|
||||
const currentSound = ref("");
|
||||
const currentRound = ref(1);
|
||||
const totalRound = ref(6);
|
||||
const currentRoundEnded = ref(false);
|
||||
const ended = ref(false);
|
||||
const halfTime = ref(false);
|
||||
|
||||
// watch(
|
||||
// () => props.tips,
|
||||
// (newVal) => {
|
||||
// let key = "";
|
||||
// if (newVal.includes("红队")) key = "请红方射击";
|
||||
// if (newVal.includes("蓝队")) key = "请蓝方射击";
|
||||
// if (key && sound.value) {
|
||||
// if (currentRoundEnded.value) {
|
||||
// currentRound.value += 1;
|
||||
// currentRoundEnded.value = false;
|
||||
// if (currentRound.value === 1) audioManager.play("第一轮");
|
||||
// if (currentRound.value === 2) audioManager.play("第二轮");
|
||||
// if (currentRound.value === 3) audioManager.play("第三轮");
|
||||
// if (currentRound.value === 4) audioManager.play("第四轮");
|
||||
// if (currentRound.value === 5) audioManager.play("第五轮");
|
||||
// setTimeout(() => {
|
||||
// audioManager.play(key);
|
||||
// }, 1000);
|
||||
// } else {
|
||||
// audioManager.play(key);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
|
||||
const updateSound = () => {
|
||||
sound.value = !sound.value;
|
||||
if (!sound.value) audioManager.stop(currentSound.value);
|
||||
};
|
||||
|
||||
async function onReceiveMessage(messages = []) {
|
||||
if (!sound.value || ended.value) return;
|
||||
messages.forEach((msg) => {
|
||||
if (
|
||||
(battleId.value && msg.constructor === MESSAGETYPES.ShootResult) ||
|
||||
(!battleId.value && msg.constructor === MESSAGETYPES.ShootSyncMeArrowID)
|
||||
) {
|
||||
if (melee.value && msg.userId !== user.value.id) return;
|
||||
if (!halfTime.value && msg.target) {
|
||||
currentSound.value = msg.target.ring
|
||||
? `${msg.target.ring}环`
|
||||
: "未上靶";
|
||||
audioManager.play(currentSound.value);
|
||||
}
|
||||
} else if (msg.constructor === MESSAGETYPES.AllReady) {
|
||||
audioManager.play("比赛开始");
|
||||
} else if (msg.constructor === MESSAGETYPES.MeleeAllReady) {
|
||||
halfTime.value = false;
|
||||
audioManager.play("比赛开始");
|
||||
} else if (msg.constructor === MESSAGETYPES.CurrentRoundEnded) {
|
||||
currentRoundEnded.value = true;
|
||||
} else if (msg.constructor === MESSAGETYPES.HalfTimeOver) {
|
||||
halfTime.value = true;
|
||||
audioManager.play("中场休息");
|
||||
} else if (msg.constructor === MESSAGETYPES.MatchOver) {
|
||||
audioManager.play("比赛结束");
|
||||
} else if (msg.constructor === MESSAGETYPES.FinalShoot) {
|
||||
audioManager.play("决金箭轮");
|
||||
} else if (msg.constructor === MESSAGETYPES.ShootSyncMePracticeID) {
|
||||
ended.value = true;
|
||||
} else if (msg.constructor === MESSAGETYPES.MatchOver) {
|
||||
ended.value = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const playSound = (key) => {
|
||||
currentSound.value = key;
|
||||
audioManager.play(key);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
uni.$on("socket-inbox", onReceiveMessage);
|
||||
uni.$on("play-sound", playSound);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off("socket-inbox", onReceiveMessage);
|
||||
uni.$off("play-sound", playSound);
|
||||
if (timer.value) clearInterval(timer.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<text>{{ tips }}</text>
|
||||
<text>({{ currentRound }}/{{ totalRound }})</text>
|
||||
<button hover-class="none" @click="updateSound">
|
||||
<image
|
||||
:src="`../static/sound${sound ? '' : '-off'}-yellow.png`"
|
||||
mode="widthFix"
|
||||
/>
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 50vw;
|
||||
color: #fed847;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container > button:last-child {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.container > button:last-child > image {
|
||||
width: 36px;
|
||||
min-height: 36px;
|
||||
}
|
||||
</style>
|
||||
115
src/components/ShootProgress2.vue
Normal file
115
src/components/ShootProgress2.vue
Normal file
@@ -0,0 +1,115 @@
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from "vue";
|
||||
import { RoundGoldImages } from "@/constants";
|
||||
const props = defineProps({
|
||||
tips: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 15,
|
||||
},
|
||||
currentRound: {
|
||||
type: String,
|
||||
default: "round1",
|
||||
},
|
||||
});
|
||||
|
||||
const barColor = ref("linear-gradient( 180deg, #FFA0A0 0%, #FF6060 100%)");
|
||||
const remain = ref(10);
|
||||
const timer = ref(null);
|
||||
|
||||
watch(
|
||||
() => props.tips,
|
||||
(newVal) => {
|
||||
if (newVal.includes("红队"))
|
||||
barColor.value = "linear-gradient( 180deg, #FFA0A0 0%, #FF6060 100%)";
|
||||
if (newVal.includes("蓝队"))
|
||||
barColor.value = "linear-gradient( 180deg, #9AB3FF 0%, #4288FF 100%)";
|
||||
if (newVal.includes("红队") || newVal.includes("蓝队")) {
|
||||
if (timer.value) clearInterval(timer.value);
|
||||
remain.value = props.total;
|
||||
timer.value = setInterval(() => {
|
||||
if (remain.value > 0) remain.value--;
|
||||
}, 1000);
|
||||
}
|
||||
console.log(barColor.value);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
const updateRemain = (value) => {
|
||||
if (timer.value) clearInterval(timer.value);
|
||||
remain.value = Math.round(value);
|
||||
if (remain.value > 0) {
|
||||
timer.value = setInterval(() => {
|
||||
if (remain.value > 0) remain.value--;
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
uni.$on("update-ramain", updateRemain);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.$off("update-ramain", updateRemain);
|
||||
if (timer.value) clearInterval(timer.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<image :src="RoundGoldImages[props.currentRound]" mode="widthFix" />
|
||||
<view>
|
||||
<view
|
||||
:style="{
|
||||
width: `${(remain / total) * 100}%`,
|
||||
background: barColor,
|
||||
right: tips.includes('红队') ? 0 : 'unset',
|
||||
}"
|
||||
/>
|
||||
<text>剩余{{ remain }}秒</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 50vw;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 12vw;
|
||||
}
|
||||
.container > image {
|
||||
width: 100%;
|
||||
transform: translateY(7px);
|
||||
}
|
||||
.container > view:last-child {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
background-color: #444444;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.container > view:last-child > view {
|
||||
position: absolute;
|
||||
height: 15px;
|
||||
border-radius: 15px;
|
||||
transition: all 1s linear;
|
||||
}
|
||||
.container > view:last-child > text {
|
||||
font-size: 10px;
|
||||
line-height: 15px;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
94
src/components/TeamAvatars.vue
Normal file
94
src/components/TeamAvatars.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
const props = defineProps({
|
||||
isRed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
team: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
youTurn: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
const players = ref(props.team);
|
||||
watch(
|
||||
() => props.youTurn,
|
||||
(newVal) => {
|
||||
players.value = props.team;
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view
|
||||
v-for="(item, index) in team"
|
||||
:key="index"
|
||||
class="player"
|
||||
:style="{
|
||||
width: (youTurn ? 40 - index * 5 : 30) + 'px',
|
||||
height: (youTurn ? 40 - index * 5 : 30) + 'px',
|
||||
borderColor: isRed ? '#ff6060' : '#5fadff',
|
||||
zIndex: players.length - index,
|
||||
top: youTurn ? index * 2 + 'px' : '6px',
|
||||
left: (isRed ? index * 20 : 35 - index * 15) + 'px',
|
||||
}"
|
||||
>
|
||||
<image :src="item.avatar || '../static/user-icon.png'" mode="widthFix" />
|
||||
<text
|
||||
v-if="youTurn && index === 0"
|
||||
:style="{ backgroundColor: isRed ? '#ff6060' : '#5fadff' }"
|
||||
>{{ isRed ? "红队" : "蓝队" }}</text
|
||||
>
|
||||
</view>
|
||||
<text
|
||||
v-if="youTurn"
|
||||
class="truncate"
|
||||
:style="{
|
||||
color: isRed ? '#ff6060' : '#5fadff',
|
||||
[isRed ? 'left' : 'right']: 0,
|
||||
}"
|
||||
>{{ team[0].name }}</text
|
||||
>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 20vw;
|
||||
height: 45px;
|
||||
}
|
||||
.container > text {
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
bottom: -12px;
|
||||
}
|
||||
.player {
|
||||
transition: all 0.3s ease;
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 1px solid;
|
||||
}
|
||||
.player > image {
|
||||
width: 100%;
|
||||
}
|
||||
.player > text {
|
||||
position: absolute;
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -174,3 +174,25 @@ export const getBattleResultTips = (
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
export const RoundImages = {
|
||||
"round1":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slggifbnw9snvs.png",
|
||||
"round2":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgf0swue5xzpd.png",
|
||||
"round3":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slglkylhmq8beb.png",
|
||||
"round4":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slggc88nasmxf5.png",
|
||||
"round5":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgeloitb8mixf.png",
|
||||
"round6":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgsjbyyuu1des.png",
|
||||
"round7":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgdysd1wqulj5.png",
|
||||
"round8":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgm82ny3qjd8m.png",
|
||||
}
|
||||
|
||||
export const RoundGoldImages = {
|
||||
"round1":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slg7kfzzwwiwcb.png",
|
||||
"round2":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgs5htghfh3a9.png",
|
||||
"round3":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgc9ge3paqkba.png",
|
||||
"round4":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgehduk96yurp.png",
|
||||
"round5":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgefz3hdmwbnz.png",
|
||||
"round6":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgeyb4cqwezgc.png",
|
||||
"round7":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slggu3tlh97v5p.png",
|
||||
"round8":"https://static.shelingxingqiu.com/attachment/2025-08-13/dc12slgszmdtmaotch.png",
|
||||
}
|
||||
@@ -6,6 +6,9 @@
|
||||
{
|
||||
"path": "pages/battle-result"
|
||||
},
|
||||
{
|
||||
"path": "pages/team-battle"
|
||||
},
|
||||
{
|
||||
"path": "pages/point-book-edit"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,12 @@ const room = ref({});
|
||||
const roomNumber = ref("");
|
||||
const owner = ref({});
|
||||
const opponent = ref({});
|
||||
const players = ref([]);
|
||||
const players = ref([
|
||||
{ name: "player1", team: 1 },
|
||||
{ name: "player2", team: 0 },
|
||||
{ name: "player3", team: 2 },
|
||||
{ name: "player4", team: 1 },
|
||||
]);
|
||||
|
||||
const showModal = ref(false);
|
||||
const battleType = ref(0);
|
||||
@@ -225,6 +230,8 @@ onHide(() => {});
|
||||
<view :style="{ display: 'flex', flexDirection: 'column' }">
|
||||
<text :style="{ color: '#fed847' }">弓箭手们,人都到齐了吗?</text>
|
||||
<text v-if="battleType === 1">1v1比赛即将开始! </text>
|
||||
<text v-if="battleType === 3">2v2比赛即将开始! </text>
|
||||
<text v-if="battleType === 4">3v3比赛即将开始! </text>
|
||||
<text v-if="battleType === 2">大乱斗即将开始! </text>
|
||||
</view>
|
||||
<view @click="setClipboardData">复制房间号</view>
|
||||
@@ -263,6 +270,41 @@ onHide(() => {});
|
||||
:total="room.count || 10"
|
||||
:players="players"
|
||||
/>
|
||||
<view class="all-players">
|
||||
<image
|
||||
src="https://static.shelingxingqiu.com/attachment/2025-08-13/dc0x1p59iab6cvbhqc.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image src="../static/title-2v2.png" mode="widthFix" />
|
||||
<view>
|
||||
<view v-for="(item, index) in players" :key="index">
|
||||
<Avatar :src="item.avatar" :size="36" />
|
||||
<text v-if="index === 0">创建者</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="choose-side">
|
||||
<view>
|
||||
<view v-for="i in 3" :key="i" class="choose-side-left-item">
|
||||
<button hover-class="none">
|
||||
<image src="../static/close-grey.png" mode="widthFix" />
|
||||
</button>
|
||||
<text class="truncate">23232323232</text>
|
||||
<Avatar :size="36" />
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<view v-for="i in 3" :key="i" class="choose-side-right-item">
|
||||
<button hover-class="none">
|
||||
<image src="../static/add-grey.png" mode="widthFix" />
|
||||
</button>
|
||||
<text class="truncate">22222</text>
|
||||
<button hover-class="none">
|
||||
<image src="../static/close-grey.png" mode="widthFix" />
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<SButton
|
||||
v-if="user.id === owner.id && battleType === 1"
|
||||
@@ -408,4 +450,144 @@ onHide(() => {});
|
||||
border-radius: 20px;
|
||||
position: relative;
|
||||
}
|
||||
.all-players {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 83vw;
|
||||
}
|
||||
.all-players > image:first-child {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
.all-players > image:nth-child(2) {
|
||||
width: 25vw;
|
||||
position: relative;
|
||||
}
|
||||
.all-players > view {
|
||||
position: relative;
|
||||
width: 42vw;
|
||||
height: 42vw;
|
||||
margin-top: 7vw;
|
||||
}
|
||||
.all-players > view > view {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
}
|
||||
/* 4个头像 - 正方形排列 */
|
||||
.all-players > view > view:nth-child(1):nth-last-child(4) {
|
||||
transform: translate(-50%, -50%) rotate(-30deg) translateY(-21.5vw)
|
||||
rotate(30deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(2):nth-last-child(3) {
|
||||
transform: translate(-50%, -50%) rotate(-120deg) translateY(-21.5vw)
|
||||
rotate(120deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(3):nth-last-child(2) {
|
||||
transform: translate(-50%, -50%) rotate(-210deg) translateY(-21.5vw)
|
||||
rotate(210deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(4):nth-last-child(1) {
|
||||
transform: translate(-50%, -50%) rotate(-300deg) translateY(-21.5vw)
|
||||
rotate(300deg);
|
||||
}
|
||||
/* 6个头像 - 六边形排列 */
|
||||
.all-players > view > view:nth-child(1):nth-last-child(6) {
|
||||
transform: translate(-50%, -50%) rotate(-30deg) translateY(-21vw)
|
||||
rotate(30deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(2):nth-last-child(5) {
|
||||
transform: translate(-50%, -50%) rotate(-90deg) translateY(-21vw)
|
||||
rotate(90deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(3):nth-last-child(4) {
|
||||
transform: translate(-50%, -50%) rotate(-150deg) translateY(-21vw)
|
||||
rotate(150deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(4):nth-last-child(3) {
|
||||
transform: translate(-50%, -50%) rotate(-210deg) translateY(-21vw)
|
||||
rotate(210deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(5):nth-last-child(2) {
|
||||
transform: translate(-50%, -50%) rotate(-270deg) translateY(-21vw)
|
||||
rotate(270deg);
|
||||
}
|
||||
.all-players > view > view:nth-child(6):nth-last-child(1) {
|
||||
transform: translate(-50%, -50%) rotate(-330deg) translateY(-21vw)
|
||||
rotate(330deg);
|
||||
}
|
||||
.all-players > view > view > text {
|
||||
position: absolute;
|
||||
background-color: #fed847;
|
||||
font-size: 8px;
|
||||
border-radius: 10px;
|
||||
padding: 1px 0px;
|
||||
bottom: -20%;
|
||||
left: calc(50% - 15px);
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.choose-side {
|
||||
display: flex;
|
||||
}
|
||||
.choose-side > view {
|
||||
width: 50%;
|
||||
}
|
||||
.choose-side > view:first-child > view {
|
||||
background: linear-gradient(270deg, #6a1212 0%, rgba(74, 0, 0, 0) 100%);
|
||||
}
|
||||
.choose-side > view:last-child > view {
|
||||
background: linear-gradient(270deg, rgba(13, 0, 74, 0) 0%, #172a86 100%);
|
||||
}
|
||||
.choose-side-left-item,
|
||||
.choose-side-right-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
align-items: center;
|
||||
margin: 10px 5px;
|
||||
position: relative;
|
||||
}
|
||||
.choose-side-left-item {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.choose-side-left-item > text,
|
||||
.choose-side-right-item > text {
|
||||
margin: 10px;
|
||||
max-width: 100px;
|
||||
}
|
||||
.choose-side-left-item > button:first-child,
|
||||
.choose-side-right-item > button:last-child {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
.choose-side-left-item > button:first-child > image,
|
||||
.choose-side-right-item > button:last-child > image {
|
||||
width: 28px;
|
||||
}
|
||||
.choose-side-left-item > button:first-child {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.choose-side-right-item > button:last-child {
|
||||
right: 0;
|
||||
}
|
||||
.choose-side-left-item > button:last-child,
|
||||
.choose-side-right-item > button:first-child {
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.choose-side-left-item > button:last-child > image,
|
||||
.choose-side-right-item > button:first-child > image {
|
||||
width: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -117,6 +117,7 @@ const onCreateRoom = async () => {
|
||||
src="https://static.shelingxingqiu.com/attachment/2025-07-15/dbcejys872iyun92h6.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image src="../static/room-notfound-title.png" mode="widthFix" />
|
||||
<view>
|
||||
<image :src="user.avatar" mode="widthFix" />
|
||||
<image src="../static/versus.png" mode="widthFix" />
|
||||
@@ -190,39 +191,43 @@ const onCreateRoom = async () => {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
.create-room > view {
|
||||
margin: 0 30px;
|
||||
padding-top: 12%;
|
||||
.create-room > image:nth-of-type(2) {
|
||||
padding: 15px;
|
||||
width: 25vw;
|
||||
position: relative;
|
||||
}
|
||||
.create-room > view:nth-child(3) {
|
||||
margin: 12vw auto;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.create-room > view > image:first-child {
|
||||
width: 18vw;
|
||||
transform: translateX(30%);
|
||||
width: 19vw;
|
||||
transform: translateY(-60%);
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
}
|
||||
.create-room > view > image:nth-child(2) {
|
||||
width: 36vw;
|
||||
transform: translateX(55%) translateY(-40px);
|
||||
width: 37vw;
|
||||
position: relative;
|
||||
}
|
||||
.create-room > view > view:nth-child(3) {
|
||||
width: 18vw;
|
||||
height: 18vw;
|
||||
position: relative;
|
||||
width: 19vw;
|
||||
height: 19vw;
|
||||
border-radius: 50%;
|
||||
background-color: #ccc;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transform: translate(290%, -75px);
|
||||
transform: translateY(60%);
|
||||
}
|
||||
.create-room > view > view:nth-child(3) > image {
|
||||
width: 20px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
.create-room > view:last-child {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
.warnning {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
146
src/pages/team-battle.vue
Normal file
146
src/pages/team-battle.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, nextTick } from "vue";
|
||||
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
|
||||
import Container from "@/components/Container.vue";
|
||||
import BattleHeader from "@/components/BattleHeader.vue";
|
||||
import BowTarget from "@/components/BowTarget.vue";
|
||||
import ShootProgress from "@/components/ShootProgress.vue";
|
||||
import PlayersRow from "@/components/PlayersRow.vue";
|
||||
import Timer from "@/components/Timer.vue";
|
||||
import BattleFooter from "@/components/BattleFooter.vue";
|
||||
import ScreenHint from "@/components/ScreenHint.vue";
|
||||
import SButton from "@/components/SButton.vue";
|
||||
import RoundEndTip from "@/components/RoundEndTip.vue";
|
||||
import TestDistance from "@/components/TestDistance.vue";
|
||||
import TeamAvatars from "@/components/TeamAvatars.vue";
|
||||
import ShootProgress2 from "@/components/ShootProgress2.vue";
|
||||
import { getCurrentGameAPI } from "@/apis";
|
||||
import { isGameEnded } from "@/util";
|
||||
import { MESSAGETYPES, roundsName } from "@/constants";
|
||||
import useStore from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
const store = useStore();
|
||||
const { user } = storeToRefs(store);
|
||||
const start = ref(true);
|
||||
const battleId = ref("");
|
||||
const currentRound = ref(1);
|
||||
const currentRedPoint = ref(0);
|
||||
const currentBluePoint = ref(0);
|
||||
const totalRounds = ref(0);
|
||||
const power = ref(0);
|
||||
const scores = ref([]);
|
||||
const blueScores = ref([]);
|
||||
const redTeam = ref([]);
|
||||
const blueTeam = ref([
|
||||
{
|
||||
name: "选手1",
|
||||
},
|
||||
{
|
||||
name: "选手2",
|
||||
},
|
||||
{
|
||||
name: "选手3",
|
||||
},
|
||||
]);
|
||||
const currentShooterId = ref(0);
|
||||
const tips = ref("即将开始...");
|
||||
const roundResults = ref([]);
|
||||
const redPoints = ref(0);
|
||||
const bluePoints = ref(0);
|
||||
const showRoundTip = ref(false);
|
||||
const isFinalShoot = ref(false);
|
||||
const isEnded = ref(false);
|
||||
|
||||
const onBack = () => {
|
||||
uni.$showHint(2);
|
||||
};
|
||||
function onReceiveMessage() {}
|
||||
|
||||
onLoad(async (options) => {
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
});
|
||||
onMounted(() => {
|
||||
uni.setKeepScreenOn({
|
||||
keepScreenOn: true,
|
||||
});
|
||||
uni.$on("socket-inbox", onReceiveMessage);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
uni.setKeepScreenOn({
|
||||
keepScreenOn: false,
|
||||
});
|
||||
uni.$off("socket-inbox", onReceiveMessage);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container :bgType="3" :onBack="onBack">
|
||||
<view class="container">
|
||||
<BattleHeader v-if="!start" :redTeam="redTeam" :blueTeam="blueTeam" />
|
||||
<TestDistance v-if="!start" :guide="false" />
|
||||
<view class="players-row">
|
||||
<TeamAvatars :team="blueTeam" :isRed="false" :youTurn="true" />
|
||||
<ShootProgress2 :tips="tips" />
|
||||
<TeamAvatars :team="blueTeam" :youTurn="true" />
|
||||
</view>
|
||||
<BowTarget
|
||||
v-if="start"
|
||||
mode="team"
|
||||
:power="start ? power : 0"
|
||||
:scores="scores"
|
||||
:blueScores="blueScores"
|
||||
/>
|
||||
<BattleFooter
|
||||
v-if="start"
|
||||
:roundResults="roundResults"
|
||||
:redPoints="redPoints"
|
||||
:bluePoints="bluePoints"
|
||||
/>
|
||||
<Timer v-if="!start" />
|
||||
<ScreenHint
|
||||
:show="showRoundTip"
|
||||
:onClose="() => (showRoundTip = false)"
|
||||
:mode="isFinalShoot ? 'tall' : 'normal'"
|
||||
>
|
||||
<RoundEndTip
|
||||
v-if="showRoundTip"
|
||||
:isFinal="isFinalShoot"
|
||||
:round="currentRound - 1"
|
||||
:bluePoint="currentBluePoint"
|
||||
:redPoint="currentRedPoint"
|
||||
:roundData="
|
||||
roundResults[roundResults.length - 2]
|
||||
? roundResults[roundResults.length - 2]
|
||||
: []
|
||||
"
|
||||
:onAutoClose="() => (showRoundTip = false)"
|
||||
/>
|
||||
</ScreenHint>
|
||||
</view>
|
||||
</Container>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.players-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
margin-bottom: -7vw;
|
||||
margin-top: -3vw;
|
||||
}
|
||||
</style>
|
||||
BIN
src/static/add-grey.png
Normal file
BIN
src/static/add-grey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 B |
BIN
src/static/app-bg4.png
Normal file
BIN
src/static/app-bg4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
BIN
src/static/room-notfound-title.png
Normal file
BIN
src/static/room-notfound-title.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
BIN
src/static/title-2v2.png
Normal file
BIN
src/static/title-2v2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
BIN
src/static/title-3v3.png
Normal file
BIN
src/static/title-3v3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
Reference in New Issue
Block a user