From 5357f131de3c74a4bb259aa247ab64dbfc456713 Mon Sep 17 00:00:00 2001 From: zhangyibo95 <690096405@qq.com> Date: Tue, 22 Sep 2026 15:15:16 +0800 Subject: [PATCH 1/3] =?UTF-8?q?update=EF=BC=9A=E4=BC=98=E5=8C=96=E7=B2=BE?= =?UTF-8?q?=E5=87=86=E7=A8=B3=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/generate-match-schema.mjs | 5 - src/components/TargetCanvas.vue | 78 ++- src/pages/training/components/BowTarget.vue | 10 +- .../training/components/ShootProgress.vue | 76 +-- .../components/StabilityEnergyTrack.vue | 626 ++++++++++++++++++ src/pages/training/practise-one.vue | 69 +- .../stability-energy/progress-empty.png | Bin 0 -> 17625 bytes .../stability-energy/progress-full.png | Bin 0 -> 22043 bytes .../stability-energy/progress-glow.png | Bin 0 -> 4937 bytes src/utils/match.min.js | 2 +- src/utils/matchProtocol.js | 43 +- 11 files changed, 797 insertions(+), 112 deletions(-) create mode 100644 src/pages/training/components/StabilityEnergyTrack.vue create mode 100644 src/static/training-difficulty-design/stability-energy/progress-empty.png create mode 100644 src/static/training-difficulty-design/stability-energy/progress-full.png create mode 100644 src/static/training-difficulty-design/stability-energy/progress-glow.png diff --git a/scripts/generate-match-schema.mjs b/scripts/generate-match-schema.mjs index 47d7a76..f012020 100644 --- a/scripts/generate-match-schema.mjs +++ b/scripts/generate-match-schema.mjs @@ -264,11 +264,6 @@ function buildSchema({ messageName, definition, messages, enumNames }) { } const repeated = rule === "repeated"; - if (repeated && !isMessage && !["string", "bytes"].includes(kind)) { - throw new Error( - `${messageName}.${fieldKey} 是 packed scalar repeated,当前通用解码器尚不支持` - ); - } const field = isMessage ? { name: fieldName, kind: "message", type: typeName } diff --git a/src/components/TargetCanvas.vue b/src/components/TargetCanvas.vue index fd3478a..7026814 100644 --- a/src/components/TargetCanvas.vue +++ b/src/components/TargetCanvas.vue @@ -46,10 +46,10 @@ const props = defineProps({ type: Number, default: 0, }, - // 指定环数,1 到 10;无效值表示高亮整个区域。 - activeRing: { - type: Number, - default: 0, + // 指定一个或多个环数,空数组表示高亮整个区域。 + activeRings: { + type: Array, + default: () => [], }, // 每次变化时以固定低帧数重新展开当前高亮扇区;默认关闭。 highlightRefreshToken: { @@ -192,6 +192,25 @@ const getPositiveInteger = (value) => { return Number.isInteger(numberValue) && numberValue > 0 ? numberValue : 0; }; +// 过滤、去重并合并连续环,避免 3、4 环同时高亮时绘制中间描边。 +const getActiveRingRanges = (ringCount) => { + const rings = [...new Set( + (Array.isArray(props.activeRings) ? props.activeRings : []) + .map(getPositiveInteger) + .filter((ring) => ring >= 1 && ring <= ringCount) + )].sort((first, second) => first - second); + + return rings.reduce((ranges, ring) => { + const lastRange = ranges[ranges.length - 1]; + if (lastRange && ring === lastRange.end + 1) { + lastRange.end = ring; + } else { + ranges.push({ start: ring, end: ring }); + } + return ranges; + }, []); +}; + // 正上方作为第一区起始边界,Canvas 角度递增方向即为顺时针。 const getSectorAngles = (sector, sectorCount) => { const count = getPositiveInteger(sectorCount); @@ -256,7 +275,7 @@ const drawTargetRings = (ctx, centerX, centerY, targetRadius, config) => { } }; -// 高亮后端指定区域;activeRing 有效时只高亮该区域内的单个环。 +// 高亮后端指定区域;activeRings 非空时高亮该区域内的一个或多个环。 const drawSectorHighlight = ( ctx, centerX, @@ -274,32 +293,35 @@ const drawSectorHighlight = ( ); if (safeRevealProgress <= 0) return; - const ring = getPositiveInteger(props.activeRing); - const hasActiveRing = ring >= 1 && ring <= config.ringCount; - const innerRadius = hasActiveRing - ? targetRadius * ((config.ringCount - ring) / config.ringCount) - : 0; - const outerRadius = hasActiveRing - ? targetRadius * ((config.ringCount + 1 - ring) / config.ringCount) - : targetRadius; + const ringRanges = getActiveRingRanges(config.ringCount); + const highlightRanges = ringRanges.length > 0 + ? ringRanges + : [{ start: 1, end: config.ringCount }]; const style = { ...defaultHighlightStyle, ...props.highlightStyle, }; - drawAnnularSector( - ctx, - centerX, - centerY, - innerRadius, - outerRadius, - angles.startAngle, - angles.startAngle + - (angles.endAngle - angles.startAngle) * safeRevealProgress, - style.color, - style.strokeColor, - Math.max(1, targetRadius * style.lineWidthRatio) - ); + highlightRanges.forEach((range) => { + const innerRadius = + targetRadius * ((config.ringCount - range.end) / config.ringCount); + const outerRadius = + targetRadius * ((config.ringCount + 1 - range.start) / config.ringCount); + + drawAnnularSector( + ctx, + centerX, + centerY, + innerRadius, + outerRadius, + angles.startAngle, + angles.startAngle + + (angles.endAngle - angles.startAngle) * safeRevealProgress, + style.color, + style.strokeColor, + Math.max(1, targetRadius * style.lineWidthRatio) + ); + }); }; // 从正上方开始顺时针绘制所有区域边界。 @@ -420,7 +442,7 @@ const getDrawKey = (width, height) => { showRingLabels: props.showRingLabels, sectorCount: props.sectorCount, activeSector: props.activeSector, - activeRing: props.activeRing, + activeRings: props.activeRings, showSectorLabels: props.showSectorLabels, targetStyleConfig: props.targetStyleConfig, crosshairStyle: props.crosshairStyle, @@ -591,7 +613,7 @@ watch( props.showRingLabels, props.sectorCount, props.activeSector, - props.activeRing, + props.activeRings, props.highlightRefreshToken, props.showSectorLabels, props.highlightOnly, diff --git a/src/pages/training/components/BowTarget.vue b/src/pages/training/components/BowTarget.vue index 27311fa..e2771c9 100644 --- a/src/pages/training/components/BowTarget.vue +++ b/src/pages/training/components/BowTarget.vue @@ -84,9 +84,9 @@ const props = defineProps({ type: Number, default: 0, }, - activeRing: { - type: Number, - default: 0, + activeRings: { + type: Array, + default: () => [], }, showSectorLabels: { type: Boolean, @@ -548,7 +548,7 @@ onBeforeUnmount(() => { :highlightOnly="true" :sectorCount="sectorCount" :activeSector="activeSector" - :activeRing="activeRing" + :activeRings="activeRings" :highlightRefreshToken="highlightRefreshToken" :showSectorLabels="showSectorLabels" /> @@ -877,7 +877,7 @@ onBeforeUnmount(() => { width: calc(100% - 20px); padding: 0 10px; display: flex; - margin-top: -40px; + margin-top: 15px; justify-content: flex-end; } .footer > image { diff --git a/src/pages/training/components/ShootProgress.vue b/src/pages/training/components/ShootProgress.vue index e2ce352..47c6d18 100644 --- a/src/pages/training/components/ShootProgress.vue +++ b/src/pages/training/components/ShootProgress.vue @@ -73,11 +73,7 @@ const props = defineProps({ type: Number, default: 0, }, - energyPercent: { - type: Number, - default: 0, - }, - energyReqPercent: { + energyCostPerSec: { type: Number, default: 0, }, @@ -187,17 +183,10 @@ const progressPercent = computed(() => { return Math.max(0, Math.min(100, (remain.value / props.total) * 100)); }); -const stabilityEnergyPercent = computed(() => - Math.max(0, Math.min(100, Number(props.energyPercent) || 0)) -); -const stabilityEnergyReqPercent = computed(() => - Math.max(0, Math.min(100, Number(props.energyReqPercent) || 0)) -); -const stabilityEnergyReached = computed( - () => - stabilityEnergyReqPercent.value > 0 && - stabilityEnergyPercent.value >= stabilityEnergyReqPercent.value -); +const stabilityEnergyCostText = computed(() => { + const value = Math.max(0, Number(props.energyCostPerSec) || 0); + return Number.isInteger(value) ? String(value) : String(Number(value.toFixed(2))); +}); const rhythmMarkerPercent = computed(() => { if (!validRhythmRoundTime.value) return 0; @@ -568,22 +557,18 @@ onBeforeUnmount(() => { " >