307 lines
6.8 KiB
Vue
307 lines
6.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,
|
||
},
|
||
scores: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
blueScores: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
showLatestArrow: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
start: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showE: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
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) => {
|
||
// startCount.value = newVal;
|
||
// },
|
||
// {
|
||
// 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, offset = 12) {
|
||
const len = 20.4 + num;
|
||
return `calc(${(len / 40.8) * 100}% - ${offset / 2}px)`;
|
||
}
|
||
function calcRealY(num, offset = 12) {
|
||
const len = num < 0 ? Math.abs(num) + 20.4 : 20.4 - num;
|
||
return `calc(${(len / 40.8) * 100}% - ${offset / 2}px)`;
|
||
}
|
||
const simulShoot = async () => {
|
||
if (device.value.deviceId) await simulShootAPI(device.value.deviceId);
|
||
};
|
||
const simulShoot2 = async () => {
|
||
if (device.value.deviceId) await simulShootAPI(device.value.deviceId, 1, 1);
|
||
};
|
||
</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-out"
|
||
:style="{
|
||
left: calcRealX(scores[scores.length - 1].x, 66),
|
||
top: calcRealY(scores[scores.length - 1].y, 150),
|
||
}"
|
||
>
|
||
经验 +1
|
||
</view>
|
||
<view
|
||
v-if="scores.length && showRoundTips && showLatestArrow"
|
||
class="round-tip fade-in-out"
|
||
:style="{
|
||
left: calcRealX(scores[scores.length - 1].x, 70),
|
||
top: calcRealY(scores[scores.length - 1].y, 100),
|
||
}"
|
||
>{{ scores[scores.length - 1].ring }}<text>环</text></view
|
||
>
|
||
<view
|
||
v-if="blueScores.length && showRoundTips && showLatestArrow"
|
||
class="round-tip fade-in-out"
|
||
:style="{
|
||
left: calcRealX(blueScores[blueScores.length - 1].x, 70),
|
||
top: calcRealY(blueScores[blueScores.length - 1].y, 100),
|
||
}"
|
||
>{{ blueScores[blueScores.length - 1].ring }}<text>环</text></view
|
||
>
|
||
<block v-for="(bow, index) in scores" :key="index">
|
||
<view
|
||
v-if="bow.ring > 0"
|
||
:class="`hit ${
|
||
index === scores.length - 1 && !blueScores.length && showLatestArrow
|
||
? 'pump-in'
|
||
: ''
|
||
}`"
|
||
:style="{
|
||
left: calcRealX(bow.x),
|
||
top: calcRealY(bow.y),
|
||
backgroundColor:
|
||
index === scores.length - 1 &&
|
||
!blueScores.length &&
|
||
showLatestArrow &&
|
||
mode !== 'team'
|
||
? 'green'
|
||
: 'red',
|
||
}"
|
||
>{{ index + 1 }}</view
|
||
>
|
||
</block>
|
||
<block v-for="(bow, index) in blueScores" :key="index">
|
||
<view
|
||
v-if="bow.ring > 0"
|
||
:class="`hit ${
|
||
index === scores.length - 1 && !blueScores.length && showLatestArrow
|
||
? 'pump-in'
|
||
: ''
|
||
}`"
|
||
:style="{
|
||
left: calcRealX(bow.x),
|
||
top: calcRealY(bow.y),
|
||
backgroundColor: 'blue',
|
||
}"
|
||
>{{ bow.ring }}</view
|
||
>
|
||
</block>
|
||
<image src="../static/bow-target.png" mode="widthFix" />
|
||
</view>
|
||
<view v-if="avatar" class="footer">
|
||
<image :src="avatar" mode="widthFix" />
|
||
</view>
|
||
<view class="simul">
|
||
<button @click="simulShoot">模拟</button>
|
||
<button @click="simulShoot2">射箭</button>
|
||
</view>
|
||
<text :style="{ color: '#fff', wordBreak: 'break-all' }">{{
|
||
scores.length ? scores[scores.length - 1] : ""
|
||
}}</text>
|
||
<!-- <StartCountdown :start="startCount" /> -->
|
||
</view>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.container {
|
||
width: calc(100% - 30px);
|
||
padding: 15px;
|
||
position: relative;
|
||
}
|
||
.target {
|
||
position: relative;
|
||
margin: 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;
|
||
width: 50px;
|
||
text-align: center;
|
||
}
|
||
.round-tip {
|
||
position: absolute;
|
||
/* top: 38%; */
|
||
/* left: 60%; */
|
||
color: #fff;
|
||
font-size: 30px;
|
||
font-weight: bold;
|
||
z-index: 2;
|
||
width: 70px;
|
||
text-align: center;
|
||
}
|
||
.round-tip > text {
|
||
font-size: 24px;
|
||
margin-left: 5px;
|
||
}
|
||
.target > image:last-child {
|
||
width: 100%;
|
||
}
|
||
.hit {
|
||
position: absolute;
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
border: 1px solid #fff;
|
||
z-index: 1;
|
||
color: #fff;
|
||
font-size: 8px;
|
||
text-align: center;
|
||
line-height: 10px;
|
||
transition: all 0.3s ease;
|
||
box-sizing: border-box;
|
||
}
|
||
.header {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: -10px;
|
||
}
|
||
.header > image:first-child {
|
||
width: 40px;
|
||
height: 40px;
|
||
}
|
||
.round-count {
|
||
font-size: 20px;
|
||
color: #fed847;
|
||
top: 75px;
|
||
font-weight: bold;
|
||
}
|
||
.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%;
|
||
border: 1px solid #fff;
|
||
}
|
||
.simul {
|
||
position: absolute;
|
||
bottom: 20px;
|
||
right: 20px;
|
||
margin-left: 20px;
|
||
}
|
||
.simul > button {
|
||
color: #fff;
|
||
}
|
||
</style>
|