Add event-driven gameplay feedback framework
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { type LonLatPoint } from '../../utils/projection'
|
||||
import { DEFAULT_GAME_AUDIO_CONFIG } from '../audio/audioConfig'
|
||||
import { type GameControl, type GameDefinition } from '../core/gameDefinition'
|
||||
import { type GameEvent } from '../core/gameEvent'
|
||||
import { type GameEffect, type GameResult } from '../core/gameResult'
|
||||
@@ -56,6 +57,31 @@ function getTargetText(control: GameControl): string {
|
||||
return '目标圈'
|
||||
}
|
||||
|
||||
function getGuidanceState(definition: GameDefinition, distanceMeters: number): GameSessionState['guidanceState'] {
|
||||
if (distanceMeters <= definition.punchRadiusMeters) {
|
||||
return 'ready'
|
||||
}
|
||||
|
||||
const approachDistanceMeters = definition.audioConfig ? definition.audioConfig.approachDistanceMeters : DEFAULT_GAME_AUDIO_CONFIG.approachDistanceMeters
|
||||
if (distanceMeters <= approachDistanceMeters) {
|
||||
return 'approaching'
|
||||
}
|
||||
|
||||
return 'searching'
|
||||
}
|
||||
|
||||
function getGuidanceEffects(
|
||||
previousState: GameSessionState['guidanceState'],
|
||||
nextState: GameSessionState['guidanceState'],
|
||||
controlId: string | null,
|
||||
): GameEffect[] {
|
||||
if (previousState === nextState) {
|
||||
return []
|
||||
}
|
||||
|
||||
return [{ type: 'guidance_state_changed', guidanceState: nextState, controlId }]
|
||||
}
|
||||
|
||||
|
||||
function buildPunchHintText(definition: GameDefinition, state: GameSessionState, currentTarget: GameControl | null): string {
|
||||
if (state.status === 'idle') {
|
||||
@@ -207,6 +233,7 @@ function applyCompletion(definition: GameDefinition, state: GameSessionState, cu
|
||||
score: getScoringControls(definition).filter((control) => completedControlIds.includes(control.id)).length,
|
||||
status: nextTarget || !definition.autoFinishOnLastControl ? state.status : 'finished',
|
||||
endedAt: nextTarget || !definition.autoFinishOnLastControl ? state.endedAt : at,
|
||||
guidanceState: nextTarget ? 'searching' : 'searching',
|
||||
}
|
||||
const effects: GameEffect[] = [buildCompletedEffect(currentTarget)]
|
||||
|
||||
@@ -235,6 +262,7 @@ export class ClassicSequentialRule implements RulePlugin {
|
||||
currentTargetControlId: getInitialTargetId(definition),
|
||||
inRangeControlId: null,
|
||||
score: 0,
|
||||
guidanceState: 'searching',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +278,7 @@ export class ClassicSequentialRule implements RulePlugin {
|
||||
startedAt: event.at,
|
||||
endedAt: null,
|
||||
inRangeControlId: null,
|
||||
guidanceState: 'searching',
|
||||
}
|
||||
return {
|
||||
nextState,
|
||||
@@ -263,6 +292,7 @@ export class ClassicSequentialRule implements RulePlugin {
|
||||
...state,
|
||||
status: 'finished',
|
||||
endedAt: event.at,
|
||||
guidanceState: 'searching',
|
||||
}
|
||||
return {
|
||||
nextState,
|
||||
@@ -291,19 +321,26 @@ export class ClassicSequentialRule implements RulePlugin {
|
||||
if (event.type === 'gps_updated') {
|
||||
const distanceMeters = getApproxDistanceMeters(currentTarget.point, { lon: event.lon, lat: event.lat })
|
||||
const inRangeControlId = distanceMeters <= definition.punchRadiusMeters ? currentTarget.id : null
|
||||
const guidanceState = getGuidanceState(definition, distanceMeters)
|
||||
const nextState: GameSessionState = {
|
||||
...state,
|
||||
inRangeControlId,
|
||||
guidanceState,
|
||||
}
|
||||
const guidanceEffects = getGuidanceEffects(state.guidanceState, guidanceState, currentTarget.id)
|
||||
|
||||
if (definition.punchPolicy === 'enter' && inRangeControlId === currentTarget.id) {
|
||||
return applyCompletion(definition, nextState, currentTarget, event.at)
|
||||
const completionResult = applyCompletion(definition, nextState, currentTarget, event.at)
|
||||
return {
|
||||
...completionResult,
|
||||
effects: [...guidanceEffects, ...completionResult.effects],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
nextState,
|
||||
presentation: buildPresentation(definition, nextState),
|
||||
effects: [],
|
||||
effects: guidanceEffects,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user