extra-game-loop 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,10 +37,10 @@ class GameLoop<FixedDeltaTime extends number = number> {
37
37
  constructor(options: {
38
38
  fixedDeltaTime: FixedDeltaTime /* ms */
39
39
  maximumDeltaTime: number /* ms */
40
- update: (deltaTime: number /* ms */) => void
41
- fixedUpdate: (deltaTime: FixedDeltaTime /* ms */) => void
42
- lateUpdate: (deltaTime: number /* ms */, alpha: number) => void
43
- render: (alpha: number /* [0, 1) */) => void
40
+ update?: (deltaTime: number /* ms */) => void
41
+ fixedUpdate?: (deltaTime: FixedDeltaTime /* ms */) => void
42
+ lateUpdate?: (deltaTime: number /* ms */, alpha: number) => void
43
+ render?: (alpha: number /* [0, 1) */) => void
44
44
  })
45
45
 
46
46
  start(): void
@@ -53,3 +53,27 @@ class GameLoop<FixedDeltaTime extends number = number> {
53
53
  nextFrame(deltaTime: number): void
54
54
  }
55
55
  ```
56
+
57
+ ### GameLoopLite
58
+ ```ts
59
+ class GameLoopLite {
60
+ constructor(options: {
61
+ update?: (deltaTime: number /* ms */) => void
62
+ render?: () => void
63
+ })
64
+
65
+ start(): void
66
+ stop(): void
67
+ getFramesOfSecond(): number
68
+
69
+ /**
70
+ * This method allows you to manually advance to the next frame.
71
+ */
72
+ nextFrame(deltaTime: number): void
73
+ }
74
+ ```
75
+
76
+ The lite version of `GameLoop` for situations where the physics system is not needed.
77
+
78
+ Basically, it can be seen as an OOP wrapper for `requestAnimationFrame`,
79
+ so it can be used for non-game projects as well.
@@ -0,0 +1,19 @@
1
+ interface IGameLoopLiteOptions {
2
+ update?: (deltaTime: number) => void;
3
+ render?: () => void;
4
+ }
5
+ export declare class GameLoopLite {
6
+ private readonly fsm;
7
+ private readonly update?;
8
+ private readonly render?;
9
+ private requstId?;
10
+ private lastTimestamp?;
11
+ private lastDeltaTime;
12
+ constructor(options: IGameLoopLiteOptions);
13
+ start(): void;
14
+ stop(): void;
15
+ getFramesOfSecond(): number;
16
+ private loop;
17
+ nextFrame(deltaTime: number): void;
18
+ }
19
+ export {};
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GameLoopLite = void 0;
4
+ const extra_fsm_1 = require("extra-fsm");
5
+ var State;
6
+ (function (State) {
7
+ State["Stopped"] = "stopped";
8
+ State["Running"] = "running";
9
+ })(State || (State = {}));
10
+ const schema = {
11
+ [State.Stopped]: { start: State.Running },
12
+ [State.Running]: { stop: State.Stopped }
13
+ };
14
+ class GameLoopLite {
15
+ constructor(options) {
16
+ this.fsm = new extra_fsm_1.FiniteStateMachine(schema, State.Stopped);
17
+ this.lastDeltaTime = 0;
18
+ this.loop = () => {
19
+ const timestamp = performance.now();
20
+ const deltaTime = timestamp - this.lastTimestamp;
21
+ this.lastDeltaTime = deltaTime;
22
+ this.lastTimestamp = timestamp;
23
+ this.nextFrame(deltaTime);
24
+ this.requstId = requestAnimationFrame(this.loop);
25
+ };
26
+ this.update = options.update;
27
+ this.render = options.render;
28
+ }
29
+ start() {
30
+ this.fsm.send('start');
31
+ this.lastTimestamp = performance.now();
32
+ this.loop();
33
+ }
34
+ stop() {
35
+ this.fsm.send('stop');
36
+ cancelAnimationFrame(this.requstId);
37
+ delete this.requstId;
38
+ delete this.lastTimestamp;
39
+ this.lastDeltaTime = 0;
40
+ }
41
+ getFramesOfSecond() {
42
+ if (this.fsm.matches(State.Running)) {
43
+ return this.lastDeltaTime !== 0
44
+ ? 1000 / this.lastDeltaTime
45
+ : 0;
46
+ }
47
+ else {
48
+ return 0;
49
+ }
50
+ }
51
+ nextFrame(deltaTime) {
52
+ var _a, _b;
53
+ (_a = this.update) === null || _a === void 0 ? void 0 : _a.call(this, deltaTime);
54
+ (_b = this.render) === null || _b === void 0 ? void 0 : _b.call(this);
55
+ }
56
+ }
57
+ exports.GameLoopLite = GameLoopLite;
58
+ //# sourceMappingURL=game-loop-lite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-loop-lite.js","sourceRoot":"","sources":["../src/game-loop-lite.ts"],"names":[],"mappings":";;;AAAA,yCAAyE;AAczE,IAAK,KAGJ;AAHD,WAAK,KAAK;IACR,4BAAmB,CAAA;IACnB,4BAAmB,CAAA;AACrB,CAAC,EAHI,KAAK,KAAL,KAAK,QAGT;AAMD,MAAM,MAAM,GAA4C;IACtD,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE;IACzC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE;CACzC,CAAA;AAED,MAAa,YAAY;IAQvB,YAAY,OAA6B;QAPxB,QAAG,GAAG,IAAI,8BAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAK5D,kBAAa,GAAG,CAAC,CAAA;QAkCjB,SAAI,GAAG,GAAS,EAAE;YAIxB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;YACnC,MAAM,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,aAAc,CAAA;YACjD,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;YAC9B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;YAE9B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;YAEzB,IAAI,CAAC,QAAQ,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClD,CAAC,CAAA;QA3CC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;IAC9B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAEtB,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;QACtC,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,IAAI;QACF,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAErB,oBAAoB,CAAC,IAAI,CAAC,QAAS,CAAC,CAAA;QAEpC,OAAO,IAAI,CAAC,QAAQ,CAAA;QACpB,OAAO,IAAI,CAAC,aAAa,CAAA;QACzB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;IACxB,CAAC;IAED,iBAAiB;QACf,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;YACnC,OAAO,IAAI,CAAC,aAAa,KAAK,CAAC;gBAC1B,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa;gBAC3B,CAAC,CAAC,CAAC,CAAA;SACT;aAAM;YACL,OAAO,CAAC,CAAA;SACT;IACH,CAAC;IAgBD,SAAS,CAAC,SAAiB;;QACzB,MAAA,IAAI,CAAC,MAAM,qDAAG,SAAS,CAAC,CAAA;QAExB,MAAA,IAAI,CAAC,MAAM,oDAAI,CAAA;IACjB,CAAC;CACF;AA3DD,oCA2DC"}
@@ -1,19 +1,19 @@
1
1
  interface IGameLoopOptions<FixedDeltaTime extends number = number> {
2
2
  fixedDeltaTime: FixedDeltaTime;
3
3
  maximumDeltaTime: number;
4
- update: (deltaTime: number) => void;
5
- fixedUpdate: (deltaTime: FixedDeltaTime) => void;
6
- lateUpdate: (deltaTime: number, alpha: number) => void;
7
- render: (alpha: number) => void;
4
+ update?: (deltaTime: number) => void;
5
+ fixedUpdate?: (deltaTime: FixedDeltaTime) => void;
6
+ lateUpdate?: (deltaTime: number, alpha: number) => void;
7
+ render?: (alpha: number) => void;
8
8
  }
9
9
  export declare class GameLoop<FixedDeltaTime extends number> {
10
10
  private readonly fsm;
11
11
  private readonly fixedDeltaTime;
12
12
  private readonly maximumDeltaTime;
13
- private readonly update;
14
- private readonly fixedUpdate;
15
- private readonly lateUpdate;
16
- private readonly render;
13
+ private readonly update?;
14
+ private readonly fixedUpdate?;
15
+ private readonly lateUpdate?;
16
+ private readonly render?;
17
17
  private requstId?;
18
18
  private lastTimestamp?;
19
19
  private deltaTimeAccumulator;
package/lib/game-loop.js CHANGED
@@ -56,15 +56,16 @@ class GameLoop {
56
56
  }
57
57
  }
58
58
  nextFrame(deltaTime) {
59
+ var _a, _b, _c, _d;
59
60
  this.deltaTimeAccumulator = Math.min(this.deltaTimeAccumulator + deltaTime, this.maximumDeltaTime);
60
- this.update(deltaTime);
61
+ (_a = this.update) === null || _a === void 0 ? void 0 : _a.call(this, deltaTime);
61
62
  while (this.deltaTimeAccumulator >= this.fixedDeltaTime) {
62
- this.fixedUpdate(this.fixedDeltaTime);
63
+ (_b = this.fixedUpdate) === null || _b === void 0 ? void 0 : _b.call(this, this.fixedDeltaTime);
63
64
  this.deltaTimeAccumulator -= this.fixedDeltaTime;
64
65
  }
65
66
  const alpha = this.deltaTimeAccumulator / this.fixedDeltaTime;
66
- this.lateUpdate(deltaTime, alpha);
67
- this.render(alpha);
67
+ (_c = this.lateUpdate) === null || _c === void 0 ? void 0 : _c.call(this, deltaTime, alpha);
68
+ (_d = this.render) === null || _d === void 0 ? void 0 : _d.call(this, alpha);
68
69
  }
69
70
  }
70
71
  exports.GameLoop = GameLoop;
@@ -1 +1 @@
1
- {"version":3,"file":"game-loop.js","sourceRoot":"","sources":["../src/game-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-loop.js","sourceRoot":"","sources":["../src/game-loop.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './game-loop';
2
+ export * from './game-loop-lite';
package/lib/index.js CHANGED
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./game-loop"), exports);
18
+ __exportStar(require("./game-loop-lite"), exports);
18
19
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA2B;AAC3B,mDAAgC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "extra-game-loop",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
@@ -0,0 +1,88 @@
1
+ import { FiniteStateMachine, IFiniteStateMachineSchema } from 'extra-fsm'
2
+
3
+ interface IGameLoopLiteOptions {
4
+ /**
5
+ * 每帧运行一次, 总是最早运行.
6
+ */
7
+ update?: (deltaTime: number) => void
8
+
9
+ /**
10
+ * 每帧运行一次, 总是最晚运行.
11
+ */
12
+ render?: () => void
13
+ }
14
+
15
+ enum State {
16
+ Stopped = 'stopped'
17
+ , Running = 'running'
18
+ }
19
+
20
+ type Event =
21
+ | 'start'
22
+ | 'stop'
23
+
24
+ const schema: IFiniteStateMachineSchema<State, Event> = {
25
+ [State.Stopped]: { start: State.Running }
26
+ , [State.Running]: { stop: State.Stopped }
27
+ }
28
+
29
+ export class GameLoopLite {
30
+ private readonly fsm = new FiniteStateMachine(schema, State.Stopped)
31
+ private readonly update?: (deltaTime: number) => void
32
+ private readonly render?: () => void
33
+ private requstId?: number
34
+ private lastTimestamp?: number
35
+ private lastDeltaTime = 0
36
+
37
+ constructor(options: IGameLoopLiteOptions) {
38
+ this.update = options.update
39
+ this.render = options.render
40
+ }
41
+
42
+ start(): void {
43
+ this.fsm.send('start')
44
+
45
+ this.lastTimestamp = performance.now()
46
+ this.loop()
47
+ }
48
+
49
+ stop(): void {
50
+ this.fsm.send('stop')
51
+
52
+ cancelAnimationFrame(this.requstId!)
53
+
54
+ delete this.requstId
55
+ delete this.lastTimestamp
56
+ this.lastDeltaTime = 0
57
+ }
58
+
59
+ getFramesOfSecond(): number {
60
+ if (this.fsm.matches(State.Running)) {
61
+ return this.lastDeltaTime !== 0
62
+ ? 1000 / this.lastDeltaTime
63
+ : 0
64
+ } else {
65
+ return 0
66
+ }
67
+ }
68
+
69
+ private loop = (): void => {
70
+ // requestAnimationFrame的实现存在陷阱, 它提供的timestamp参数有时会比`performance.now()`早.
71
+ // 因此主动调用`performance.now()`来获取时间戳.
72
+ // https://stackoverflow.com/questions/50895206/exact-time-of-display-requestanimationframe-usage-and-timeline
73
+ const timestamp = performance.now()
74
+ const deltaTime = timestamp - this.lastTimestamp!
75
+ this.lastDeltaTime = deltaTime
76
+ this.lastTimestamp = timestamp
77
+
78
+ this.nextFrame(deltaTime)
79
+
80
+ this.requstId = requestAnimationFrame(this.loop)
81
+ }
82
+
83
+ nextFrame(deltaTime: number): void {
84
+ this.update?.(deltaTime)
85
+
86
+ this.render?.()
87
+ }
88
+ }
package/src/game-loop.ts CHANGED
@@ -15,28 +15,28 @@ interface IGameLoopOptions<FixedDeltaTime extends number = number> {
15
15
  maximumDeltaTime: number
16
16
 
17
17
  /**
18
- * 每帧运行一次, 运行早于fixedUpdate.
18
+ * 每帧运行一次, 总是最早运行.
19
19
  * 在此处理用户输入等与物理计算无关的操作, 在update里改变的状态直到下一物理帧时才会反应.
20
20
  */
21
- update: (deltaTime: number) => void
21
+ update?: (deltaTime: number) => void
22
22
 
23
23
  /**
24
24
  * 每物理帧运行一次, 运行晚于update, 早于lateUpdate.
25
25
  * deltaTime固定等于fixedDeltaTime.
26
26
  * 一帧中可能运行零次, 一次, 或数十次, 不应在此处理物理计算以外的繁重操作.
27
27
  */
28
- fixedUpdate: (deltaTime: FixedDeltaTime) => void
28
+ fixedUpdate?: (deltaTime: FixedDeltaTime) => void
29
29
 
30
30
  /**
31
31
  * 每帧运行一次, 运行晚于fixedUpdate, 能获得alpha.
32
32
  * 出于各种原因, 你可能会想使用它.
33
33
  */
34
- lateUpdate: (deltaTime: number, alpha: number) => void
34
+ lateUpdate?: (deltaTime: number, alpha: number) => void
35
35
 
36
36
  /**
37
- * 每帧运行一次, 总是运行在fixedUpdate和udpate之后.
37
+ * 每帧运行一次, 总是最晚运行.
38
38
  */
39
- render: (alpha: number) => void
39
+ render?: (alpha: number) => void
40
40
  }
41
41
 
42
42
  enum State {
@@ -57,10 +57,10 @@ export class GameLoop<FixedDeltaTime extends number> {
57
57
  private readonly fsm = new FiniteStateMachine(schema, State.Stopped)
58
58
  private readonly fixedDeltaTime: FixedDeltaTime
59
59
  private readonly maximumDeltaTime: number
60
- private readonly update: (deltaTime: number) => void
61
- private readonly fixedUpdate: (fixedDeltaTime: FixedDeltaTime) => void
62
- private readonly lateUpdate: (deltaTime: number, alpha: number) => void
63
- private readonly render: (alpha: number) => void
60
+ private readonly update?: (deltaTime: number) => void
61
+ private readonly fixedUpdate?: (fixedDeltaTime: FixedDeltaTime) => void
62
+ private readonly lateUpdate?: (deltaTime: number, alpha: number) => void
63
+ private readonly render?: (alpha: number) => void
64
64
  private requstId?: number
65
65
  private lastTimestamp?: number
66
66
  private deltaTimeAccumulator = 0
@@ -122,7 +122,7 @@ export class GameLoop<FixedDeltaTime extends number> {
122
122
  }
123
123
 
124
124
  /**
125
- * nextFrameUpdateFirst依序做以下几件事:
125
+ * nextFrame依序做以下几件事:
126
126
  * 1. 响应用户输入, 为这一帧的游戏世界做出非物理方面的更新, 例如角色转向, 改变武器瞄准角度等.
127
127
  * 2. 响应游戏世界从上一帧更新后到这一帧更新之前发生的物理变化.
128
128
  * 注意, 如果渲染帧率比物理帧率快, 且运行性能良好, 则物理帧不一定会在此帧更新.
@@ -134,15 +134,15 @@ export class GameLoop<FixedDeltaTime extends number> {
134
134
  , this.maximumDeltaTime
135
135
  )
136
136
 
137
- this.update(deltaTime)
137
+ this.update?.(deltaTime)
138
138
 
139
139
  while (this.deltaTimeAccumulator >= this.fixedDeltaTime) {
140
- this.fixedUpdate(this.fixedDeltaTime)
140
+ this.fixedUpdate?.(this.fixedDeltaTime)
141
141
  this.deltaTimeAccumulator -= this.fixedDeltaTime
142
142
  }
143
143
 
144
144
  const alpha = this.deltaTimeAccumulator / this.fixedDeltaTime
145
- this.lateUpdate(deltaTime, alpha)
146
- this.render(alpha)
145
+ this.lateUpdate?.(deltaTime, alpha)
146
+ this.render?.(alpha)
147
147
  }
148
148
  }
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './game-loop'
2
+ export * from './game-loop-lite'