gameRuntime.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { type GameDefinition } from './gameDefinition'
  2. import { type GameEvent } from './gameEvent'
  3. import { type GameResult } from './gameResult'
  4. import { type GameSessionState } from './gameSessionState'
  5. import { EMPTY_GAME_PRESENTATION_STATE, type GamePresentationState } from '../presentation/presentationState'
  6. import { EMPTY_HUD_PRESENTATION_STATE, type HudPresentationState } from '../presentation/hudPresentationState'
  7. import { EMPTY_MAP_PRESENTATION_STATE, type MapPresentationState } from '../presentation/mapPresentationState'
  8. import { ClassicSequentialRule } from '../rules/classicSequentialRule'
  9. import { ScoreORule } from '../rules/scoreORule'
  10. import { type RulePlugin } from '../rules/rulePlugin'
  11. export class GameRuntime {
  12. definition: GameDefinition | null
  13. plugin: RulePlugin | null
  14. state: GameSessionState | null
  15. presentation: GamePresentationState
  16. mapPresentation: MapPresentationState
  17. hudPresentation: HudPresentationState
  18. lastResult: GameResult | null
  19. constructor() {
  20. this.definition = null
  21. this.plugin = null
  22. this.state = null
  23. this.presentation = EMPTY_GAME_PRESENTATION_STATE
  24. this.mapPresentation = EMPTY_MAP_PRESENTATION_STATE
  25. this.hudPresentation = EMPTY_HUD_PRESENTATION_STATE
  26. this.lastResult = null
  27. }
  28. clear(): void {
  29. this.definition = null
  30. this.plugin = null
  31. this.state = null
  32. this.presentation = EMPTY_GAME_PRESENTATION_STATE
  33. this.mapPresentation = EMPTY_MAP_PRESENTATION_STATE
  34. this.hudPresentation = EMPTY_HUD_PRESENTATION_STATE
  35. this.lastResult = null
  36. }
  37. loadDefinition(definition: GameDefinition): GameResult {
  38. this.definition = definition
  39. this.plugin = this.resolvePlugin(definition)
  40. this.state = this.plugin.initialize(definition)
  41. const result: GameResult = {
  42. nextState: this.state,
  43. presentation: this.plugin.buildPresentation(definition, this.state),
  44. effects: [],
  45. }
  46. this.presentation = result.presentation
  47. this.mapPresentation = result.presentation.map
  48. this.hudPresentation = result.presentation.hud
  49. this.lastResult = result
  50. return result
  51. }
  52. startSession(startAt = Date.now()): GameResult {
  53. return this.dispatch({ type: 'session_started', at: startAt })
  54. }
  55. dispatch(event: GameEvent): GameResult {
  56. if (!this.definition || !this.plugin || !this.state) {
  57. const emptyState: GameSessionState = {
  58. status: 'idle',
  59. startedAt: null,
  60. endedAt: null,
  61. completedControlIds: [],
  62. skippedControlIds: [],
  63. currentTargetControlId: null,
  64. inRangeControlId: null,
  65. score: 0,
  66. guidanceState: 'searching',
  67. modeState: null,
  68. }
  69. const result: GameResult = {
  70. nextState: emptyState,
  71. presentation: EMPTY_GAME_PRESENTATION_STATE,
  72. effects: [],
  73. }
  74. this.lastResult = result
  75. this.presentation = result.presentation
  76. this.mapPresentation = result.presentation.map
  77. this.hudPresentation = result.presentation.hud
  78. return result
  79. }
  80. const result = this.plugin.reduce(this.definition, this.state, event)
  81. this.state = result.nextState
  82. this.presentation = result.presentation
  83. this.mapPresentation = result.presentation.map
  84. this.hudPresentation = result.presentation.hud
  85. this.lastResult = result
  86. return result
  87. }
  88. getPresentation(): GamePresentationState {
  89. return this.presentation
  90. }
  91. getMapPresentation(): MapPresentationState {
  92. return this.mapPresentation
  93. }
  94. getHudPresentation(): HudPresentationState {
  95. return this.hudPresentation
  96. }
  97. resolvePlugin(definition: GameDefinition): RulePlugin {
  98. if (definition.mode === 'classic-sequential') {
  99. return new ClassicSequentialRule()
  100. }
  101. if (definition.mode === 'score-o') {
  102. return new ScoreORule()
  103. }
  104. throw new Error(`未支持的玩法模式: ${definition.mode}`)
  105. }
  106. }