完善地图交互、动画与罗盘调试

This commit is contained in:
2026-03-26 16:58:53 +08:00
parent d695308a55
commit 5fc996dea1
18 changed files with 1566 additions and 165 deletions

View File

@@ -1,12 +1,16 @@
import { type GameEffect } from '../core/gameResult'
import { type AnimationLevel } from '../../utils/animationLevel'
import {
DEFAULT_GAME_UI_EFFECTS_CONFIG,
type FeedbackCueKey,
type GameUiEffectsConfig,
type UiContentCardMotion,
type UiHudDistanceMotion,
type UiHudProgressMotion,
type UiMapPulseMotion,
type UiPunchButtonMotion,
type UiPunchFeedbackMotion,
type UiCueConfig,
type UiStageMotion,
} from './feedbackConfig'
@@ -14,6 +18,8 @@ export interface UiEffectHost {
showPunchFeedback: (text: string, tone: 'neutral' | 'success' | 'warning', motionClass?: string) => void
showContentCard: (title: string, body: string, motionClass?: string) => void
setPunchButtonFxClass: (className: string) => void
setHudProgressFxClass: (className: string) => void
setHudDistanceFxClass: (className: string) => void
showMapPulse: (controlId: string, motionClass?: string) => void
showStageFx: (className: string) => void
}
@@ -23,30 +29,46 @@ export class UiEffectDirector {
config: GameUiEffectsConfig
host: UiEffectHost
punchButtonMotionTimer: number
hudProgressMotionTimer: number
hudDistanceMotionTimer: number
punchButtonMotionToggle: boolean
animationLevel: AnimationLevel
constructor(host: UiEffectHost, config: GameUiEffectsConfig = DEFAULT_GAME_UI_EFFECTS_CONFIG) {
this.enabled = true
this.host = host
this.config = config
this.punchButtonMotionTimer = 0
this.hudProgressMotionTimer = 0
this.hudDistanceMotionTimer = 0
this.punchButtonMotionToggle = false
this.animationLevel = 'standard'
}
configure(config: GameUiEffectsConfig): void {
this.config = config
this.clearPunchButtonMotion()
this.clearHudProgressMotion()
this.clearHudDistanceMotion()
}
setEnabled(enabled: boolean): void {
this.enabled = enabled
if (!enabled) {
this.clearPunchButtonMotion()
this.clearHudProgressMotion()
this.clearHudDistanceMotion()
}
}
setAnimationLevel(level: AnimationLevel): void {
this.animationLevel = level
}
destroy(): void {
this.clearPunchButtonMotion()
this.clearHudProgressMotion()
this.clearHudDistanceMotion()
}
clearPunchButtonMotion(): void {
@@ -57,6 +79,22 @@ export class UiEffectDirector {
this.host.setPunchButtonFxClass('')
}
clearHudProgressMotion(): void {
if (this.hudProgressMotionTimer) {
clearTimeout(this.hudProgressMotionTimer)
this.hudProgressMotionTimer = 0
}
this.host.setHudProgressFxClass('')
}
clearHudDistanceMotion(): void {
if (this.hudDistanceMotionTimer) {
clearTimeout(this.hudDistanceMotionTimer)
this.hudDistanceMotionTimer = 0
}
this.host.setHudDistanceFxClass('')
}
getPunchFeedbackMotionClass(motion: UiPunchFeedbackMotion): string {
if (motion === 'warning') {
return 'game-punch-feedback--fx-warning'
@@ -94,12 +132,32 @@ export class UiEffectDirector {
}
getStageMotionClass(motion: UiStageMotion): string {
if (motion === 'control') {
return 'map-stage__stage-fx--control'
}
if (motion === 'finish') {
return 'map-stage__stage-fx--finish'
}
return ''
}
getHudProgressMotionClass(motion: UiHudProgressMotion): string {
if (motion === 'finish') {
return 'race-panel__progress--fx-finish'
}
if (motion === 'success') {
return 'race-panel__progress--fx-success'
}
return ''
}
getHudDistanceMotionClass(motion: UiHudDistanceMotion): string {
if (motion === 'success') {
return 'race-panel__metric-group--fx-distance-success'
}
return ''
}
triggerPunchButtonMotion(motion: UiPunchButtonMotion, durationMs: number): void {
if (motion === 'none') {
return
@@ -121,7 +179,37 @@ export class UiEffectDirector {
}, durationMs) as unknown as number
}
getCue(key: FeedbackCueKey) {
triggerHudProgressMotion(motion: UiHudProgressMotion, durationMs: number): void {
const className = this.getHudProgressMotionClass(motion)
if (!className) {
return
}
this.host.setHudProgressFxClass(className)
if (this.hudProgressMotionTimer) {
clearTimeout(this.hudProgressMotionTimer)
}
this.hudProgressMotionTimer = setTimeout(() => {
this.hudProgressMotionTimer = 0
this.host.setHudProgressFxClass('')
}, durationMs) as unknown as number
}
triggerHudDistanceMotion(motion: UiHudDistanceMotion, durationMs: number): void {
const className = this.getHudDistanceMotionClass(motion)
if (!className) {
return
}
this.host.setHudDistanceFxClass(className)
if (this.hudDistanceMotionTimer) {
clearTimeout(this.hudDistanceMotionTimer)
}
this.hudDistanceMotionTimer = setTimeout(() => {
this.hudDistanceMotionTimer = 0
this.host.setHudDistanceFxClass('')
}, durationMs) as unknown as number
}
getCue(key: FeedbackCueKey): UiCueConfig | null {
if (!this.enabled || !this.config.enabled) {
return null
}
@@ -131,7 +219,16 @@ export class UiEffectDirector {
return null
}
return cue
if (this.animationLevel === 'standard') {
return cue
}
return {
...cue,
stageMotion: 'none' as const,
hudDistanceMotion: 'none' as const,
durationMs: cue.durationMs > 0 ? Math.max(260, Math.round(cue.durationMs * 0.6)) : 0,
}
}
handleEffects(effects: GameEffect[]): void {
@@ -172,6 +269,10 @@ export class UiEffectDirector {
if (cue && cue.stageMotion !== 'none') {
this.host.showStageFx(this.getStageMotionClass(cue.stageMotion))
}
if (cue) {
this.triggerHudProgressMotion(cue.hudProgressMotion, cue.durationMs)
this.triggerHudDistanceMotion(cue.hudDistanceMotion, cue.durationMs)
}
continue
}
@@ -188,10 +289,14 @@ export class UiEffectDirector {
if (effect.type === 'session_finished') {
this.clearPunchButtonMotion()
this.clearHudProgressMotion()
this.clearHudDistanceMotion()
}
if (effect.type === 'session_cancelled') {
this.clearPunchButtonMotion()
this.clearHudProgressMotion()
this.clearHudDistanceMotion()
}
}
}