287 lines
5.8 KiB
Vue
287 lines
5.8 KiB
Vue
<script setup>
|
||
import { ref, watch } from "vue";
|
||
import BowPower from "@/components/BowPower.vue";
|
||
import StartCountdown from "@/components/StartCountdown.vue";
|
||
import { simulShootAPI } from "@/apis";
|
||
import useStore from "@/store";
|
||
import { storeToRefs } from "pinia";
|
||
const store = useStore();
|
||
const { device } = storeToRefs(store);
|
||
|
||
const props = defineProps({
|
||
totalRound: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
currentRound: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
avatar: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
power: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
tips: {
|
||
type: String,
|
||
default: "",
|
||
},
|
||
scores: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
blueScores: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
showLatestArrow: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
start: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showE: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
start: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
mode: {
|
||
type: String,
|
||
default: "solo", // solo 单排,team 双排
|
||
},
|
||
});
|
||
|
||
const showRoundTips = ref(false);
|
||
const startCount = ref(false);
|
||
const prevLength = ref(0);
|
||
const timer = ref(null);
|
||
|
||
watch(
|
||
() => props.start,
|
||
(newVal) => {
|
||
if (newVal) {
|
||
startCount.value = true;
|
||
}
|
||
},
|
||
{
|
||
immediate: true,
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => props.scores,
|
||
(newVal) => {
|
||
if (newVal.length - prevLength.value === 1) {
|
||
if (timer.value) clearTimeout(timer.value);
|
||
showRoundTips.value = true;
|
||
timer.value = setTimeout(() => {
|
||
showRoundTips.value = false;
|
||
}, 1000);
|
||
}
|
||
prevLength.value = newVal.length;
|
||
},
|
||
{
|
||
deep: true,
|
||
}
|
||
);
|
||
|
||
watch(
|
||
() => props.blueScores,
|
||
(newVal) => {
|
||
if (newVal.length - prevLength.value === 1) {
|
||
if (timer.value) clearTimeout(timer.value);
|
||
showRoundTips.value = true;
|
||
timer.value = setTimeout(() => {
|
||
showRoundTips.value = false;
|
||
}, 1000);
|
||
}
|
||
prevLength.value = newVal.length;
|
||
},
|
||
{
|
||
deep: true,
|
||
}
|
||
);
|
||
|
||
function calcRealX(num) {
|
||
const len = 20 + num;
|
||
return `calc(${(len / 40) * 100}% - 10px)`;
|
||
}
|
||
function calcRealY(num) {
|
||
const len = num < 0 ? Math.abs(num) + 20 : 20 - num;
|
||
return `calc(${(len / 40) * 100}% - 10px)`;
|
||
}
|
||
const simulShoot = async () => {
|
||
if (device.value.deviceId) await simulShootAPI(device.value.deviceId);
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<view class="container">
|
||
<view class="header" v-if="totalRound > 0 || power">
|
||
<text v-if="totalRound > 0" class="round-count">{{
|
||
(currentRound > totalRound ? totalRound : currentRound) +
|
||
"/" +
|
||
totalRound
|
||
}}</text>
|
||
<BowPower :power="power" />
|
||
</view>
|
||
<view class="target">
|
||
<view
|
||
v-if="scores.length && showRoundTips && showLatestArrow && showE"
|
||
class="e-value fade-in"
|
||
>
|
||
经验 +1
|
||
</view>
|
||
<view
|
||
v-if="scores.length && showRoundTips && showLatestArrow"
|
||
class="round-tip fade-in"
|
||
>{{ scores[scores.length - 1].ring }}<text>环</text></view
|
||
>
|
||
<view
|
||
v-if="blueScores.length && showRoundTips && showLatestArrow"
|
||
class="round-tip fade-in"
|
||
>{{ blueScores[blueScores.length - 1].ring }}<text>环</text></view
|
||
>
|
||
<block v-for="(bow, index) in scores" :key="index">
|
||
<image
|
||
v-if="bow.ring > 0"
|
||
:src="
|
||
index === scores.length - 1 &&
|
||
!blueScores.length &&
|
||
showLatestArrow &&
|
||
mode !== 'team'
|
||
? '../static/hit-icon-green.png'
|
||
: '../static/hit-icon.png'
|
||
"
|
||
:class="`hit ${
|
||
index === scores.length - 1 && !blueScores.length && showLatestArrow
|
||
? 'pump-in'
|
||
: ''
|
||
}`"
|
||
:style="{
|
||
left: calcRealX(bow.x),
|
||
top: calcRealY(bow.y),
|
||
}"
|
||
/>
|
||
</block>
|
||
<block v-for="(bow, index) in blueScores" :key="index">
|
||
<image
|
||
v-if="bow.ring > 0"
|
||
src="../static/hit-icon-blue.png"
|
||
class="hit"
|
||
:class="`hit ${blueScores.length === 1 ? 'pump-in' : ''}`"
|
||
:style="{
|
||
left: calcRealX(bow.x),
|
||
top: calcRealY(bow.y),
|
||
}"
|
||
/>
|
||
</block>
|
||
<image src="../static/bow-target.png" mode="widthFix" />
|
||
</view>
|
||
<view v-if="avatar" class="footer">
|
||
<image :src="avatar" mode="widthFix" />
|
||
</view>
|
||
<text v-if="tips">{{ tips }}</text>
|
||
<view class="simul" @click="simulShoot" :style="{ color: '#fff' }">
|
||
模拟射箭
|
||
</view>
|
||
<StartCountdown :start="startCount" />
|
||
</view>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.container {
|
||
width: calc(100% - 30px);
|
||
padding: 15px;
|
||
/* overflow: hidden; */
|
||
position: relative;
|
||
}
|
||
.target {
|
||
position: relative;
|
||
padding: 10px;
|
||
}
|
||
.e-value {
|
||
position: absolute;
|
||
top: 30%;
|
||
left: 60%;
|
||
background-color: #0006;
|
||
color: #fff;
|
||
font-size: 12px;
|
||
padding: 4px 7px;
|
||
border-radius: 5px;
|
||
z-index: 2;
|
||
}
|
||
.round-tip {
|
||
position: absolute;
|
||
top: 38%;
|
||
left: 60%;
|
||
color: #fff;
|
||
font-size: 30px;
|
||
font-weight: bold;
|
||
z-index: 2;
|
||
}
|
||
.round-tip > text {
|
||
font-size: 24px;
|
||
margin-left: 5px;
|
||
}
|
||
.target > image:last-child {
|
||
width: 100%;
|
||
}
|
||
.hit {
|
||
position: absolute;
|
||
width: 20px;
|
||
height: 20px;
|
||
z-index: 1;
|
||
}
|
||
.header {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.header > image:first-child {
|
||
width: 40px;
|
||
height: 40px;
|
||
}
|
||
.round-count {
|
||
font-size: 20px;
|
||
color: #fed847;
|
||
top: 75px;
|
||
}
|
||
.footer {
|
||
width: calc(100% - 20px);
|
||
padding: 0 10px;
|
||
display: flex;
|
||
margin-top: -40px;
|
||
}
|
||
.footer > image {
|
||
width: 40px;
|
||
min-height: 40px;
|
||
max-height: 40px;
|
||
border-radius: 50%;
|
||
}
|
||
.container > text {
|
||
width: 100%;
|
||
color: #fed847;
|
||
text-align: center;
|
||
line-height: 40px;
|
||
display: block;
|
||
margin-top: 20px;
|
||
}
|
||
.simul {
|
||
position: absolute;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
color: #fff;
|
||
margin-left: 20px;
|
||
}
|
||
</style>
|