Jelajahi Sumber

优化指北针持续追踪手感

zhangyan 1 Minggu lalu
induk
melakukan
8b10afe5b9
2 mengubah file dengan 92 tambahan dan 14 penghapusan
  1. 91 13
      miniprogram/engine/map/mapEngine.ts
  2. 1 1
      miniprogram/pages/map/map.ts

+ 91 - 13
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<CompassTuningProfile, {
   needleMinSmoothing: number
   needleMaxSmoothing: number
@@ -827,6 +829,7 @@ export class MapEngine {
   previewResetTimer: number
   viewSyncTimer: number
   autoRotateTimer: number
+  compassNeedleTimer: number
   pendingViewPatch: Partial<MapEngineViewState>
   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<MapEngineViewState>): Partial<MapEngineViewState> {
     const viewPatch = {} as Partial<MapEngineViewState>
     for (const key of VIEW_SYNC_KEYS) {

+ 1 - 1
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'