mani-game-engine 1.0.0-pre.5 → 1.0.0-pre.51

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/src/clock.ts CHANGED
@@ -1,103 +1,163 @@
1
- import {Signal} from 'mani-signal';
2
- import {OnEarlyUpdateParams, OnFixedUpdateParams, OnUpdateParams} from './types';
3
-
4
- const MIN_TIME_SCALE = 0.00001;
5
-
6
- // type OnUpdateParams = { time: number, deltaTime: number, alpha: number; };
7
-
8
- const defaultOptions = {
9
- autoStart: true,
10
- fixedDeltaTime: 1 / 60,
11
- maxFrameTime: 0.25,
12
- timeScale: 1,
13
- };
14
-
15
- export type GameClockOptions = Partial<typeof defaultOptions>;
16
-
17
- export class Clock {
18
- private isRunning = false;
19
- private requestId = 0;
20
- private currentTime = 0;
21
- private accumulator = 0;
22
- private gameTime = 0;
23
-
24
- private _fixedDeltaTime: number;
25
- private update = (time: number) => {
26
- const newTime = time * 0.001;
27
- if (!this.isRunning) {
28
- this.currentTime = newTime;
29
- this.isRunning = true;
30
- }
31
-
32
- let frameTime = (newTime - this.currentTime) * this.timeScale;
33
-
34
- if (frameTime > this.maxFrameTime) {
35
- frameTime = this.maxFrameTime;
36
- }
37
-
38
- this.currentTime = newTime;
39
- this.accumulator += frameTime;
40
- let isMultipleFixedUpdate = false;
41
-
42
- this.onPrepare.dispatch();
43
- this.onEarlyUpdate.dispatch({time: this.gameTime, deltaTime: frameTime});
44
- while (this.accumulator >= this._fixedDeltaTime) {
45
- if (isMultipleFixedUpdate) {
46
- this.onPrepare.dispatch();
47
- }
48
- this.onFixedUpdate.dispatch({time: this.gameTime, deltaTime: this._fixedDeltaTime});
49
- isMultipleFixedUpdate = true;
50
- this.accumulator -= this._fixedDeltaTime;
51
- this.gameTime += this._fixedDeltaTime;
52
- }
53
- const alpha = this.accumulator / this._fixedDeltaTime;
54
- this.onUpdate.dispatch({time: this.gameTime + alpha * this._fixedDeltaTime, deltaTime: frameTime, alpha: alpha});
55
- if (this.isRunning) {
56
- this.requestId = requestAnimationFrame(this.update);
57
- }
58
- };
59
-
60
- private maxFrameTime: number;
61
-
62
- readonly onPrepare = new Signal();
63
- readonly onEarlyUpdate = new Signal<OnEarlyUpdateParams>();
64
- readonly onUpdate = new Signal<OnUpdateParams>();
65
- readonly onFixedUpdate = new Signal<OnFixedUpdateParams>();
66
-
67
- constructor(options?: GameClockOptions) {
68
- const opts = {...defaultOptions, ...options} as Required<GameClockOptions>;
69
- this._fixedDeltaTime = opts.fixedDeltaTime;
70
- this.maxFrameTime = opts.maxFrameTime;
71
- this.timeScale = opts.timeScale;
72
-
73
- opts.autoStart && this.start();
74
- }
75
-
76
- get fixedDeltaTime(): number { return this._fixedDeltaTime; }
77
-
78
- private _timeScale = 1;
79
-
80
- get timeScale(): number {
81
- return this._timeScale;
82
- }
83
-
84
- set timeScale(value: number) {
85
- this._timeScale = Math.max(value, MIN_TIME_SCALE);
86
- }
87
-
88
- start(): this {
89
- if (this.isRunning) {
90
- return this;
91
- }
92
- this.requestId = requestAnimationFrame(this.update);
93
- return this;
94
- }
95
-
96
- stop() {
97
- if (!this.isRunning) {
98
- return;
99
- }
100
- this.isRunning = false;
101
- cancelAnimationFrame(this.requestId);
102
- }
103
- }
1
+ import {Signal} from 'mani-signal';
2
+ import {OnEarlyUpdateParams, OnFixedUpdateParams, OnUpdateParams} from './types';
3
+
4
+ const MIN_TIME_SCALE = 0.00001;
5
+
6
+ // type OnUpdateParams = { time: number, deltaTime: number, alpha: number; };
7
+
8
+ const defaultOptions = {
9
+ autoStart: true,
10
+ fixedDeltaTime: 1 / 60,
11
+ maxFrameTime: 0.25,
12
+ timeScale: 1,
13
+ };
14
+
15
+ export type Timeout = {
16
+ recall?: number;
17
+ callback: Function;
18
+ callTime: number;
19
+ };
20
+ export type GameClockOptions = Partial<typeof defaultOptions>;
21
+
22
+ export interface Clock {
23
+
24
+ onPrepare: Signal<unknown>;
25
+ onEarlyUpdate: Signal<OnEarlyUpdateParams>;
26
+ onUpdate: Signal<OnUpdateParams>;
27
+ onFixedUpdate: Signal<OnFixedUpdateParams>;
28
+ timeScale: number;
29
+ start(): this;
30
+ stop(): this;
31
+ dispose(): void;
32
+ setTimeout(callback: Function, delay: number): number;
33
+ setInterval(callback: Function, delay: number): number;
34
+ clearTimeout(timeoutId: number): boolean;
35
+ }
36
+
37
+ export class GameClock implements Clock {
38
+ private nextTimeoutId = 0;
39
+ private timeouts = new Map<number, Timeout>();
40
+ private isRunning = false;
41
+ private requestId = 0;
42
+ private currentTime = 0;
43
+ private accumulator = 0;
44
+ private gameTime = 0;
45
+
46
+ private readonly _fixedDeltaTime: number;
47
+ private update = (time: number) => {
48
+ const newTime = time * 0.001;
49
+ if (!this.isRunning) {
50
+ this.currentTime = newTime;
51
+ this.isRunning = true;
52
+ }
53
+
54
+ let frameTime = (newTime - this.currentTime) * this.timeScale;
55
+
56
+ if (frameTime > this.maxFrameTime) {
57
+ frameTime = this.maxFrameTime;
58
+ }
59
+
60
+ this.currentTime = newTime;
61
+ this.accumulator += frameTime;
62
+ let isMultipleFixedUpdate = false;
63
+
64
+ this.onPrepare.dispatch();
65
+ this.onEarlyUpdate.dispatch({time: this.gameTime, deltaTime: frameTime});
66
+
67
+ for (const [id, timeOut] of this.timeouts) {
68
+ if (this.gameTime >= timeOut.callTime) {
69
+ timeOut.callback();
70
+ if (timeOut.recall) {
71
+ timeOut.callTime += timeOut.recall;
72
+ } else {
73
+ this.timeouts.delete(id);
74
+ }
75
+ }
76
+ }
77
+
78
+ while (this.accumulator >= this._fixedDeltaTime) {
79
+ if (isMultipleFixedUpdate) {
80
+ this.onPrepare.dispatch();
81
+ }
82
+ this.onFixedUpdate.dispatch({time: this.gameTime, deltaTime: this._fixedDeltaTime});
83
+ isMultipleFixedUpdate = true;
84
+ this.accumulator -= this._fixedDeltaTime;
85
+ this.gameTime += this._fixedDeltaTime;
86
+ }
87
+ const alpha = this.accumulator / this._fixedDeltaTime;
88
+ this.onUpdate.dispatch({time: this.gameTime + alpha * this._fixedDeltaTime, deltaTime: frameTime, alpha: alpha});
89
+ if (this.isRunning) {
90
+ this.requestId = requestAnimationFrame(this.update);
91
+ }
92
+ };
93
+
94
+ private readonly maxFrameTime: number;
95
+
96
+ readonly onPrepare = new Signal();
97
+ readonly onEarlyUpdate = new Signal<OnEarlyUpdateParams>();
98
+ readonly onUpdate = new Signal<OnUpdateParams>();
99
+ readonly onFixedUpdate = new Signal<OnFixedUpdateParams>();
100
+
101
+ constructor(options?: GameClockOptions) {
102
+ const opts = {...defaultOptions, ...options} as Required<GameClockOptions>;
103
+ this._fixedDeltaTime = opts.fixedDeltaTime;
104
+ this.maxFrameTime = opts.maxFrameTime;
105
+ this.timeScale = opts.timeScale;
106
+
107
+ opts.autoStart && this.start();
108
+ }
109
+
110
+ dispose(): void {
111
+ this.onPrepare.detachAll();
112
+ this.onEarlyUpdate.detachAll();
113
+ this.onUpdate.detachAll();
114
+ this.onFixedUpdate.detachAll();
115
+ }
116
+
117
+ get fixedDeltaTime(): number { return this._fixedDeltaTime; }
118
+
119
+ private _timeScale = 1;
120
+
121
+ get timeScale(): number {
122
+ return this._timeScale;
123
+ }
124
+
125
+ set timeScale(value: number) {
126
+ this._timeScale = Math.max(value, MIN_TIME_SCALE);
127
+ }
128
+
129
+ start(): this {
130
+ if (this.isRunning) {
131
+ return this;
132
+ }
133
+ this.requestId = requestAnimationFrame(this.update);
134
+ return this;
135
+ }
136
+
137
+ stop(): this {
138
+ if (!this.isRunning) {
139
+ return this;
140
+ }
141
+ this.isRunning = false;
142
+ cancelAnimationFrame(this.requestId);
143
+ return this;
144
+ }
145
+
146
+ setTimeout(callback: Function, delay: number) {
147
+ const timeOut: Timeout = {callback, callTime: this.gameTime + delay};
148
+ this.nextTimeoutId++;
149
+ this.timeouts.set(this.nextTimeoutId, timeOut);
150
+ return this.nextTimeoutId;
151
+ }
152
+
153
+ setInterval(callback: Function, delay: number) {
154
+ const timeOut: Timeout = {callback, callTime: this.gameTime + delay, recall: delay};
155
+ this.nextTimeoutId++;
156
+ this.timeouts.set(this.nextTimeoutId, timeOut);
157
+ return this.nextTimeoutId;
158
+ }
159
+
160
+ clearTimeout(timeoutId: number) {
161
+ return this.timeouts.delete(timeoutId);
162
+ }
163
+ }