src/game/GameRunner.js 1.9 K raw
1
export default class GameRunner {
2
  constructor() {
3
    this.looping = false
4
    this.preloaded = false
5
    this.targetFrameRate = 60
6
    this.frameCount = 0
7
    this.frameRate = 0
8
    this.paused = false
9
    this.stepFrames = null
10
    this._lastFrameTime = window.performance.now()
11
12
    // store this bound function so we don't have to create
13
    // one every single time we call requestAnimationFrame
14
    this.__loop = this._loop.bind(this)
15
  }
16
17
  async start(paused = false) {
18
    if (!this.preloaded) {
19
      if (this.preload) {
20
        await this.preload()
21
      }
22
      this.preloaded = true
23
    }
24
25
    if (paused) {
26
      this.paused = paused
27
    }
28
29
    this.looping = true
30
31
    if (!paused) {
32
      window.requestAnimationFrame(this.__loop)
33
    }
34
  }
35
36
  stop() {
37
    this.looping = false
38
  }
39
40
  pause() {
41
    this.paused = true
42
  }
43
44
  unpause() {
45
    this.paused = false
46
  }
47
48
  step(frames = 1) {
49
    if (typeof this.stepFrames === 'number') {
50
      this.stepFrames += frames
51
    } else {
52
      this.stepFrames = frames
53
    }
54
55
    this.__loop(window.performance.now())
56
  }
57
58
  _loop(timestamp) {
59
    const now = window.performance.now()
60
    const timeSinceLast = now - this._lastFrameTime
61
    const targetTimeBetweenFrames = 1000 / this.targetFrameRate
62
63
    if (timeSinceLast >= targetTimeBetweenFrames - 5) {
64
      this.onFrame()
65
      this.frameRate = 1000 / (now - this._lastFrameTime)
66
      this._lastFrameTime = now
67
      this.frameCount++
68
    }
69
70
    if (this.looping) {
71
      let shouldLoop = true
72
73
      if (this.paused) {
74
        if (typeof this.stepFrames === 'number') {
75
          if (this.stepFrames === 0) {
76
            this.stepFrames = null
77
            shouldLoop = false
78
          } else {
79
            this.stepFrames--
80
          }
81
        } else {
82
          shouldLoop = false
83
        }
84
      }
85
86
      if (shouldLoop) {
87
        window.requestAnimationFrame(this.__loop)
88
      }
89
    }
90
  }
91
}