update:修复大乱斗特效飘移

This commit is contained in:
2026-07-03 17:46:00 +08:00
parent 3c7467fbdf
commit 0a678cb387
2 changed files with 81 additions and 27 deletions
+16 -3
View File
@@ -34,6 +34,7 @@ const phase = ref("idle");
const activePlayKey = ref(""); const activePlayKey = ref("");
const animationKey = ref(""); const animationKey = ref("");
const impactEmitted = ref(false); const impactEmitted = ref(false);
const activeShot = ref(null);
let timers = []; let timers = [];
const isActive = computed(() => phase.value !== "idle"); const isActive = computed(() => phase.value !== "idle");
@@ -54,9 +55,17 @@ const safeTargetSize = computed(() => {
}; };
}); });
function hasShotPoint(shot) {
const x = Number(shot?.x);
const y = Number(shot?.y);
return Number.isFinite(x) && Number.isFinite(y);
}
const effectiveShot = computed(() => activeShot.value || props.shot);
const shotPoint = computed(() => { const shotPoint = computed(() => {
const x = Number(props.shot?.x); const x = Number(effectiveShot.value?.x);
const y = Number(props.shot?.y); const y = Number(effectiveShot.value?.y);
return { return {
x: Number.isFinite(x) ? x : 0, x: Number.isFinite(x) ? x : 0,
y: Number.isFinite(y) ? y : 0, y: Number.isFinite(y) ? y : 0,
@@ -179,16 +188,20 @@ function finish(playKey) {
clearTimers(); clearTimers();
phase.value = "idle"; phase.value = "idle";
activePlayKey.value = ""; activePlayKey.value = "";
activeShot.value = null;
emit("complete", playKey); emit("complete", playKey);
} }
function play() { function play() {
if (!props.playKey || !props.shot || !props.shot.ring) return; if (!props.playKey || !props.shot || !props.shot.ring || !hasShotPoint(props.shot)) {
return;
}
clearTimers(); clearTimers();
activePlayKey.value = props.playKey; activePlayKey.value = props.playKey;
animationKey.value = `${props.playKey}`; animationKey.value = `${props.playKey}`;
impactEmitted.value = false; impactEmitted.value = false;
activeShot.value = { ...props.shot };
phase.value = "playing"; phase.value = "playing";
queueTimer(() => { queueTimer(() => {
+65 -24
View File
@@ -1,5 +1,13 @@
<script setup> <script setup>
import { ref, watch, onMounted, onBeforeUnmount, computed, nextTick } from "vue"; import {
ref,
watch,
onMounted,
onBeforeUnmount,
computed,
nextTick,
getCurrentInstance,
} from "vue";
import PointSwitcher from "@/components/PointSwitcher.vue"; import PointSwitcher from "@/components/PointSwitcher.vue";
import BowShotEffect from "@/components/BowShotEffect.vue"; import BowShotEffect from "@/components/BowShotEffect.vue";
@@ -56,8 +64,6 @@ const props = defineProps({
const pMode = ref(true); const pMode = ref(true);
const latestOne = ref(null); const latestOne = ref(null);
const bluelatestOne = ref(null); const bluelatestOne = ref(null);
const prevScores = ref([]);
const prevBlueScores = ref([]);
const timer = ref(null); const timer = ref(null);
const dirTimer = ref(null); const dirTimer = ref(null);
const angle = ref(null); const angle = ref(null);
@@ -66,7 +72,9 @@ const shotEffect = ref(null);
const hiddenRedLatestKey = ref(""); const hiddenRedLatestKey = ref("");
const hiddenBlueLatestKey = ref(""); const hiddenBlueLatestKey = ref("");
const targetShaking = ref(false); const targetShaking = ref(false);
const targetSize = ref({ width: 0, height: 0 });
const shakeTimer = ref(null); const shakeTimer = ref(null);
const instance = getCurrentInstance();
const ROUND_TIP_OFFSET_Y = -32; const ROUND_TIP_OFFSET_Y = -32;
const EXPERIENCE_TIP_OFFSET_Y = -68; const EXPERIENCE_TIP_OFFSET_Y = -68;
@@ -82,8 +90,14 @@ function buildShotEffectKey(team, shot, index) {
].join("-"); ].join("-");
} }
function hasShotPoint(shot) {
const x = Number(shot?.x);
const y = Number(shot?.y);
return Number.isFinite(x) && Number.isFinite(y);
}
function shouldPlayShotEffect(shot) { function shouldPlayShotEffect(shot) {
return props.isSvip && !!shot && Number(shot.ring) > 0; return props.isSvip && !!shot && Number(shot.ring) > 0 && hasShotPoint(shot);
} }
function clearTipTimer() { function clearTipTimer() {
@@ -154,6 +168,29 @@ function shakeTarget() {
}); });
} }
function updateTargetSize() {
nextTick(() => {
const query = instance?.proxy
? uni.createSelectorQuery().in(instance.proxy)
: uni.createSelectorQuery();
query
.select(".target")
.boundingClientRect((rect) => {
const width = Number(rect?.width);
const height = Number(rect?.height);
if (!Number.isFinite(width) || !Number.isFinite(height)) return;
if (width <= 0 || height <= 0) return;
targetSize.value = { width, height };
})
.exec();
});
}
function handleWindowResize() {
updateTargetSize();
}
function shouldHideRedHit(index) { function shouldHideRedHit(index) {
return !!hiddenRedLatestKey.value && index === props.scores.length - 1; return !!hiddenRedLatestKey.value && index === props.scores.length - 1;
} }
@@ -163,46 +200,44 @@ function shouldHideBlueHit(index) {
} }
watch( watch(
() => props.scores, () => props.scores.length,
(newVal) => { (newLen, oldLen) => {
if (newVal.length - prevScores.value.length === 1) { if (newLen === oldLen + 1) {
const latestShot = newVal[newVal.length - 1]; const latestShot = props.scores[newLen - 1];
if (shouldPlayShotEffect(latestShot)) { if (shouldPlayShotEffect(latestShot)) {
triggerShotEffect("red", latestShot, newVal.length - 1); triggerShotEffect("red", latestShot, newLen - 1);
} else { } else {
showShotTip("red", latestShot); showShotTip("red", latestShot);
} }
} else if (newVal.length <= prevScores.value.length) { return;
}
if (newLen < oldLen) {
latestOne.value = null; latestOne.value = null;
hiddenRedLatestKey.value = ""; hiddenRedLatestKey.value = "";
if (shotEffect.value?.team === "red") shotEffect.value = null; if (shotEffect.value?.team === "red") shotEffect.value = null;
} }
prevScores.value = [...newVal];
},
{
deep: true,
} }
); );
watch( watch(
() => props.blueScores, () => props.blueScores.length,
(newVal) => { (newLen, oldLen) => {
if (newVal.length - prevBlueScores.value.length === 1) { if (newLen === oldLen + 1) {
const latestShot = newVal[newVal.length - 1]; const latestShot = props.blueScores[newLen - 1];
if (shouldPlayShotEffect(latestShot)) { if (shouldPlayShotEffect(latestShot)) {
triggerShotEffect("blue", latestShot, newVal.length - 1); triggerShotEffect("blue", latestShot, newLen - 1);
} else { } else {
showShotTip("blue", latestShot); showShotTip("blue", latestShot);
} }
} else if (newVal.length <= prevBlueScores.value.length) { return;
}
if (newLen < oldLen) {
bluelatestOne.value = null; bluelatestOne.value = null;
hiddenBlueLatestKey.value = ""; hiddenBlueLatestKey.value = "";
if (shotEffect.value?.team === "blue") shotEffect.value = null; if (shotEffect.value?.team === "blue") shotEffect.value = null;
} }
prevBlueScores.value = [...newVal];
},
{
deep: true,
} }
); );
@@ -349,6 +384,8 @@ async function onReceiveMessage(message) {
onMounted(() => { onMounted(() => {
uni.$on("socket-inbox", onReceiveMessage); uni.$on("socket-inbox", onReceiveMessage);
updateTargetSize();
if (uni.onWindowResize) uni.onWindowResize(handleWindowResize);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
@@ -365,6 +402,7 @@ onBeforeUnmount(() => {
shakeTimer.value = null; shakeTimer.value = null;
} }
uni.$off("socket-inbox", onReceiveMessage); uni.$off("socket-inbox", onReceiveMessage);
if (uni.offWindowResize) uni.offWindowResize(handleWindowResize);
}); });
</script> </script>
@@ -461,6 +499,9 @@ onBeforeUnmount(() => {
:shot="shotEffect && shotEffect.shot" :shot="shotEffect && shotEffect.shot"
:playKey="shotEffect ? shotEffect.key : ''" :playKey="shotEffect ? shotEffect.key : ''"
:targetRadius="safeTargetRadius" :targetRadius="safeTargetRadius"
:targetWidth="targetSize.width"
:targetHeight="targetSize.height"
:hitOffsetPx="currentHitRadiusPx"
@impact="shakeTarget" @impact="shakeTarget"
@complete="completeShotEffect" @complete="completeShotEffect"
/> />