diff --git a/src/components/BowTarget.vue b/src/components/BowTarget.vue index 79ee41d..1a26f5a 100644 --- a/src/components/BowTarget.vue +++ b/src/components/BowTarget.vue @@ -57,6 +57,8 @@ const timer = ref(null); const dirTimer = ref(null); const angle = ref(null); const circleColor = ref(""); +const ROUND_TIP_OFFSET_Y = -32; +const EXPERIENCE_TIP_OFFSET_Y = -68; watch( () => props.scores, @@ -133,14 +135,14 @@ function formatTargetPosition(percent, offset) { return pxOffset ? `calc(${percent}%${pxOffset})` : `${percent}%`; } -function getTargetPositionStyle(point, offsetPx = 0) { +function getTargetPositionStyle(point, offsetPx = 0, extraOffset = {}) { if (!point) return { display: "none" }; const radius = safeTargetRadius.value; const diameter = radius * 2; const direction = getPointDirection(point); - const xOffset = direction ? direction.x * offsetPx : 0; - const yOffset = direction ? -direction.y * offsetPx : 0; + const xOffset = (direction ? direction.x * offsetPx : 0) + (extraOffset.x || 0); + const yOffset = (direction ? -direction.y * offsetPx : 0) + (extraOffset.y || 0); const leftPercent = ((point.x + radius) / diameter) * 100; const topPercent = ((radius - point.y) / diameter) * 100; @@ -162,9 +164,22 @@ function getHitStyle(shot) { }; } -function getTipStyle(shot) { +function getRoundTipStyle(shot) { const point = getShotPoint(shot, true); - return getTargetPositionStyle(point, shot?.ring ? currentHitRadiusPx.value : 0); + return getTargetPositionStyle( + point, + shot?.ring ? currentHitRadiusPx.value : 0, + { y: ROUND_TIP_OFFSET_Y } + ); +} + +function getExperienceTipStyle(shot) { + const point = getShotPoint(shot, true); + return getTargetPositionStyle( + point, + shot?.ring ? currentHitRadiusPx.value : 0, + { y: EXPERIENCE_TIP_OFFSET_Y } + ); } const simulShoot = async () => { if (device.value.deviceId) await simulShootAPI(device.value.deviceId); @@ -247,14 +262,14 @@ onBeforeUnmount(() => { 经验 +1 {{ latestOne.ringX ? "X" : latestOne.ring || "未上靶" }} @@ -265,14 +280,14 @@ onBeforeUnmount(() => { user.id === bluelatestOne.playerId " class="e-value fade-in-out" - :style="getTipStyle(bluelatestOne)" + :style="getExperienceTipStyle(bluelatestOne)" > 经验 +1 {{ bluelatestOne.ringX ? "X" : bluelatestOne.ring || "未上靶" }} @@ -356,6 +371,31 @@ onBeforeUnmount(() => { font-size: 24px; margin-left: 5px; } +@keyframes target-tip-fade-in-out { + 0% { + transform: translate(-50%, -50%) translateY(20px); + opacity: 0; + } + + 30% { + transform: translate(-50%, -50%); + opacity: 1; + } + + 80% { + transform: translate(-50%, -50%); + opacity: 1; + } + + 100% { + transform: translate(-50%, -50%); + opacity: 0; + } +} +.round-tip.fade-in-out, +.e-value.fade-in-out { + animation: target-tip-fade-in-out 1.2s ease forwards; +} .target > image:last-child { width: 100%; height: 100%; diff --git a/src/pages/team-battle/components/BowTarget.vue b/src/pages/team-battle/components/BowTarget.vue index c855fea..4555309 100644 --- a/src/pages/team-battle/components/BowTarget.vue +++ b/src/pages/team-battle/components/BowTarget.vue @@ -59,6 +59,8 @@ const timer = ref(null); const dirTimer = ref(null); const angle = ref(null); const circleColor = ref(""); +const ROUND_TIP_OFFSET_Y = -32; +const EXPERIENCE_TIP_OFFSET_Y = -68; function showShotFlash(flash) { const shootData = flash?.shootData; @@ -128,14 +130,14 @@ function formatTargetPosition(percent, offset) { return pxOffset ? `calc(${percent}%${pxOffset})` : `${percent}%`; } -function getTargetPositionStyle(point, offsetPx = 0) { +function getTargetPositionStyle(point, offsetPx = 0, extraOffset = {}) { if (!point) return { display: "none" }; const radius = safeTargetRadius.value; const diameter = radius * 2; const direction = getPointDirection(point); - const xOffset = direction ? direction.x * offsetPx : 0; - const yOffset = direction ? -direction.y * offsetPx : 0; + const xOffset = (direction ? direction.x * offsetPx : 0) + (extraOffset.x || 0); + const yOffset = (direction ? -direction.y * offsetPx : 0) + (extraOffset.y || 0); const leftPercent = ((point.x + radius) / diameter) * 100; const topPercent = ((radius - point.y) / diameter) * 100; @@ -157,9 +159,22 @@ function getHitStyle(shot) { }; } -function getTipStyle(shot) { +function getRoundTipStyle(shot) { const point = getShotPoint(shot, true); - return getTargetPositionStyle(point, shot?.ring ? currentHitRadiusPx.value : 0); + return getTargetPositionStyle( + point, + shot?.ring ? currentHitRadiusPx.value : 0, + { y: ROUND_TIP_OFFSET_Y } + ); +} + +function getExperienceTipStyle(shot) { + const point = getShotPoint(shot, true); + return getTargetPositionStyle( + point, + shot?.ring ? currentHitRadiusPx.value : 0, + { y: EXPERIENCE_TIP_OFFSET_Y } + ); } const simulShoot = async () => { if (device.value.deviceId) await simulShootAPI(device.value.deviceId); @@ -242,14 +257,14 @@ onBeforeUnmount(() => { 经验 +1 {{ latestOne.ringX ? "X" : latestOne.ring || "未上靶" }} @@ -260,14 +275,14 @@ onBeforeUnmount(() => { user.id === bluelatestOne.playerId " class="e-value fade-in-out" - :style="getTipStyle(bluelatestOne)" + :style="getExperienceTipStyle(bluelatestOne)" > 经验 +1 {{ bluelatestOne.ringX ? "X" : bluelatestOne.ring || "未上靶" }} @@ -351,6 +366,31 @@ onBeforeUnmount(() => { font-size: 24px; margin-left: 5px; } +@keyframes target-tip-fade-in-out { + 0% { + transform: translate(-50%, -50%) translateY(20px); + opacity: 0; + } + + 30% { + transform: translate(-50%, -50%); + opacity: 1; + } + + 80% { + transform: translate(-50%, -50%); + opacity: 1; + } + + 100% { + transform: translate(-50%, -50%); + opacity: 0; + } +} +.round-tip.fade-in-out, +.e-value.fade-in-out { + animation: target-tip-fade-in-out 1.2s ease forwards; +} .target > image:last-child { width: 100%; height: 100%;