From 8b10afe5b9eec33773052274b463ee498c0b1c31 Mon Sep 17 00:00:00 2001 From: zhangyan Date: Thu, 26 Mar 2026 17:06:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8C=87=E5=8C=97=E9=92=88?= =?UTF-8?q?=E6=8C=81=E7=BB=AD=E8=BF=BD=E8=B8=AA=E6=89=8B=E6=84=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/engine/map/mapEngine.ts | 104 ++++++++++++++++++++++++---- miniprogram/pages/map/map.ts | 2 +- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/miniprogram/engine/map/mapEngine.ts b/miniprogram/engine/map/mapEngine.ts index f700dca..45e2936 100644 --- a/miniprogram/engine/map/mapEngine.ts +++ b/miniprogram/engine/map/mapEngine.ts @@ -57,6 +57,8 @@ const AUTO_ROTATE_SNAP_DEG = 0.1 const AUTO_ROTATE_DEADZONE_DEG = 4 const AUTO_ROTATE_MAX_STEP_DEG = 0.75 const AUTO_ROTATE_HEADING_SMOOTHING = 0.46 +const COMPASS_NEEDLE_FRAME_MS = 16 +const COMPASS_NEEDLE_SNAP_DEG = 0.08 const COMPASS_TUNING_PRESETS: Record mounted: boolean diagnosticUiEnabled: boolean @@ -834,6 +837,7 @@ export class MapEngine { sensorHeadingDeg: number | null smoothedSensorHeadingDeg: number | null compassDisplayHeadingDeg: number | null + targetCompassDisplayHeadingDeg: number | null compassSource: 'compass' | 'motion' | null compassTuningProfile: CompassTuningProfile smoothedMovementHeadingDeg: number | null @@ -1277,6 +1281,7 @@ export class MapEngine { this.previewResetTimer = 0 this.viewSyncTimer = 0 this.autoRotateTimer = 0 + this.compassNeedleTimer = 0 this.pendingViewPatch = {} this.mounted = false this.diagnosticUiEnabled = false @@ -1284,6 +1289,7 @@ export class MapEngine { this.sensorHeadingDeg = null this.smoothedSensorHeadingDeg = null this.compassDisplayHeadingDeg = null + this.targetCompassDisplayHeadingDeg = null this.compassSource = null this.compassTuningProfile = 'balanced' this.smoothedMovementHeadingDeg = null @@ -1399,6 +1405,7 @@ export class MapEngine { this.clearPreviewResetTimer() this.clearViewSyncTimer() this.clearAutoRotateTimer() + this.clearCompassNeedleTimer() this.clearPunchFeedbackTimer() this.clearContentCardTimer() this.clearMapPulseTimer() @@ -2940,27 +2947,19 @@ export class MapEngine { const compassHeadingDeg = getCompassReferenceHeadingDeg(this.northReferenceMode, this.smoothedSensorHeadingDeg) if (this.compassDisplayHeadingDeg === null) { this.compassDisplayHeadingDeg = compassHeadingDeg + this.targetCompassDisplayHeadingDeg = compassHeadingDeg + this.syncCompassDisplayState() } else { + this.targetCompassDisplayHeadingDeg = compassHeadingDeg const displayDeltaDeg = Math.abs(normalizeAngleDeltaDeg(compassHeadingDeg - this.compassDisplayHeadingDeg)) if (displayDeltaDeg >= COMPASS_TUNING_PRESETS[this.compassTuningProfile].displayDeadzoneDeg) { - this.compassDisplayHeadingDeg = interpolateAngleDeg( - this.compassDisplayHeadingDeg, - compassHeadingDeg, - getCompassNeedleSmoothingFactor( - this.compassDisplayHeadingDeg, - compassHeadingDeg, - this.compassTuningProfile, - ), - ) + this.scheduleCompassNeedleFollow() } } this.autoRotateHeadingDeg = this.resolveAutoRotateInputHeadingDeg() - this.setState({ - compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.compassDisplayHeadingDeg), - sensorHeadingText: formatHeadingText(this.compassDisplayHeadingDeg), - compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode), + compassSourceText: formatCompassSourceText(this.compassSource), ...(this.diagnosticUiEnabled ? { ...this.getTelemetrySensorViewPatch(), @@ -2986,9 +2985,11 @@ export class MapEngine { handleCompassError(message: string): void { this.clearAutoRotateTimer() + this.clearCompassNeedleTimer() this.targetAutoRotationDeg = null this.autoRotateCalibrationPending = false this.compassSource = null + this.targetCompassDisplayHeadingDeg = null this.setState({ compassSourceText: formatCompassSourceText(null), autoRotateCalibrationText: formatAutoRotateCalibrationText(false, this.autoRotateCalibrationOffsetDeg), @@ -3013,6 +3014,7 @@ export class MapEngine { this.northReferenceMode = nextMode this.autoRotateCalibrationOffsetDeg = nextMapNorthOffsetDeg this.compassDisplayHeadingDeg = compassHeadingDeg + this.targetCompassDisplayHeadingDeg = compassHeadingDeg if (this.state.orientationMode === 'north-up') { const exactCenter = this.getExactCenterFromTranslate(this.state.tileTranslateX, this.state.tileTranslateY) @@ -3056,6 +3058,10 @@ export class MapEngine { if (this.state.orientationMode === 'heading-up' && this.refreshAutoRotateTarget()) { this.scheduleAutoRotate() } + + if (this.compassDisplayHeadingDeg !== null) { + this.syncCompassDisplayState() + } } setCourseHeading(headingDeg: number | null): void { @@ -3570,6 +3576,78 @@ export class MapEngine { this.autoRotateTimer = 0 } } + + clearCompassNeedleTimer(): void { + if (this.compassNeedleTimer) { + clearTimeout(this.compassNeedleTimer) + this.compassNeedleTimer = 0 + } + } + + syncCompassDisplayState(): void { + this.setState({ + compassNeedleDeg: formatCompassNeedleDegForMode(this.northReferenceMode, this.compassDisplayHeadingDeg), + sensorHeadingText: formatHeadingText(this.compassDisplayHeadingDeg), + compassDeclinationText: formatCompassDeclinationText(this.northReferenceMode), + ...(this.diagnosticUiEnabled + ? { + ...this.getTelemetrySensorViewPatch(), + northReferenceButtonText: formatNorthReferenceButtonText(this.northReferenceMode), + autoRotateSourceText: this.getAutoRotateSourceText(), + northReferenceText: formatNorthReferenceText(this.northReferenceMode), + } + : {}), + }) + } + + scheduleCompassNeedleFollow(): void { + if ( + this.compassNeedleTimer + || this.targetCompassDisplayHeadingDeg === null + || this.compassDisplayHeadingDeg === null + ) { + return + } + + const step = () => { + this.compassNeedleTimer = 0 + + if ( + this.targetCompassDisplayHeadingDeg === null + || this.compassDisplayHeadingDeg === null + ) { + return + } + + const deltaDeg = normalizeAngleDeltaDeg( + this.targetCompassDisplayHeadingDeg - this.compassDisplayHeadingDeg, + ) + const absDeltaDeg = Math.abs(deltaDeg) + + if (absDeltaDeg <= COMPASS_NEEDLE_SNAP_DEG) { + if (absDeltaDeg > 0.001) { + this.compassDisplayHeadingDeg = this.targetCompassDisplayHeadingDeg + this.syncCompassDisplayState() + } + return + } + + this.compassDisplayHeadingDeg = interpolateAngleDeg( + this.compassDisplayHeadingDeg, + this.targetCompassDisplayHeadingDeg, + getCompassNeedleSmoothingFactor( + this.compassDisplayHeadingDeg, + this.targetCompassDisplayHeadingDeg, + this.compassTuningProfile, + ), + ) + this.syncCompassDisplayState() + this.scheduleCompassNeedleFollow() + } + + this.compassNeedleTimer = setTimeout(step, COMPASS_NEEDLE_FRAME_MS) as unknown as number + } + pickViewPatch(patch: Partial): Partial { const viewPatch = {} as Partial for (const key of VIEW_SYNC_KEYS) { diff --git a/miniprogram/pages/map/map.ts b/miniprogram/pages/map/map.ts index 52a3a00..4ae3d00 100644 --- a/miniprogram/pages/map/map.ts +++ b/miniprogram/pages/map/map.ts @@ -89,7 +89,7 @@ type MapPageData = MapEngineViewState & { showRightButtonGroups: boolean showBottomDebugButton: boolean } -const INTERNAL_BUILD_VERSION = 'map-build-282' +const INTERNAL_BUILD_VERSION = 'map-build-283' const USER_SETTINGS_STORAGE_KEY = 'cmr_user_settings_v1' const CLASSIC_REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/gotomars/event/classic-sequential.json' const SCORE_O_REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/gotomars/event/score-o.json'