gameRuntime.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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 { ClassicSequentialRule } from '../rules/classicSequentialRule'
  7. import { type RulePlugin } from '../rules/rulePlugin'
  8. export class GameRuntime {
  9. definition: GameDefinition | null
  10. plugin: RulePlugin | null
  11. state: GameSessionState | null
  12. presentation: GamePresentationState
  13. lastResult: GameResult | null
  14. constructor() {
  15. this.definition = null
  16. this.plugin = null
  17. this.state = null
  18. this.presentation = EMPTY_GAME_PRESENTATION_STATE
  19. this.lastResult = null
  20. }
  21. clear(): void {
  22. this.definition = null
  23. this.plugin = null
  24. this.state = null
  25. this.presentation = EMPTY_GAME_PRESENTATION_STATE
  26. this.lastResult = null
  27. }
  28. loadDefinition(definition: GameDefinition): GameResult {
  29. this.definition = definition
  30. this.plugin = this.resolvePlugin(definition)
  31. this.state = this.plugin.initialize(definition)
  32. const result: GameResult = {
  33. nextState: this.state,
  34. presentation: this.plugin.buildPresentation(definition, this.state),
  35. effects: [],
  36. }
  37. this.presentation = result.presentation
  38. this.lastResult = result
  39. return result
  40. }
  41. startSession(startAt = Date.now()): GameResult {
  42. return this.dispatch({ type: 'session_started', at: startAt })
  43. }
  44. dispatch(event: GameEvent): GameResult {
  45. if (!this.definition || !this.plugin || !this.state) {
  46. const emptyState: GameSessionState = {
  47. status: 'idle',
  48. startedAt: null,
  49. endedAt: null,
  50. completedControlIds: [],
  51. currentTargetControlId: null,
  52. inRangeControlId: null,
  53. score: 0,
  54. }
  55. const result: GameResult = {
  56. nextState: emptyState,
  57. presentation: EMPTY_GAME_PRESENTATION_STATE,
  58. effects: [],
  59. }
  60. this.lastResult = result
  61. this.presentation = result.presentation
  62. return result
  63. }
  64. const result = this.plugin.reduce(this.definition, this.state, event)
  65. this.state = result.nextState
  66. this.presentation = result.presentation
  67. this.lastResult = result
  68. return result
  69. }
  70. getPresentation(): GamePresentationState {
  71. return this.presentation
  72. }
  73. resolvePlugin(definition: GameDefinition): RulePlugin {
  74. if (definition.mode === 'classic-sequential') {
  75. return new ClassicSequentialRule()
  76. }
  77. throw new Error(`未支持的玩法模式: ${definition.mode}`)
  78. }
  79. }