完善地图交互、动画与罗盘调试
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
type MapEngineViewState,
|
||||
} from '../../engine/map/mapEngine'
|
||||
import { loadRemoteMapConfig } from '../../utils/remoteMapConfig'
|
||||
import { type AnimationLevel } from '../../utils/animationLevel'
|
||||
type CompassTickData = {
|
||||
angle: number
|
||||
long: boolean
|
||||
@@ -31,9 +32,17 @@ type ScaleRulerMajorMarkData = {
|
||||
type SideButtonMode = 'all' | 'left' | 'right' | 'hidden'
|
||||
type SideActionButtonState = 'muted' | 'default' | 'active'
|
||||
type CenterScaleRulerAnchorMode = 'screen-center' | 'compass-center'
|
||||
type UserNorthReferenceMode = 'magnetic' | 'true'
|
||||
type StoredUserSettings = {
|
||||
animationLevel?: AnimationLevel
|
||||
northReferenceMode?: UserNorthReferenceMode
|
||||
showCenterScaleRuler?: boolean
|
||||
centerScaleRulerAnchorMode?: CenterScaleRulerAnchorMode
|
||||
}
|
||||
type MapPageData = MapEngineViewState & {
|
||||
showDebugPanel: boolean
|
||||
showGameInfoPanel: boolean
|
||||
showSystemSettingsPanel: boolean
|
||||
showCenterScaleRuler: boolean
|
||||
showPunchHintBanner: boolean
|
||||
centerScaleRulerAnchorMode: CenterScaleRulerAnchorMode
|
||||
@@ -52,6 +61,10 @@ type MapPageData = MapEngineViewState & {
|
||||
panelDistanceValueText: string
|
||||
panelProgressText: string
|
||||
panelSpeedValueText: string
|
||||
panelTimerFxClass: string
|
||||
panelMileageFxClass: string
|
||||
panelSpeedFxClass: string
|
||||
panelHeartRateFxClass: string
|
||||
compassTicks: CompassTickData[]
|
||||
compassLabels: CompassLabelData[]
|
||||
sideButtonMode: SideButtonMode
|
||||
@@ -59,6 +72,7 @@ type MapPageData = MapEngineViewState & {
|
||||
sideButton2Class: string
|
||||
sideButton4Class: string
|
||||
sideButton11Class: string
|
||||
sideButton12Class: string
|
||||
sideButton13Class: string
|
||||
sideButton14Class: string
|
||||
sideButton16Class: string
|
||||
@@ -75,7 +89,8 @@ type MapPageData = MapEngineViewState & {
|
||||
showRightButtonGroups: boolean
|
||||
showBottomDebugButton: boolean
|
||||
}
|
||||
const INTERNAL_BUILD_VERSION = 'map-build-261'
|
||||
const INTERNAL_BUILD_VERSION = 'map-build-282'
|
||||
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'
|
||||
const PUNCH_HINT_AUTO_HIDE_MS = 30000
|
||||
@@ -83,7 +98,43 @@ let mapEngine: MapEngine | null = null
|
||||
let stageCanvasAttached = false
|
||||
let gameInfoPanelSyncTimer = 0
|
||||
let centerScaleRulerSyncTimer = 0
|
||||
let centerScaleRulerUpdateTimer = 0
|
||||
let punchHintDismissTimer = 0
|
||||
let panelTimerFxTimer = 0
|
||||
let panelMileageFxTimer = 0
|
||||
let panelSpeedFxTimer = 0
|
||||
let panelHeartRateFxTimer = 0
|
||||
let lastCenterScaleRulerStablePatch: Pick<
|
||||
MapPageData,
|
||||
| 'centerScaleRulerVisible'
|
||||
| 'centerScaleRulerCenterXPx'
|
||||
| 'centerScaleRulerZeroYPx'
|
||||
| 'centerScaleRulerHeightPx'
|
||||
| 'centerScaleRulerAxisBottomPx'
|
||||
| 'centerScaleRulerZeroVisible'
|
||||
| 'centerScaleRulerZeroLabel'
|
||||
| 'centerScaleRulerMinorTicks'
|
||||
| 'centerScaleRulerMajorMarks'
|
||||
> = {
|
||||
centerScaleRulerVisible: false,
|
||||
centerScaleRulerCenterXPx: 0,
|
||||
centerScaleRulerZeroYPx: 0,
|
||||
centerScaleRulerHeightPx: 0,
|
||||
centerScaleRulerAxisBottomPx: 0,
|
||||
centerScaleRulerZeroVisible: false,
|
||||
centerScaleRulerZeroLabel: '0 m',
|
||||
centerScaleRulerMinorTicks: [],
|
||||
centerScaleRulerMajorMarks: [],
|
||||
}
|
||||
let centerScaleRulerInputCache: Partial<Pick<
|
||||
MapPageData,
|
||||
'stageWidth'
|
||||
| 'stageHeight'
|
||||
| 'zoom'
|
||||
| 'centerTileY'
|
||||
| 'tileSizePx'
|
||||
| 'previewScale'
|
||||
>> = {}
|
||||
|
||||
const DEBUG_ONLY_VIEW_KEYS = new Set<string>([
|
||||
'buildVersion',
|
||||
@@ -93,14 +144,15 @@ const DEBUG_ONLY_VIEW_KEYS = new Set<string>([
|
||||
'mapReadyText',
|
||||
'mapName',
|
||||
'configStatusText',
|
||||
'sensorHeadingText',
|
||||
'deviceHeadingText',
|
||||
'devicePoseText',
|
||||
'headingConfidenceText',
|
||||
'accelerometerText',
|
||||
'gyroscopeText',
|
||||
'deviceMotionText',
|
||||
'compassDeclinationText',
|
||||
'compassSourceText',
|
||||
'compassTuningProfile',
|
||||
'compassTuningProfileText',
|
||||
'northReferenceButtonText',
|
||||
'autoRotateSourceText',
|
||||
'autoRotateCalibrationText',
|
||||
@@ -148,6 +200,15 @@ const CENTER_SCALE_RULER_DEP_KEYS = new Set<string>([
|
||||
'previewScale',
|
||||
])
|
||||
|
||||
const CENTER_SCALE_RULER_CACHE_KEYS: Array<keyof typeof centerScaleRulerInputCache> = [
|
||||
'stageWidth',
|
||||
'stageHeight',
|
||||
'zoom',
|
||||
'centerTileY',
|
||||
'tileSizePx',
|
||||
'previewScale',
|
||||
]
|
||||
|
||||
const RULER_ONLY_VIEW_KEYS = new Set<string>([
|
||||
'zoom',
|
||||
'centerTileX',
|
||||
@@ -213,12 +274,83 @@ function clearCenterScaleRulerSyncTimer() {
|
||||
}
|
||||
}
|
||||
|
||||
function clearCenterScaleRulerUpdateTimer() {
|
||||
if (centerScaleRulerUpdateTimer) {
|
||||
clearTimeout(centerScaleRulerUpdateTimer)
|
||||
centerScaleRulerUpdateTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
function clearPunchHintDismissTimer() {
|
||||
if (punchHintDismissTimer) {
|
||||
clearTimeout(punchHintDismissTimer)
|
||||
punchHintDismissTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
function clearHudFxTimer(key: 'timer' | 'mileage' | 'speed' | 'heartRate') {
|
||||
const timerMap = {
|
||||
timer: panelTimerFxTimer,
|
||||
mileage: panelMileageFxTimer,
|
||||
speed: panelSpeedFxTimer,
|
||||
heartRate: panelHeartRateFxTimer,
|
||||
}
|
||||
const timer = timerMap[key]
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
if (key === 'timer') {
|
||||
panelTimerFxTimer = 0
|
||||
} else if (key === 'mileage') {
|
||||
panelMileageFxTimer = 0
|
||||
} else if (key === 'speed') {
|
||||
panelSpeedFxTimer = 0
|
||||
} else {
|
||||
panelHeartRateFxTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
function updateCenterScaleRulerInputCache(patch: Partial<MapPageData>) {
|
||||
for (const key of CENTER_SCALE_RULER_CACHE_KEYS) {
|
||||
if (Object.prototype.hasOwnProperty.call(patch, key)) {
|
||||
;(centerScaleRulerInputCache as Record<string, unknown>)[key] =
|
||||
(patch as Record<string, unknown>)[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadStoredUserSettings(): StoredUserSettings {
|
||||
try {
|
||||
const stored = wx.getStorageSync(USER_SETTINGS_STORAGE_KEY)
|
||||
if (!stored || typeof stored !== 'object') {
|
||||
return {}
|
||||
}
|
||||
|
||||
const normalized = stored as Record<string, unknown>
|
||||
const settings: StoredUserSettings = {}
|
||||
if (normalized.animationLevel === 'standard' || normalized.animationLevel === 'lite') {
|
||||
settings.animationLevel = normalized.animationLevel
|
||||
}
|
||||
if (normalized.northReferenceMode === 'magnetic' || normalized.northReferenceMode === 'true') {
|
||||
settings.northReferenceMode = normalized.northReferenceMode
|
||||
}
|
||||
if (typeof normalized.showCenterScaleRuler === 'boolean') {
|
||||
settings.showCenterScaleRuler = normalized.showCenterScaleRuler
|
||||
}
|
||||
if (normalized.centerScaleRulerAnchorMode === 'screen-center' || normalized.centerScaleRulerAnchorMode === 'compass-center') {
|
||||
settings.centerScaleRulerAnchorMode = normalized.centerScaleRulerAnchorMode
|
||||
}
|
||||
return settings
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function persistStoredUserSettings(settings: StoredUserSettings) {
|
||||
try {
|
||||
wx.setStorageSync(USER_SETTINGS_STORAGE_KEY, settings)
|
||||
} catch {}
|
||||
}
|
||||
function buildSideButtonVisibility(mode: SideButtonMode) {
|
||||
return {
|
||||
sideButtonMode: mode,
|
||||
@@ -296,7 +428,7 @@ function getSideActionButtonClass(state: SideActionButtonState): string {
|
||||
return 'map-side-button map-side-button--default'
|
||||
}
|
||||
|
||||
function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGameInfoPanel' | 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'skipButtonEnabled' | 'gameSessionStatus' | 'gpsLockEnabled' | 'gpsLockAvailable'>) {
|
||||
function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGameInfoPanel' | 'showSystemSettingsPanel' | 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'skipButtonEnabled' | 'gameSessionStatus' | 'gpsLockEnabled' | 'gpsLockAvailable'>) {
|
||||
const sideButton2State: SideActionButtonState = !data.gpsLockAvailable
|
||||
? 'muted'
|
||||
: data.gpsLockEnabled
|
||||
@@ -304,6 +436,7 @@ function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGa
|
||||
: 'default'
|
||||
const sideButton4State: SideActionButtonState = data.gameSessionStatus === 'idle' ? 'default' : 'active'
|
||||
const sideButton11State: SideActionButtonState = data.showGameInfoPanel ? 'active' : 'default'
|
||||
const sideButton12State: SideActionButtonState = data.showSystemSettingsPanel ? 'active' : 'default'
|
||||
const sideButton13State: SideActionButtonState = data.showCenterScaleRuler ? 'active' : 'default'
|
||||
const sideButton14State: SideActionButtonState = !data.showCenterScaleRuler
|
||||
? 'muted'
|
||||
@@ -317,6 +450,7 @@ function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGa
|
||||
sideButton2Class: getSideActionButtonClass(sideButton2State),
|
||||
sideButton4Class: getSideActionButtonClass(sideButton4State),
|
||||
sideButton11Class: getSideActionButtonClass(sideButton11State),
|
||||
sideButton12Class: getSideActionButtonClass(sideButton12State),
|
||||
sideButton13Class: getSideActionButtonClass(sideButton13State),
|
||||
sideButton14Class: getSideActionButtonClass(sideButton14State),
|
||||
sideButton16Class: getSideActionButtonClass(sideButton16State),
|
||||
@@ -367,7 +501,7 @@ function formatScaleDistanceLabel(distanceMeters: number): string {
|
||||
|
||||
function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'stageWidth' | 'stageHeight' | 'topInsetHeight' | 'zoom' | 'centerTileY' | 'tileSizePx' | 'previewScale'>) {
|
||||
if (!data.showCenterScaleRuler) {
|
||||
return {
|
||||
lastCenterScaleRulerStablePatch = {
|
||||
centerScaleRulerVisible: false,
|
||||
centerScaleRulerCenterXPx: 0,
|
||||
centerScaleRulerZeroYPx: 0,
|
||||
@@ -378,20 +512,11 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
||||
centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
||||
centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
||||
}
|
||||
return { ...lastCenterScaleRulerStablePatch }
|
||||
}
|
||||
|
||||
if (!data.stageWidth || !data.stageHeight) {
|
||||
return {
|
||||
centerScaleRulerVisible: false,
|
||||
centerScaleRulerCenterXPx: 0,
|
||||
centerScaleRulerZeroYPx: 0,
|
||||
centerScaleRulerHeightPx: 0,
|
||||
centerScaleRulerAxisBottomPx: 0,
|
||||
centerScaleRulerZeroVisible: false,
|
||||
centerScaleRulerZeroLabel: '0 m',
|
||||
centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
||||
centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
||||
}
|
||||
return { ...lastCenterScaleRulerStablePatch }
|
||||
}
|
||||
|
||||
const topPadding = 12
|
||||
@@ -414,15 +539,13 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
||||
|| !Number.isFinite(data.centerTileY)
|
||||
) {
|
||||
return {
|
||||
...lastCenterScaleRulerStablePatch,
|
||||
centerScaleRulerVisible: true,
|
||||
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
||||
centerScaleRulerZeroYPx: zeroYPx,
|
||||
centerScaleRulerHeightPx: fallbackHeight,
|
||||
centerScaleRulerHeightPx: lastCenterScaleRulerStablePatch.centerScaleRulerHeightPx || fallbackHeight,
|
||||
centerScaleRulerAxisBottomPx: coveredBottomPx,
|
||||
centerScaleRulerZeroVisible: data.centerScaleRulerAnchorMode !== 'compass-center',
|
||||
centerScaleRulerZeroLabel: '0 m',
|
||||
centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
||||
centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,15 +558,13 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
||||
|
||||
if (!Number.isFinite(effectiveMetersPerPixel) || effectiveMetersPerPixel <= 0 || rulerHeight < 120) {
|
||||
return {
|
||||
...lastCenterScaleRulerStablePatch,
|
||||
centerScaleRulerVisible: true,
|
||||
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
||||
centerScaleRulerZeroYPx: zeroYPx,
|
||||
centerScaleRulerHeightPx: Math.max(rulerHeight, fallbackHeight),
|
||||
centerScaleRulerHeightPx: lastCenterScaleRulerStablePatch.centerScaleRulerHeightPx || fallbackHeight,
|
||||
centerScaleRulerAxisBottomPx: coveredBottomPx,
|
||||
centerScaleRulerZeroVisible: data.centerScaleRulerAnchorMode !== 'compass-center',
|
||||
centerScaleRulerZeroLabel: '0 m',
|
||||
centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
||||
centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,7 +601,7 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
lastCenterScaleRulerStablePatch = {
|
||||
centerScaleRulerVisible: true,
|
||||
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
||||
centerScaleRulerZeroYPx: zeroYPx,
|
||||
@@ -491,6 +612,7 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
||||
centerScaleRulerMinorTicks: minorTicks,
|
||||
centerScaleRulerMajorMarks: majorMarks,
|
||||
}
|
||||
return { ...lastCenterScaleRulerStablePatch }
|
||||
}
|
||||
|
||||
function buildEmptyGameInfoSnapshot(): MapEngineGameInfoSnapshot {
|
||||
@@ -512,6 +634,7 @@ Page({
|
||||
data: {
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: false,
|
||||
statusBarHeight: 0,
|
||||
topInsetHeight: 12,
|
||||
@@ -572,6 +695,9 @@ Page({
|
||||
accelerometerText: '--',
|
||||
gyroscopeText: '--',
|
||||
deviceMotionText: '--',
|
||||
compassSourceText: '无数据',
|
||||
compassTuningProfile: 'balanced',
|
||||
compassTuningProfileText: '平衡',
|
||||
punchButtonText: '打点',
|
||||
punchButtonEnabled: false,
|
||||
skipButtonEnabled: false,
|
||||
@@ -583,6 +709,8 @@ Page({
|
||||
contentCardTitle: '',
|
||||
contentCardBody: '',
|
||||
punchButtonFxClass: '',
|
||||
panelProgressFxClass: '',
|
||||
panelDistanceFxClass: '',
|
||||
punchFeedbackFxClass: '',
|
||||
contentCardFxClass: '',
|
||||
mapPulseVisible: false,
|
||||
@@ -606,6 +734,7 @@ Page({
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: 'left',
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: false,
|
||||
centerScaleRulerAnchorMode: 'screen-center',
|
||||
skipButtonEnabled: false,
|
||||
@@ -649,7 +778,10 @@ Page({
|
||||
nextData.mockHeartRateBridgeUrlDraft = nextPatch.mockHeartRateBridgeUrlText
|
||||
}
|
||||
|
||||
updateCenterScaleRulerInputCache(nextPatch)
|
||||
|
||||
const mergedData = {
|
||||
...centerScaleRulerInputCache,
|
||||
...this.data,
|
||||
...nextData,
|
||||
} as MapPageData
|
||||
@@ -659,6 +791,7 @@ Page({
|
||||
this.data.showCenterScaleRuler
|
||||
&& hasAnyPatchKey(nextPatch as Record<string, unknown>, CENTER_SCALE_RULER_DEP_KEYS)
|
||||
) {
|
||||
clearCenterScaleRulerUpdateTimer()
|
||||
Object.assign(derivedPatch, buildCenterScaleRulerPatch(mergedData))
|
||||
}
|
||||
|
||||
@@ -685,6 +818,57 @@ Page({
|
||||
}
|
||||
}
|
||||
|
||||
const nextAnimationLevel = typeof nextPatch.animationLevel === 'string'
|
||||
? nextPatch.animationLevel
|
||||
: this.data.animationLevel
|
||||
|
||||
if (nextAnimationLevel === 'lite') {
|
||||
clearHudFxTimer('timer')
|
||||
clearHudFxTimer('mileage')
|
||||
clearHudFxTimer('speed')
|
||||
clearHudFxTimer('heartRate')
|
||||
nextData.panelTimerFxClass = ''
|
||||
nextData.panelMileageFxClass = ''
|
||||
nextData.panelSpeedFxClass = ''
|
||||
nextData.panelHeartRateFxClass = ''
|
||||
} else {
|
||||
if (typeof nextPatch.panelTimerText === 'string' && nextPatch.panelTimerText !== this.data.panelTimerText && this.data.panelTimerText !== '00:00:00') {
|
||||
clearHudFxTimer('timer')
|
||||
nextData.panelTimerFxClass = 'race-panel__timer--fx-tick'
|
||||
panelTimerFxTimer = setTimeout(() => {
|
||||
panelTimerFxTimer = 0
|
||||
this.setData({ panelTimerFxClass: '' })
|
||||
}, 320) as unknown as number
|
||||
}
|
||||
|
||||
if (typeof nextPatch.panelMileageText === 'string' && nextPatch.panelMileageText !== this.data.panelMileageText && this.data.panelMileageText !== '0m') {
|
||||
clearHudFxTimer('mileage')
|
||||
nextData.panelMileageFxClass = 'race-panel__mileage-wrap--fx-update'
|
||||
panelMileageFxTimer = setTimeout(() => {
|
||||
panelMileageFxTimer = 0
|
||||
this.setData({ panelMileageFxClass: '' })
|
||||
}, 360) as unknown as number
|
||||
}
|
||||
|
||||
if (typeof nextPatch.panelSpeedValueText === 'string' && nextPatch.panelSpeedValueText !== this.data.panelSpeedValueText && this.data.panelSpeedValueText !== '0') {
|
||||
clearHudFxTimer('speed')
|
||||
nextData.panelSpeedFxClass = 'race-panel__metric-group--fx-speed-update'
|
||||
panelSpeedFxTimer = setTimeout(() => {
|
||||
panelSpeedFxTimer = 0
|
||||
this.setData({ panelSpeedFxClass: '' })
|
||||
}, 360) as unknown as number
|
||||
}
|
||||
|
||||
if (typeof nextPatch.panelHeartRateValueText === 'string' && nextPatch.panelHeartRateValueText !== this.data.panelHeartRateValueText && this.data.panelHeartRateValueText !== '--') {
|
||||
clearHudFxTimer('heartRate')
|
||||
nextData.panelHeartRateFxClass = 'race-panel__metric-group--fx-heart-rate-update'
|
||||
panelHeartRateFxTimer = setTimeout(() => {
|
||||
panelHeartRateFxTimer = 0
|
||||
this.setData({ panelHeartRateFxClass: '' })
|
||||
}, 400) as unknown as number
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(nextData).length || Object.keys(derivedPatch).length) {
|
||||
this.setData({
|
||||
...nextData,
|
||||
@@ -698,22 +882,46 @@ Page({
|
||||
},
|
||||
})
|
||||
|
||||
const storedUserSettings = loadStoredUserSettings()
|
||||
if (storedUserSettings.animationLevel) {
|
||||
mapEngine.handleSetAnimationLevel(storedUserSettings.animationLevel)
|
||||
}
|
||||
if (storedUserSettings.northReferenceMode) {
|
||||
mapEngine.handleSetNorthReferenceMode(storedUserSettings.northReferenceMode)
|
||||
}
|
||||
|
||||
mapEngine.setDiagnosticUiEnabled(false)
|
||||
centerScaleRulerInputCache = {
|
||||
stageWidth: 0,
|
||||
stageHeight: 0,
|
||||
zoom: 0,
|
||||
centerTileY: 0,
|
||||
tileSizePx: 0,
|
||||
previewScale: 1,
|
||||
}
|
||||
|
||||
const initialShowCenterScaleRuler = !!storedUserSettings.showCenterScaleRuler
|
||||
const initialCenterScaleRulerAnchorMode = storedUserSettings.centerScaleRulerAnchorMode || 'screen-center'
|
||||
|
||||
this.setData({
|
||||
...mapEngine.getInitialData(),
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: initialShowCenterScaleRuler,
|
||||
statusBarHeight,
|
||||
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
||||
hudPanelIndex: 0,
|
||||
configSourceText: '顺序赛配置',
|
||||
centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
||||
gameInfoTitle: '当前游戏',
|
||||
gameInfoSubtitle: '未开始',
|
||||
gameInfoLocalRows: [],
|
||||
gameInfoGlobalRows: buildEmptyGameInfoSnapshot().globalRows,
|
||||
panelTimerText: '00:00:00',
|
||||
panelTimerFxClass: '',
|
||||
panelMileageText: '0m',
|
||||
panelMileageFxClass: '',
|
||||
panelActionTagText: '目标',
|
||||
panelDistanceTagText: '点距',
|
||||
panelDistanceValueText: '--',
|
||||
@@ -740,6 +948,7 @@ Page({
|
||||
mockHeartRateBridgeUrlDraft: 'wss://gs.gotomars.xyz/mock-gps',
|
||||
mockHeartRateText: '--',
|
||||
panelSpeedValueText: '0',
|
||||
panelSpeedFxClass: '',
|
||||
panelTelemetryTone: 'blue',
|
||||
panelHeartRateZoneNameText: '--',
|
||||
panelHeartRateZoneRangeText: '',
|
||||
@@ -747,6 +956,7 @@ Page({
|
||||
heartRateStatusText: '心率带未连接',
|
||||
heartRateDeviceText: '--',
|
||||
panelHeartRateValueText: '--',
|
||||
panelHeartRateFxClass: '',
|
||||
panelHeartRateUnitText: '',
|
||||
panelCaloriesValueText: '0',
|
||||
panelCaloriesUnitText: 'kcal',
|
||||
@@ -760,6 +970,9 @@ Page({
|
||||
accelerometerText: '--',
|
||||
gyroscopeText: '--',
|
||||
deviceMotionText: '--',
|
||||
compassSourceText: '无数据',
|
||||
compassTuningProfile: 'balanced',
|
||||
compassTuningProfileText: '平衡',
|
||||
punchButtonText: '打点',
|
||||
punchButtonEnabled: false,
|
||||
skipButtonEnabled: false,
|
||||
@@ -771,6 +984,8 @@ Page({
|
||||
contentCardTitle: '',
|
||||
contentCardBody: '',
|
||||
punchButtonFxClass: '',
|
||||
panelProgressFxClass: '',
|
||||
panelDistanceFxClass: '',
|
||||
punchFeedbackFxClass: '',
|
||||
contentCardFxClass: '',
|
||||
mapPulseVisible: false,
|
||||
@@ -785,8 +1000,9 @@ Page({
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: 'left',
|
||||
showGameInfoPanel: false,
|
||||
showCenterScaleRuler: false,
|
||||
centerScaleRulerAnchorMode: 'screen-center',
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: initialShowCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
||||
skipButtonEnabled: false,
|
||||
gameSessionStatus: 'idle',
|
||||
gpsLockEnabled: false,
|
||||
@@ -794,8 +1010,8 @@ Page({
|
||||
}),
|
||||
...buildCenterScaleRulerPatch({
|
||||
...(mapEngine.getInitialData() as MapPageData),
|
||||
showCenterScaleRuler: false,
|
||||
centerScaleRulerAnchorMode: 'screen-center',
|
||||
showCenterScaleRuler: initialShowCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
||||
stageWidth: 0,
|
||||
stageHeight: 0,
|
||||
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
||||
@@ -827,7 +1043,12 @@ Page({
|
||||
onUnload() {
|
||||
clearGameInfoPanelSyncTimer()
|
||||
clearCenterScaleRulerSyncTimer()
|
||||
clearCenterScaleRulerUpdateTimer()
|
||||
clearPunchHintDismissTimer()
|
||||
clearHudFxTimer('timer')
|
||||
clearHudFxTimer('mileage')
|
||||
clearHudFxTimer('speed')
|
||||
clearHudFxTimer('heartRate')
|
||||
if (mapEngine) {
|
||||
mapEngine.destroy()
|
||||
mapEngine = null
|
||||
@@ -997,6 +1218,24 @@ Page({
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningSmooth() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('smooth')
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningBalanced() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('balanced')
|
||||
}
|
||||
},
|
||||
|
||||
handleSetCompassTuningResponsive() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleSetCompassTuningProfile('responsive')
|
||||
}
|
||||
},
|
||||
|
||||
handleAutoRotateCalibrate() {
|
||||
if (mapEngine) {
|
||||
mapEngine.handleAutoRotateCalibrate()
|
||||
@@ -1260,10 +1499,12 @@ Page({
|
||||
this.syncGameInfoPanelSnapshot()
|
||||
this.setData({
|
||||
showDebugPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showGameInfoPanel: true,
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: true,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
@@ -1281,6 +1522,7 @@ Page({
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
@@ -1293,6 +1535,89 @@ Page({
|
||||
|
||||
handleGameInfoPanelTap() {},
|
||||
|
||||
handleOpenSystemSettingsPanel() {
|
||||
clearGameInfoPanelSyncTimer()
|
||||
this.setData({
|
||||
showDebugPanel: false,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: true,
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: true,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
gameSessionStatus: this.data.gameSessionStatus,
|
||||
gpsLockEnabled: this.data.gpsLockEnabled,
|
||||
gpsLockAvailable: this.data.gpsLockAvailable,
|
||||
}),
|
||||
})
|
||||
},
|
||||
|
||||
handleCloseSystemSettingsPanel() {
|
||||
this.setData({
|
||||
showSystemSettingsPanel: false,
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: this.data.showGameInfoPanel,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
gameSessionStatus: this.data.gameSessionStatus,
|
||||
gpsLockEnabled: this.data.gpsLockEnabled,
|
||||
gpsLockAvailable: this.data.gpsLockAvailable,
|
||||
}),
|
||||
})
|
||||
},
|
||||
|
||||
handleSystemSettingsPanelTap() {},
|
||||
|
||||
handleSetAnimationLevelStandard() {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetAnimationLevel('standard')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
animationLevel: 'standard',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetAnimationLevelLite() {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetAnimationLevel('lite')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
animationLevel: 'lite',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetNorthReferenceMagnetic() {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetNorthReferenceMode('magnetic')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
northReferenceMode: 'magnetic',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetNorthReferenceTrue() {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
mapEngine.handleSetNorthReferenceMode('true')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
northReferenceMode: 'true',
|
||||
})
|
||||
},
|
||||
|
||||
handleOverlayTouch() {},
|
||||
|
||||
handlePunchAction() {
|
||||
@@ -1318,6 +1643,8 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
handlePunchHintTap() {},
|
||||
|
||||
handleHudPanelChange(event: WechatMiniprogram.CustomEvent<{ current: number }>) {
|
||||
this.setData({
|
||||
hudPanelIndex: event.detail.current || 0,
|
||||
@@ -1331,6 +1658,7 @@ Page({
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: nextMode,
|
||||
showGameInfoPanel: this.data.showGameInfoPanel,
|
||||
showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
@@ -1368,9 +1696,11 @@ Page({
|
||||
this.setData({
|
||||
showDebugPanel: nextShowDebugPanel,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: false,
|
||||
showSystemSettingsPanel: false,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
@@ -1390,6 +1720,7 @@ Page({
|
||||
...buildSideButtonState({
|
||||
sideButtonMode: this.data.sideButtonMode,
|
||||
showGameInfoPanel: this.data.showGameInfoPanel,
|
||||
showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
skipButtonEnabled: this.data.skipButtonEnabled,
|
||||
@@ -1400,25 +1731,29 @@ Page({
|
||||
})
|
||||
},
|
||||
|
||||
handleToggleCenterScaleRuler() {
|
||||
const nextEnabled = !this.data.showCenterScaleRuler
|
||||
applyCenterScaleRulerSettings(nextEnabled: boolean, nextAnchorMode: CenterScaleRulerAnchorMode) {
|
||||
this.data.showCenterScaleRuler = nextEnabled
|
||||
this.data.centerScaleRulerAnchorMode = nextAnchorMode
|
||||
clearCenterScaleRulerSyncTimer()
|
||||
clearCenterScaleRulerUpdateTimer()
|
||||
|
||||
const syncRulerFromEngine = () => {
|
||||
if (!mapEngine) {
|
||||
return
|
||||
}
|
||||
const engineSnapshot = mapEngine.getInitialData() as Partial<MapPageData>
|
||||
updateCenterScaleRulerInputCache(engineSnapshot)
|
||||
const mergedData = {
|
||||
...engineSnapshot,
|
||||
...centerScaleRulerInputCache,
|
||||
...this.data,
|
||||
showCenterScaleRuler: nextEnabled,
|
||||
centerScaleRulerAnchorMode: nextAnchorMode,
|
||||
} as MapPageData
|
||||
|
||||
this.setData({
|
||||
...filterDebugOnlyPatch(engineSnapshot, this.data.showDebugPanel, nextEnabled),
|
||||
showCenterScaleRuler: nextEnabled,
|
||||
centerScaleRulerAnchorMode: nextAnchorMode,
|
||||
...buildCenterScaleRulerPatch(mergedData),
|
||||
...buildSideButtonState(mergedData),
|
||||
})
|
||||
@@ -1431,9 +1766,11 @@ Page({
|
||||
|
||||
this.setData({
|
||||
showCenterScaleRuler: true,
|
||||
centerScaleRulerAnchorMode: nextAnchorMode,
|
||||
...buildSideButtonState({
|
||||
...this.data,
|
||||
showCenterScaleRuler: true,
|
||||
centerScaleRulerAnchorMode: nextAnchorMode,
|
||||
} as MapPageData),
|
||||
})
|
||||
|
||||
@@ -1450,6 +1787,42 @@ Page({
|
||||
}, 96) as unknown as number
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerVisibleOn() {
|
||||
this.applyCenterScaleRulerSettings(true, this.data.centerScaleRulerAnchorMode)
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
showCenterScaleRuler: true,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerVisibleOff() {
|
||||
this.applyCenterScaleRulerSettings(false, this.data.centerScaleRulerAnchorMode)
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
showCenterScaleRuler: false,
|
||||
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerAnchorScreenCenter() {
|
||||
this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'screen-center')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: 'screen-center',
|
||||
})
|
||||
},
|
||||
|
||||
handleSetCenterScaleRulerAnchorCompassCenter() {
|
||||
this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'compass-center')
|
||||
persistStoredUserSettings({
|
||||
...loadStoredUserSettings(),
|
||||
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
||||
centerScaleRulerAnchorMode: 'compass-center',
|
||||
})
|
||||
},
|
||||
|
||||
handleToggleCenterScaleRulerAnchor() {
|
||||
if (!this.data.showCenterScaleRuler) {
|
||||
return
|
||||
@@ -1459,9 +1832,10 @@ Page({
|
||||
? 'compass-center'
|
||||
: 'screen-center'
|
||||
const engineSnapshot = mapEngine ? (mapEngine.getInitialData() as Partial<MapPageData>) : {}
|
||||
updateCenterScaleRulerInputCache(engineSnapshot)
|
||||
this.data.centerScaleRulerAnchorMode = nextAnchorMode
|
||||
const mergedData = {
|
||||
...engineSnapshot,
|
||||
...centerScaleRulerInputCache,
|
||||
...this.data,
|
||||
centerScaleRulerAnchorMode: nextAnchorMode,
|
||||
} as MapPageData
|
||||
|
||||
@@ -28,10 +28,6 @@
|
||||
<view class="map-stage__map-pulse {{mapPulseFxClass}}" wx:if="{{mapPulseVisible}}" style="left: {{mapPulseLeftPx}}px; top: {{mapPulseTopPx}}px;"></view>
|
||||
<view class="map-stage__stage-fx {{stageFxClass}}" wx:if="{{stageFxVisible}}"></view>
|
||||
|
||||
<view class="game-punch-hint" wx:if="{{showPunchHintBanner && punchHintText}}" style="top: {{topInsetHeight}}px;">
|
||||
<view class="game-punch-hint__text">{{punchHintText}}</view>
|
||||
<view class="game-punch-hint__close" bindtap="handleClosePunchHint">×</view>
|
||||
</view>
|
||||
<view class="game-punch-feedback game-punch-feedback--{{punchFeedbackTone}} {{punchFeedbackFxClass}}" wx:if="{{punchFeedbackVisible}}">{{punchFeedbackText}}</view>
|
||||
<view class="game-content-card {{contentCardFxClass}}" wx:if="{{contentCardVisible}}" bindtap="handleCloseContentCard">
|
||||
<view class="game-content-card__title">{{contentCardTitle}}</view>
|
||||
@@ -40,7 +36,7 @@
|
||||
</view>
|
||||
|
||||
|
||||
<view class="map-stage__overlay-center-layer" wx:if="{{!showDebugPanel && !showGameInfoPanel}}">
|
||||
<view class="map-stage__overlay-center-layer" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}">
|
||||
<view class="center-scale-ruler" wx:if="{{centerScaleRulerVisible}}" style="left: {{centerScaleRulerCenterXPx}}px; top: {{centerScaleRulerZeroYPx}}px; height: {{centerScaleRulerHeightPx}}px;">
|
||||
<view class="center-scale-ruler__axis" style="bottom: {{centerScaleRulerAxisBottomPx}}px;"></view>
|
||||
<view class="center-scale-ruler__arrow"></view>
|
||||
@@ -84,13 +80,18 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<cover-view class="map-side-toggle" wx:if="{{!showDebugPanel && !showGameInfoPanel}}" style="top: {{topInsetHeight}}px;" bindtap="handleCycleSideButtons">
|
||||
<view class="game-punch-hint" wx:if="{{showPunchHintBanner && punchHintText}}" style="top: {{topInsetHeight}}px;" catchtouchstart="handlePunchHintTap" catchtouchmove="handlePunchHintTap" catchtouchend="handlePunchHintTap">
|
||||
<view class="game-punch-hint__text">{{punchHintText}}</view>
|
||||
<view class="game-punch-hint__close" catchtouchstart="handlePunchHintTap" catchtouchmove="handlePunchHintTap" catchtouchend="handlePunchHintTap" catchtap="handleClosePunchHint">×</view>
|
||||
</view>
|
||||
|
||||
<cover-view class="map-side-toggle" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}" style="top: {{topInsetHeight}}px;" bindtap="handleCycleSideButtons">
|
||||
<cover-view class="map-side-button map-side-button--icon">
|
||||
<cover-image class="map-side-button__image" src="{{sideToggleIconSrc}}"></cover-image>
|
||||
</cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--left map-side-column--left-group" wx:if="{{!showDebugPanel && !showGameInfoPanel && showLeftButtonGroup}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-column map-side-column--left map-side-column--left-group" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showLeftButtonGroup}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-button map-side-button--icon" bindtap="handleToggleMapRotateMode"><cover-image class="map-side-button__rotate-image {{orientationMode === 'heading-up' ? 'map-side-button__rotate-image--active' : ''}}" src="../../assets/btn_map_rotate_cropped.png"></cover-image></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--muted"><cover-view class="map-side-button__text">1</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton2Class}}" bindtap="handleToggleGpsLock"><cover-view class="map-side-button__text">2</cover-view></cover-view>
|
||||
@@ -98,7 +99,7 @@
|
||||
<cover-view class="{{sideButton4Class}}" bindtap="handleForceExitGame"><cover-image class="map-side-button__action-image" src="../../assets/btn_exit.png"></cover-image></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--right-main" wx:if="{{!showDebugPanel && !showGameInfoPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-column map-side-column--right-main" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">5</cover-view></cover-view>
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">6</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">7</cover-view></cover-view>
|
||||
@@ -107,24 +108,24 @@
|
||||
<cover-view class="map-side-button map-side-button--active"><cover-view class="map-side-button__text">10</cover-view></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-side-column map-side-column--right-sub" wx:if="{{!showDebugPanel && !showGameInfoPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="map-side-column map-side-column--right-sub" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showRightButtonGroups}}" style="top: {{topInsetHeight}}px;">
|
||||
<cover-view class="{{sideButton11Class}}" bindtap="handleOpenGameInfoPanel"><cover-image class="map-side-button__action-image" src="../../assets/btn_info.png"></cover-image></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">12</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton13Class}}" bindtap="handleToggleCenterScaleRuler"><cover-view class="map-side-button__text">13</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton14Class}}" bindtap="handleToggleCenterScaleRulerAnchor"><cover-view class="map-side-button__text">14</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton12Class}}" bindtap="handleOpenSystemSettingsPanel"><cover-view class="map-side-button__text">12</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">13</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">14</cover-view></cover-view>
|
||||
<cover-view class="map-side-button"><cover-view class="map-side-button__text">15</cover-view></cover-view>
|
||||
<cover-view class="{{sideButton16Class}}" bindtap="handleSkipAction"><cover-image class="map-side-button__action-image" src="../../assets/btn_skip_cp.png"></cover-image></cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="map-punch-button {{punchButtonEnabled ? 'map-punch-button--active' : ''}} {{punchButtonFxClass}}" wx:if="{{!showDebugPanel && !showGameInfoPanel}}" bindtap="handlePunchAction">
|
||||
<cover-view class="map-punch-button {{punchButtonEnabled ? 'map-punch-button--active' : ''}} {{punchButtonFxClass}}" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}" bindtap="handlePunchAction">
|
||||
<cover-view class="map-punch-button__text">{{punchButtonText}}</cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="screen-button-layer screen-button-layer--start-left" wx:if="{{!showDebugPanel && !showGameInfoPanel && showBottomDebugButton && gameSessionStatus === 'idle'}}" bindtap="handleStartGame">
|
||||
<cover-view class="screen-button-layer screen-button-layer--start-left" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showBottomDebugButton && gameSessionStatus === 'idle'}}" bindtap="handleStartGame">
|
||||
<cover-view class="screen-button-layer__text screen-button-layer__text--start">开始</cover-view>
|
||||
</cover-view>
|
||||
|
||||
<cover-view class="screen-button-layer screen-button-layer--bottom-left" wx:if="{{!showDebugPanel && !showGameInfoPanel && showBottomDebugButton}}" bindtap="handleToggleDebugPanel">
|
||||
<cover-view class="screen-button-layer screen-button-layer--bottom-left" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel && showBottomDebugButton}}" bindtap="handleToggleDebugPanel">
|
||||
<cover-view class="screen-button-layer__icon">
|
||||
<cover-view class="screen-button-layer__line"></cover-view>
|
||||
<cover-view class="screen-button-layer__stand"></cover-view>
|
||||
@@ -132,7 +133,7 @@
|
||||
<cover-view class="screen-button-layer__text">调试</cover-view>
|
||||
</cover-view>
|
||||
|
||||
<swiper wx:if="{{!showGameInfoPanel}}" class="race-panel-swiper" current="{{hudPanelIndex}}" bindchange="handleHudPanelChange" duration="220" easing-function="easeOutCubic">
|
||||
<swiper wx:if="{{!showGameInfoPanel && !showSystemSettingsPanel}}" class="race-panel-swiper" current="{{hudPanelIndex}}" bindchange="handleHudPanelChange" duration="220" easing-function="easeOutCubic">
|
||||
<swiper-item>
|
||||
<view class="race-panel race-panel--tone-{{panelTelemetryTone}}">
|
||||
<view class="race-panel__tag race-panel__tag--top-left">{{panelActionTagText}}</view>
|
||||
@@ -155,10 +156,10 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--timer">
|
||||
<text class="race-panel__timer">{{panelTimerText}}</text>
|
||||
<text class="race-panel__timer {{panelTimerFxClass}}">{{panelTimerText}}</text>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--mileage">
|
||||
<view class="race-panel__mileage-wrap">
|
||||
<view class="race-panel__mileage-wrap {{panelMileageFxClass}}">
|
||||
<text class="race-panel__mileage">{{panelMileageText}}</text>
|
||||
<view class="race-panel__chevrons">
|
||||
<view class="race-panel__chevron"></view>
|
||||
@@ -167,16 +168,16 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--distance">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--left">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--left {{panelDistanceFxClass}}">
|
||||
<text class="race-panel__metric-value race-panel__metric-value--distance">{{panelDistanceValueText}}</text>
|
||||
<text class="race-panel__metric-unit race-panel__metric-unit--distance">{{panelDistanceUnitText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--progress">
|
||||
<text class="race-panel__progress">{{panelProgressText}}</text>
|
||||
<text class="race-panel__progress {{panelProgressFxClass}}">{{panelProgressText}}</text>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--speed">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--right">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--right {{panelSpeedFxClass}}">
|
||||
<text class="race-panel__metric-value race-panel__metric-value--speed">{{panelSpeedValueText}}</text>
|
||||
<text class="race-panel__metric-unit race-panel__metric-unit--speed">km/h</text>
|
||||
</view>
|
||||
@@ -201,13 +202,13 @@
|
||||
|
||||
<view class="race-panel__grid">
|
||||
<view class="race-panel__cell race-panel__cell--action">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--left race-panel__metric-group--panel">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--left race-panel__metric-group--panel {{panelHeartRateFxClass}}">
|
||||
<text class="race-panel__metric-value race-panel__metric-value--telemetry">{{panelHeartRateValueText}}</text>
|
||||
<text class="race-panel__metric-unit race-panel__metric-unit--telemetry">{{panelHeartRateUnitText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--timer">
|
||||
<text class="race-panel__timer">{{panelTimerText}}</text>
|
||||
<text class="race-panel__timer {{panelTimerFxClass}}">{{panelTimerText}}</text>
|
||||
</view>
|
||||
<view class="race-panel__cell race-panel__cell--mileage">
|
||||
<view class="race-panel__metric-group race-panel__metric-group--right race-panel__metric-group--panel">
|
||||
@@ -237,7 +238,7 @@
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="race-panel-pager" wx:if="{{!showDebugPanel && !showGameInfoPanel}}">
|
||||
<view class="race-panel-pager" wx:if="{{!showDebugPanel && !showGameInfoPanel && !showSystemSettingsPanel}}">
|
||||
<view class="race-panel-pager__dot {{hudPanelIndex === 0 ? 'race-panel-pager__dot--active' : ''}}"></view>
|
||||
<view class="race-panel-pager__dot {{hudPanelIndex === 1 ? 'race-panel-pager__dot--active' : ''}}"></view>
|
||||
</view>
|
||||
@@ -281,6 +282,93 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="game-info-modal" wx:if="{{showSystemSettingsPanel}}" bindtap="handleCloseSystemSettingsPanel">
|
||||
<view class="game-info-modal__dialog" catchtap="handleSystemSettingsPanelTap">
|
||||
<view class="game-info-modal__header">
|
||||
<view class="game-info-modal__header-main">
|
||||
<view class="game-info-modal__eyebrow">SYSTEM SETTINGS</view>
|
||||
<view class="game-info-modal__title">系统设置</view>
|
||||
<view class="game-info-modal__subtitle">用户端偏好与设备级选项</view>
|
||||
</view>
|
||||
<view class="game-info-modal__header-actions">
|
||||
<view class="game-info-modal__close" bindtap="handleCloseSystemSettingsPanel">关闭</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view class="game-info-modal__content" scroll-y enhanced show-scrollbar="true">
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">01. 动画性能</view>
|
||||
<view class="debug-section__desc">根据设备性能切换动画强度,低端机建议精简</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前级别</text>
|
||||
<text class="info-panel__value">{{animationLevel === 'lite' ? '精简' : '标准'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{animationLevel === 'standard' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetAnimationLevelStandard">标准</view>
|
||||
<view class="control-chip {{animationLevel === 'lite' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetAnimationLevelLite">精简</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">02. 比例尺显示</view>
|
||||
<view class="debug-section__desc">控制比例尺显示与否,默认沿用你的本地偏好</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前状态</text>
|
||||
<text class="info-panel__value">{{showCenterScaleRuler ? '显示' : '隐藏'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerVisibleOn">显示</view>
|
||||
<view class="control-chip {{!showCenterScaleRuler ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerVisibleOff">隐藏</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">03. 比例尺基准点</view>
|
||||
<view class="debug-section__desc">设置比例尺零点锚定位置,可跟随屏幕中心或指北针圆心</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前锚点</text>
|
||||
<text class="info-panel__value">{{centerScaleRulerAnchorMode === 'compass-center' ? '指北针圆心' : '屏幕中心'}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'screen-center' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerAnchorScreenCenter">屏幕中心</view>
|
||||
<view class="control-chip {{centerScaleRulerAnchorMode === 'compass-center' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCenterScaleRulerAnchorCompassCenter">指北针圆心</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">04. 北参考</view>
|
||||
<view class="debug-section__desc">切换磁北/真北作为地图与指北针参考</view>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">当前参考</text>
|
||||
<text class="info-panel__value">{{northReferenceText}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{northReferenceMode === 'magnetic' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetNorthReferenceMagnetic">磁北</view>
|
||||
<view class="control-chip {{northReferenceMode === 'true' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetNorthReferenceTrue">真北</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-section debug-section--info">
|
||||
<view class="debug-section__header">
|
||||
<view class="debug-section__title">05. 心率设备</view>
|
||||
<view class="debug-section__desc">清除已记住的首选心率带设备,下次重新选择</view>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip control-chip--secondary" bindtap="handleClearPreferredHeartRateDevice">清除首选设备</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="debug-modal" wx:if="{{showDebugPanel}}" bindtap="handleCloseDebugPanel">
|
||||
<view class="debug-modal__dialog" catchtap="handleDebugPanelTap">
|
||||
<view class="debug-modal__header">
|
||||
@@ -464,6 +552,19 @@
|
||||
<text class="info-panel__label">Heading Confidence</text>
|
||||
<text class="info-panel__value">{{headingConfidenceText}}</text>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">Compass Source</text>
|
||||
<text class="info-panel__value">{{compassSourceText}}</text>
|
||||
</view>
|
||||
<view class="info-panel__row">
|
||||
<text class="info-panel__label">Compass Tune</text>
|
||||
<text class="info-panel__value">{{compassTuningProfileText}}</text>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<view class="control-chip {{compassTuningProfile === 'smooth' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningSmooth">顺滑</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'balanced' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningBalanced">平衡</view>
|
||||
<view class="control-chip {{compassTuningProfile === 'responsive' ? 'control-chip--active' : 'control-chip--secondary'}}" bindtap="handleSetCompassTuningResponsive">跟手</view>
|
||||
</view>
|
||||
<view class="info-panel__row info-panel__row--stack">
|
||||
<text class="info-panel__label">Accel</text>
|
||||
<text class="info-panel__value">{{accelerometerText}}</text>
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
animation: stage-fx-finish 0.76s ease-out 1;
|
||||
}
|
||||
|
||||
.map-stage__stage-fx--control {
|
||||
animation: stage-fx-control 0.52s ease-out 1;
|
||||
}
|
||||
|
||||
.map-stage__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -834,6 +838,10 @@
|
||||
text-shadow: 0 2rpx 0 rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.race-panel__timer--fx-tick {
|
||||
animation: race-panel-timer-tick 0.32s cubic-bezier(0.24, 0.86, 0.3, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__mileage {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
@@ -851,6 +859,10 @@
|
||||
transform: translateX(-16rpx);
|
||||
}
|
||||
|
||||
.race-panel__mileage-wrap--fx-update {
|
||||
animation: race-panel-mileage-update 0.36s cubic-bezier(0.22, 0.88, 0.34, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__metric-group {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
@@ -864,11 +876,23 @@
|
||||
transform: translateX(16rpx);
|
||||
}
|
||||
|
||||
.race-panel__metric-group--fx-distance-success {
|
||||
animation: race-panel-distance-success 0.56s cubic-bezier(0.22, 0.88, 0.34, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__metric-group--right {
|
||||
justify-content: center;
|
||||
transform: translateX(-16rpx);
|
||||
}
|
||||
|
||||
.race-panel__metric-group--fx-speed-update {
|
||||
animation: race-panel-speed-update 0.36s cubic-bezier(0.22, 0.88, 0.34, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__metric-group--fx-heart-rate-update {
|
||||
animation: race-panel-heart-rate-update 0.4s cubic-bezier(0.2, 0.9, 0.3, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__metric-value {
|
||||
line-height: 1;
|
||||
text-shadow: 0 2rpx 0 rgba(255, 255, 255, 0.16);
|
||||
@@ -924,6 +948,38 @@
|
||||
text-shadow: 0 2rpx 0 rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.race-panel__progress--fx-success {
|
||||
animation: race-panel-progress-success 0.56s cubic-bezier(0.2, 0.88, 0.32, 1) 1;
|
||||
}
|
||||
|
||||
.race-panel__progress--fx-finish {
|
||||
animation: race-panel-progress-finish 0.68s cubic-bezier(0.18, 0.92, 0.28, 1) 1;
|
||||
}
|
||||
|
||||
@keyframes race-panel-timer-tick {
|
||||
0% { transform: translateY(0) scale(1); opacity: 0.94; }
|
||||
35% { transform: translateY(-2rpx) scale(1.04); opacity: 1; }
|
||||
100% { transform: translateY(0) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes race-panel-mileage-update {
|
||||
0% { transform: translateX(-16rpx) scale(1); opacity: 0.94; }
|
||||
40% { transform: translateX(-16rpx) scale(1.05); opacity: 1; }
|
||||
100% { transform: translateX(-16rpx) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes race-panel-speed-update {
|
||||
0% { transform: translateX(-16rpx) scale(1); opacity: 0.94; }
|
||||
40% { transform: translateX(-16rpx) scale(1.06); opacity: 1; }
|
||||
100% { transform: translateX(-16rpx) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes race-panel-heart-rate-update {
|
||||
0% { transform: translateX(16rpx) scale(1); opacity: 0.94; }
|
||||
38% { transform: translateX(16rpx) scale(1.05); opacity: 1; }
|
||||
100% { transform: translateX(16rpx) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
.race-panel__zone {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -982,6 +1038,72 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@keyframes race-panel-distance-success {
|
||||
0% {
|
||||
transform: translateX(16rpx) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
28% {
|
||||
transform: translateX(16rpx) scale(1.09);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
62% {
|
||||
transform: translateX(16rpx) scale(0.98);
|
||||
opacity: 0.96;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateX(16rpx) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes race-panel-progress-success {
|
||||
0% {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
24% {
|
||||
transform: scale(1.16) translateY(-4rpx);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: scale(0.98) translateY(0);
|
||||
opacity: 0.96;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes race-panel-progress-finish {
|
||||
0% {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
20% {
|
||||
transform: scale(1.2) translateY(-6rpx);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
46% {
|
||||
transform: scale(1.08) translateY(-2rpx);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.map-punch-button {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
@@ -1593,7 +1715,7 @@
|
||||
font-size: 24rpx;
|
||||
line-height: 1.2;
|
||||
text-align: left;
|
||||
z-index: 16;
|
||||
z-index: 40;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@@ -1603,9 +1725,9 @@
|
||||
}
|
||||
|
||||
.game-punch-hint__close {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
flex: 0 0 40rpx;
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
flex: 0 0 56rpx;
|
||||
border-radius: 999rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1939,3 +2061,21 @@
|
||||
backdrop-filter: brightness(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes stage-fx-control {
|
||||
0% {
|
||||
opacity: 0;
|
||||
background: radial-gradient(circle at 50% 50%, rgba(138, 255, 235, 0.16) 0%, rgba(138, 255, 235, 0.06) 26%, rgba(255, 255, 255, 0) 60%);
|
||||
backdrop-filter: brightness(1);
|
||||
}
|
||||
36% {
|
||||
opacity: 1;
|
||||
background: radial-gradient(circle at 50% 50%, rgba(138, 255, 235, 0.24) 0%, rgba(138, 255, 235, 0.1) 32%, rgba(255, 255, 255, 0.03) 72%);
|
||||
backdrop-filter: brightness(1.03);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
background: radial-gradient(circle at 50% 50%, rgba(138, 255, 235, 0) 0%, rgba(138, 255, 235, 0) 100%);
|
||||
backdrop-filter: brightness(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user