gameRuntime.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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. guidanceState: 'searching',
  55. }
  56. const result: GameResult = {
  57. nextState: emptyState,
  58. presentation: EMPTY_GAME_PRESENTATION_STATE,
  59. effects: [],
  60. }
  61. this.lastResult = result
  62. this.presentation = result.presentation
  63. return result
  64. }
  65. const result = this.plugin.reduce(this.definition, this.state, event)
  66. this.state = result.nextState
  67. this.presentation = result.presentation
  68. this.lastResult = result
  69. return result
  70. }
  71. getPresentation(): GamePresentationState {
  72. return this.presentation
  73. }
  74. resolvePlugin(definition: GameDefinition): RulePlugin {
  75. if (definition.mode === 'classic-sequential') {
  76. return new ClassicSequentialRule()
  77. }
  78. throw new Error(`未支持的玩法模式: ${definition.mode}`)
  79. }
  80. }