Files
shoot-miniprograms/src/components/BowTarget.vue

221 lines
4.3 KiB
Vue
Raw Normal View History

2025-05-10 16:57:36 +08:00
<script setup>
2025-06-08 12:52:49 +08:00
import { ref, watch } from "vue";
2025-05-16 15:56:54 +08:00
import BowPower from "@/components/BowPower.vue";
2025-05-29 23:45:44 +08:00
const props = defineProps({
2025-05-10 16:57:36 +08:00
totalRound: {
type: Number,
default: 0,
},
currentRound: {
type: Number,
default: 0,
},
avatar: {
type: String,
default: "",
},
power: {
type: Number,
default: 0,
},
tips: {
type: String,
default: "",
},
debug: {
type: Boolean,
default: false,
},
2025-05-29 23:45:44 +08:00
scores: {
type: Array,
default: () => [],
},
2025-06-14 22:45:07 +08:00
blueScores: {
type: Array,
default: () => [],
},
2025-06-17 16:02:29 +08:00
showLatestArrow: {
2025-06-08 20:59:41 +08:00
type: Boolean,
default: true,
},
2025-06-17 19:35:21 +08:00
showE: {
type: Boolean,
default: true,
},
2025-05-10 16:57:36 +08:00
});
2025-05-29 23:45:44 +08:00
2025-06-08 12:52:49 +08:00
const showRoundTips = ref(false);
2025-06-15 15:53:57 +08:00
const prevLength = ref(0);
2025-06-15 20:55:34 +08:00
const timer = ref(null);
2025-06-08 12:52:49 +08:00
watch(
() => props.scores,
(newVal) => {
2025-06-15 15:53:57 +08:00
if (newVal.length - prevLength.value === 1) {
2025-06-15 20:55:34 +08:00
if (timer.value) clearTimeout(timer.value);
2025-06-08 12:52:49 +08:00
showRoundTips.value = true;
2025-06-15 20:55:34 +08:00
timer.value = setTimeout(() => {
2025-06-08 12:52:49 +08:00
showRoundTips.value = false;
2025-06-15 15:53:57 +08:00
}, 1000);
2025-06-08 12:52:49 +08:00
}
2025-06-15 15:53:57 +08:00
prevLength.value = newVal.length;
2025-06-08 12:52:49 +08:00
},
{
deep: true,
}
);
2025-05-29 23:45:44 +08:00
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)`;
}
2025-05-10 16:57:36 +08:00
</script>
2025-05-08 22:05:53 +08:00
<template>
<view class="container">
<view class="header">
2025-05-30 13:58:43 +08:00
<text v-if="debug" class="header-tips">大人请射箭</text>
2025-05-16 15:56:54 +08:00
<text v-if="totalRound > 0" class="round-count">{{
2025-05-31 14:57:25 +08:00
(currentRound > totalRound ? totalRound : currentRound) +
"/" +
totalRound
2025-05-10 16:57:36 +08:00
}}</text>
2025-06-15 20:55:34 +08:00
<BowPower :power="power" />
2025-05-08 22:05:53 +08:00
</view>
2025-05-29 23:45:44 +08:00
<view class="target">
2025-06-08 20:59:41 +08:00
<view
2025-06-17 19:35:21 +08:00
v-if="scores.length && showRoundTips && showLatestArrow && showE"
2025-06-08 20:59:41 +08:00
class="e-value fade-in"
2025-06-08 12:52:49 +08:00
>经验 +1</view
>
2025-06-17 16:02:29 +08:00
<view
v-if="scores.length && showRoundTips && showLatestArrow"
class="round-tip fade-in"
2025-06-08 12:52:49 +08:00
>{{ scores[scores.length - 1].ring }}<text></text></view
>
2025-06-17 19:35:21 +08:00
<block v-for="(bow, index) in scores" :key="index">
<image
v-if="bow.ring > 0"
:src="
index === scores.length - 1 && !blueScores.length && showLatestArrow
? '../static/hit-icon-green.png'
: '../static/hit-icon.png'
"
:class="`hit ${
index + 1 === scores.length && !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"
:style="{
left: calcRealX(bow.x),
top: calcRealY(bow.y),
}"
/>
</block>
2025-05-29 23:45:44 +08:00
<image src="../static/bow-target.png" mode="widthFix" />
</view>
2025-05-16 15:56:54 +08:00
<view v-if="avatar" class="footer">
2025-05-10 16:57:36 +08:00
<image :src="avatar" mode="widthFix" />
</view>
<text v-if="tips">{{ tips }}</text>
2025-05-08 22:05:53 +08:00
</view>
</template>
<style scoped>
.container {
width: calc(100% - 30px);
2025-06-05 22:21:40 +08:00
padding: 15px;
2025-06-17 16:58:24 +08:00
/* overflow: hidden; */
2025-05-08 22:05:53 +08:00
}
2025-05-29 23:45:44 +08:00
.target {
position: relative;
}
2025-06-08 12:52:49 +08:00
.e-value {
position: absolute;
top: 30%;
left: 60%;
background-color: #0006;
color: #fff;
font-size: 12px;
padding: 4px 7px;
border-radius: 5px;
2025-06-13 16:36:18 +08:00
z-index: 2;
2025-06-08 12:52:49 +08:00
}
.round-tip {
position: absolute;
top: 38%;
left: 60%;
color: #fff;
font-size: 30px;
font-weight: bold;
2025-06-13 16:36:18 +08:00
z-index: 2;
2025-06-08 12:52:49 +08:00
}
.round-tip > text {
font-size: 18px;
margin-left: 5px;
}
2025-05-29 23:45:44 +08:00
.target > image:last-child {
2025-05-08 22:05:53 +08:00
width: 100%;
}
2025-05-29 23:45:44 +08:00
.hit {
position: absolute;
width: 20px;
height: 20px;
2025-06-13 16:36:18 +08:00
z-index: 1;
2025-05-29 23:45:44 +08:00
}
2025-05-08 22:05:53 +08:00
.header {
2025-05-10 22:16:59 +08:00
width: 100%;
2025-05-08 22:05:53 +08:00
display: flex;
align-items: center;
justify-content: space-between;
}
2025-05-10 16:57:36 +08:00
.header > image:first-child {
2025-05-08 22:05:53 +08:00
width: 40px;
height: 40px;
}
2025-05-16 15:56:54 +08:00
.round-count {
2025-05-10 16:57:36 +08:00
font-size: 20px;
color: #fed847;
top: 75px;
}
.header-tips {
font-size: 20px;
color: #fed847;
}
.footer {
width: calc(100% - 20px);
padding: 0 10px;
display: flex;
margin-top: -40px;
}
.footer > image {
width: 40px;
height: 40px;
2025-05-30 13:58:43 +08:00
border-radius: 50%;
2025-05-10 16:57:36 +08:00
}
.container > text {
width: 100%;
color: #fed847;
text-align: center;
line-height: 40px;
display: block;
margin-top: 20px;
}
2025-05-08 22:05:53 +08:00
</style>