mani-game-engine 1.0.0-pre.12 → 1.0.0-pre.15
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/LICENSE +21 -21
- package/README.md +69 -69
- package/lib/clock.d.ts +40 -40
- package/lib/clock.js +79 -79
- package/lib/ecsInjector.d.ts +26 -26
- package/lib/ecsInjector.js +139 -139
- package/lib/entity.d.ts +23 -21
- package/lib/entity.js +91 -85
- package/lib/entity.js.map +1 -1
- package/lib/gameEngine.d.ts +79 -79
- package/lib/gameEngine.js +327 -327
- package/lib/index.d.ts +12 -12
- package/lib/index.js +10 -10
- package/lib/scope/scopeContext.d.ts +54 -54
- package/lib/scope/scopeContext.js +244 -244
- package/lib/systemContext.d.ts +12 -12
- package/lib/systemContext.js +19 -19
- package/lib/types.d.ts +69 -69
- package/lib/types.js +11 -11
- package/lib/utils/map2k.d.ts +6 -6
- package/lib/utils/map2k.js +39 -39
- package/package.json +41 -41
- package/src/clock.ts +115 -115
- package/src/ecsInjector.ts +184 -184
- package/src/entity.ts +123 -116
- package/src/gameEngine.ts +424 -424
- package/src/index.ts +17 -17
- package/src/scope/scopeContext.ts +314 -314
- package/src/systemContext.ts +27 -27
- package/src/types.ts +84 -84
- package/src/utils/map2k.ts +52 -52
package/lib/gameEngine.js
CHANGED
|
@@ -1,328 +1,328 @@
|
|
|
1
|
-
import { EngineSignals } from './types';
|
|
2
|
-
import { putIfAbsent } from 'mani-injector';
|
|
3
|
-
import { EcsInjector, signalHandlers, staticSignalHandlers } from './ecsInjector';
|
|
4
|
-
import { GameClock } from './clock';
|
|
5
|
-
const defaultOptions = {
|
|
6
|
-
fixedDeltaTime: 1 / 60,
|
|
7
|
-
plugins: [],
|
|
8
|
-
};
|
|
9
|
-
export class GameEngine {
|
|
10
|
-
constructor(injector, clock) {
|
|
11
|
-
this.injector = injector;
|
|
12
|
-
this.clock = clock;
|
|
13
|
-
this.onEarlyUpdateSet = new Set();
|
|
14
|
-
this.onUpdateSet = new Set();
|
|
15
|
-
this.onFixedUpdateSet = new Set();
|
|
16
|
-
this.onPreFixedUpdateSet = new Set();
|
|
17
|
-
this.onPhysicsUpdateSet = new Set();
|
|
18
|
-
this.onPostPhysicsUpdateSet = new Set();
|
|
19
|
-
this.onLateFixedUpdateSet = new Set();
|
|
20
|
-
this.onLateUpdateSet = new Set();
|
|
21
|
-
this.onRenderUpdateSet = new Set();
|
|
22
|
-
this.entitySystemMap = new Map();
|
|
23
|
-
this.serviceClasses = new Set();
|
|
24
|
-
this.services = [];
|
|
25
|
-
this.resolveFrame = () => undefined;
|
|
26
|
-
this.addQueue = [];
|
|
27
|
-
this.removeQueue = [];
|
|
28
|
-
this._started = false;
|
|
29
|
-
this._frameCount = 0;
|
|
30
|
-
this._fixedFrameCount = 0;
|
|
31
|
-
this.signalMappings = new Map();
|
|
32
|
-
this.staticSignalMappings = new Map();
|
|
33
|
-
this.signalMapBindings = new Map();
|
|
34
|
-
this.injector.map(GameEngine).toValue(this);
|
|
35
|
-
this.onPrepare = this.injector.getSignal(EngineSignals.OnPrepare);
|
|
36
|
-
this.onStart = this.injector.getSignal(EngineSignals.OnStart);
|
|
37
|
-
this.onRender = this.injector.getSignal(EngineSignals.OnRender);
|
|
38
|
-
this.onFixedUpdate = this.injector.getSignal(EngineSignals.OnFixedUpdate);
|
|
39
|
-
this.onUpdate = this.injector.getSignal(EngineSignals.OnUpdate);
|
|
40
|
-
this.onLateUpdate = this.injector.getSignal(EngineSignals.OnLateUpdate);
|
|
41
|
-
this.onPrePhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysics);
|
|
42
|
-
this.onPostPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysics);
|
|
43
|
-
this.onLateFixedUpdate = this.injector.getSignal(EngineSignals.onLateFixedUpdate);
|
|
44
|
-
this.setupClock();
|
|
45
|
-
this.prepareFrame();
|
|
46
|
-
}
|
|
47
|
-
get started() { return this._started; }
|
|
48
|
-
get frameCount() { return this._frameCount; }
|
|
49
|
-
get fixedFrameCount() { return this._fixedFrameCount; }
|
|
50
|
-
get numEntities() { return this.entitySystemMap.size; }
|
|
51
|
-
static createDefault(options) {
|
|
52
|
-
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
53
|
-
const clock = new GameClock({
|
|
54
|
-
fixedDeltaTime: opts.fixedDeltaTime,
|
|
55
|
-
autoStart: false,
|
|
56
|
-
});
|
|
57
|
-
const injector = new EcsInjector();
|
|
58
|
-
const engine = new GameEngine(injector, clock);
|
|
59
|
-
engine.installPlugins(opts.plugins);
|
|
60
|
-
return engine;
|
|
61
|
-
}
|
|
62
|
-
static createDefaultWithInjector(injector, options) {
|
|
63
|
-
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
64
|
-
const clock = new GameClock({
|
|
65
|
-
fixedDeltaTime: opts.fixedDeltaTime,
|
|
66
|
-
autoStart: false,
|
|
67
|
-
});
|
|
68
|
-
const engine = new GameEngine(injector, clock);
|
|
69
|
-
engine.installPlugins(opts.plugins);
|
|
70
|
-
return engine;
|
|
71
|
-
}
|
|
72
|
-
addService(service) {
|
|
73
|
-
this.mapAnnotatedSignals(service);
|
|
74
|
-
service.onStart && service.onStart();
|
|
75
|
-
service.onPreFixedUpdate && this.onPreFixedUpdateSet.add(service);
|
|
76
|
-
service.onFixedUpdate && this.onFixedUpdateSet.add(service);
|
|
77
|
-
service.onUpdate && this.onUpdateSet.add(service);
|
|
78
|
-
service.onLateUpdate && this.onLateUpdateSet.add(service);
|
|
79
|
-
service.onPhysicsUpdate && this.onPhysicsUpdateSet.add(service);
|
|
80
|
-
service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(service);
|
|
81
|
-
service.onLateFixedUpdate && this.onLateFixedUpdateSet.add(service);
|
|
82
|
-
service.onRender && this.onRenderUpdateSet.add(service);
|
|
83
|
-
this.services.push(service);
|
|
84
|
-
}
|
|
85
|
-
installPlugins(plugins) {
|
|
86
|
-
plugins.forEach(plugin => {
|
|
87
|
-
plugin.onPrepare && plugin.onPrepare(this);
|
|
88
|
-
});
|
|
89
|
-
plugins.forEach(plugin => {
|
|
90
|
-
plugin.onStart && plugin.onStart(this);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
registerSystem(systemClass) {
|
|
94
|
-
this.mapStaticAnnotatedSignals(systemClass);
|
|
95
|
-
if (this._started)
|
|
96
|
-
throw new Error('Register Systems before engine is started');
|
|
97
|
-
this.injector.registerSystem(systemClass);
|
|
98
|
-
}
|
|
99
|
-
registerService(serviceClass) {
|
|
100
|
-
this.mapStaticAnnotatedSignals(serviceClass);
|
|
101
|
-
if (this._started)
|
|
102
|
-
throw new Error('Register Services before engine is started');
|
|
103
|
-
this.injector.map(serviceClass).toSingleton();
|
|
104
|
-
this.serviceClasses.add(serviceClass);
|
|
105
|
-
}
|
|
106
|
-
getService(serviceClass) {
|
|
107
|
-
return this.injector.get(serviceClass);
|
|
108
|
-
}
|
|
109
|
-
start() {
|
|
110
|
-
this._started = true;
|
|
111
|
-
for (const serviceClass of this.serviceClasses) {
|
|
112
|
-
const service = this.injector.get(serviceClass);
|
|
113
|
-
this.addService(service);
|
|
114
|
-
}
|
|
115
|
-
this.clock.start();
|
|
116
|
-
this.onStart.dispatch();
|
|
117
|
-
}
|
|
118
|
-
setupClock() {
|
|
119
|
-
this.clock.onPrepare.add(this.prepareFrame, this);
|
|
120
|
-
this.clock.onEarlyUpdate.add(({ time, deltaTime }) => {
|
|
121
|
-
for (const system of this.onEarlyUpdateSet) {
|
|
122
|
-
system.onEarlyUpdate(time, deltaTime);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
this.clock.onFixedUpdate.add((params) => {
|
|
126
|
-
const { time, deltaTime } = params;
|
|
127
|
-
for (const system of this.onPreFixedUpdateSet) {
|
|
128
|
-
system.onPreFixedUpdate(time, deltaTime);
|
|
129
|
-
}
|
|
130
|
-
for (const system of this.onFixedUpdateSet) {
|
|
131
|
-
system.onFixedUpdate(time, deltaTime);
|
|
132
|
-
}
|
|
133
|
-
this.onFixedUpdate.dispatch(params);
|
|
134
|
-
for (const system of this.onPhysicsUpdateSet) {
|
|
135
|
-
system.onPhysicsUpdate(time, deltaTime);
|
|
136
|
-
}
|
|
137
|
-
this.onPostPhysicsUpdate.dispatch(params);
|
|
138
|
-
for (const system of this.onPostPhysicsUpdateSet) {
|
|
139
|
-
system.onPostPhysicsUpdate(time, deltaTime);
|
|
140
|
-
}
|
|
141
|
-
this.onLateFixedUpdate.dispatch(params);
|
|
142
|
-
for (const system of this.onLateFixedUpdateSet) {
|
|
143
|
-
system.onLateFixedUpdate(time, deltaTime);
|
|
144
|
-
}
|
|
145
|
-
this._fixedFrameCount++;
|
|
146
|
-
});
|
|
147
|
-
this.clock.onUpdate.add(onUpdateParams => {
|
|
148
|
-
const { time, deltaTime, alpha } = onUpdateParams;
|
|
149
|
-
for (const system of this.onUpdateSet) {
|
|
150
|
-
system.onUpdate(time, deltaTime, alpha);
|
|
151
|
-
}
|
|
152
|
-
this.onUpdate.dispatch(onUpdateParams);
|
|
153
|
-
for (const system of this.onLateUpdateSet) {
|
|
154
|
-
system.onLateUpdate(time, deltaTime, alpha);
|
|
155
|
-
}
|
|
156
|
-
this.onLateUpdate.dispatch(onUpdateParams);
|
|
157
|
-
for (const system of this.onRenderUpdateSet) {
|
|
158
|
-
system.onRender(time, deltaTime, alpha);
|
|
159
|
-
}
|
|
160
|
-
this.onRender.dispatch(onUpdateParams);
|
|
161
|
-
this._frameCount++;
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
add(entity) {
|
|
165
|
-
return new Promise(resolve => this.addQueue.push([entity, resolve]));
|
|
166
|
-
}
|
|
167
|
-
waitFrame() {
|
|
168
|
-
return this.framePromise;
|
|
169
|
-
}
|
|
170
|
-
async remove(entity) {
|
|
171
|
-
if (entity.markRemoval)
|
|
172
|
-
return;
|
|
173
|
-
entity.markRemoval = true;
|
|
174
|
-
return new Promise(resolve => this.removeQueue.push([entity, resolve]));
|
|
175
|
-
}
|
|
176
|
-
stop() {
|
|
177
|
-
this.clock.stop();
|
|
178
|
-
}
|
|
179
|
-
runAction(action) {
|
|
180
|
-
return action(this);
|
|
181
|
-
}
|
|
182
|
-
getSignal(signalId) {
|
|
183
|
-
return this.injector.getSignal(signalId);
|
|
184
|
-
}
|
|
185
|
-
mapStaticAnnotatedSignals(target) {
|
|
186
|
-
let staticSignalMap = this.getStaticSignalMap(target);
|
|
187
|
-
if (staticSignalMap.length === 0)
|
|
188
|
-
return;
|
|
189
|
-
const bindings = [];
|
|
190
|
-
for (const [key, signal] of staticSignalMap) {
|
|
191
|
-
bindings.push(signal.add(target[key], target));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
mapAnnotatedSignals(target) {
|
|
195
|
-
const signalMap = this.getSignalMap(target.constructor);
|
|
196
|
-
if (signalMap.length === 0)
|
|
197
|
-
return;
|
|
198
|
-
const bindings = [];
|
|
199
|
-
for (const [key, signal] of signalMap) {
|
|
200
|
-
bindings.push(signal.add(target[key], target));
|
|
201
|
-
}
|
|
202
|
-
this.signalMapBindings.set(target, bindings);
|
|
203
|
-
}
|
|
204
|
-
unmapAnnotatedSignals(target) {
|
|
205
|
-
const signalBindings = this.signalMapBindings.get(target);
|
|
206
|
-
if (!signalBindings)
|
|
207
|
-
return;
|
|
208
|
-
for (const binding of signalBindings) {
|
|
209
|
-
binding.detach();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
getSignalMap(target) {
|
|
213
|
-
return putIfAbsent(this.signalMappings, target, () => {
|
|
214
|
-
const handlers = signalHandlers.get(target);
|
|
215
|
-
if (!handlers)
|
|
216
|
-
return [];
|
|
217
|
-
const result = [];
|
|
218
|
-
for (const [key, signalId] of handlers) {
|
|
219
|
-
result.push([key, this.getSignal(signalId)]);
|
|
220
|
-
}
|
|
221
|
-
return result;
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
getStaticSignalMap(target) {
|
|
225
|
-
return putIfAbsent(this.staticSignalMappings, target, () => {
|
|
226
|
-
const handlers = staticSignalHandlers.get(target);
|
|
227
|
-
if (!handlers)
|
|
228
|
-
return [];
|
|
229
|
-
const result = [];
|
|
230
|
-
for (const [key, signalId] of handlers) {
|
|
231
|
-
result.push([key, this.getSignal(signalId)]);
|
|
232
|
-
}
|
|
233
|
-
return result;
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
dispose() {
|
|
237
|
-
this.clock.stop();
|
|
238
|
-
for (const systems of this.entitySystemMap.values()) {
|
|
239
|
-
for (const system of systems) {
|
|
240
|
-
system.system.onEnd && system.system.onEnd();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
for (const service of this.services) {
|
|
244
|
-
service.onEnd && service.onEnd();
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
prepareFrame() {
|
|
248
|
-
for (const [entity, resolve] of this.removeQueue) {
|
|
249
|
-
const entities = entity.getAllEntities();
|
|
250
|
-
for (const entity of entities) {
|
|
251
|
-
entity.markRemoval = false;
|
|
252
|
-
if (!entity.gameEngine) {
|
|
253
|
-
console.log(entity);
|
|
254
|
-
}
|
|
255
|
-
entity.gameEngine = undefined;
|
|
256
|
-
const systemContexts = this.entitySystemMap.get(entity);
|
|
257
|
-
this.entitySystemMap.delete(entity);
|
|
258
|
-
if (systemContexts) {
|
|
259
|
-
for (const context of systemContexts) {
|
|
260
|
-
context.dispose();
|
|
261
|
-
const system = context.system;
|
|
262
|
-
this.unmapAnnotatedSignals(system);
|
|
263
|
-
system.onEnd && system.onEnd();
|
|
264
|
-
system.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(system);
|
|
265
|
-
system.onFixedUpdate && this.onFixedUpdateSet.delete(system);
|
|
266
|
-
system.onEarlyUpdate && this.onEarlyUpdateSet.delete(system);
|
|
267
|
-
system.onUpdate && this.onUpdateSet.delete(system);
|
|
268
|
-
system.onLateUpdate && this.onLateUpdateSet.delete(system);
|
|
269
|
-
system.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(system);
|
|
270
|
-
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(system);
|
|
271
|
-
system.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(system);
|
|
272
|
-
system.onRender && this.onRenderUpdateSet.delete(system);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
entity.onRemove.dispatch();
|
|
276
|
-
entity.onRemove.detachAll();
|
|
277
|
-
}
|
|
278
|
-
resolve();
|
|
279
|
-
}
|
|
280
|
-
this.removeQueue = [];
|
|
281
|
-
for (const [entity, resolve] of this.addQueue) {
|
|
282
|
-
const preparePromises = [];
|
|
283
|
-
const nexSystemContexts = [];
|
|
284
|
-
const entities = entity.getAllEntities();
|
|
285
|
-
for (const entity of entities) {
|
|
286
|
-
if (entity.gameEngine)
|
|
287
|
-
throw new Error('Entity already added to a gameEngine');
|
|
288
|
-
entity.gameEngine = this;
|
|
289
|
-
const systemContexts = this.injector.createSystems(entity);
|
|
290
|
-
for (const context of systemContexts) {
|
|
291
|
-
context.system.onPrepare && preparePromises.push(context.system.onPrepare());
|
|
292
|
-
nexSystemContexts.push(context);
|
|
293
|
-
}
|
|
294
|
-
this.entitySystemMap.set(entity, systemContexts);
|
|
295
|
-
}
|
|
296
|
-
const startSystems = () => {
|
|
297
|
-
for (const context of nexSystemContexts) {
|
|
298
|
-
const system = context.system;
|
|
299
|
-
this.mapAnnotatedSignals(system);
|
|
300
|
-
system.onStart && system.onStart();
|
|
301
|
-
system.onPreFixedUpdate && this.onPreFixedUpdateSet.add(system);
|
|
302
|
-
system.onFixedUpdate && this.onFixedUpdateSet.add(system);
|
|
303
|
-
system.onEarlyUpdate && this.onEarlyUpdateSet.add(system);
|
|
304
|
-
system.onUpdate && this.onUpdateSet.add(system);
|
|
305
|
-
system.onLateUpdate && this.onLateUpdateSet.add(system);
|
|
306
|
-
system.onPhysicsUpdate && this.onPhysicsUpdateSet.add(system);
|
|
307
|
-
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(system);
|
|
308
|
-
system.onLateFixedUpdate && this.onLateFixedUpdateSet.add(system);
|
|
309
|
-
system.onRender && this.onRenderUpdateSet.add(system);
|
|
310
|
-
}
|
|
311
|
-
resolve();
|
|
312
|
-
};
|
|
313
|
-
if (preparePromises.length === 0) {
|
|
314
|
-
startSystems();
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
Promise.all(preparePromises).then(startSystems);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
this.addQueue = [];
|
|
321
|
-
this.resolveFrame();
|
|
322
|
-
this.framePromise = new Promise(resolve => {
|
|
323
|
-
this.resolveFrame = resolve;
|
|
324
|
-
});
|
|
325
|
-
this.onPrepare.dispatch();
|
|
326
|
-
}
|
|
327
|
-
}
|
|
1
|
+
import { EngineSignals } from './types';
|
|
2
|
+
import { putIfAbsent } from 'mani-injector';
|
|
3
|
+
import { EcsInjector, signalHandlers, staticSignalHandlers } from './ecsInjector';
|
|
4
|
+
import { GameClock } from './clock';
|
|
5
|
+
const defaultOptions = {
|
|
6
|
+
fixedDeltaTime: 1 / 60,
|
|
7
|
+
plugins: [],
|
|
8
|
+
};
|
|
9
|
+
export class GameEngine {
|
|
10
|
+
constructor(injector, clock) {
|
|
11
|
+
this.injector = injector;
|
|
12
|
+
this.clock = clock;
|
|
13
|
+
this.onEarlyUpdateSet = new Set();
|
|
14
|
+
this.onUpdateSet = new Set();
|
|
15
|
+
this.onFixedUpdateSet = new Set();
|
|
16
|
+
this.onPreFixedUpdateSet = new Set();
|
|
17
|
+
this.onPhysicsUpdateSet = new Set();
|
|
18
|
+
this.onPostPhysicsUpdateSet = new Set();
|
|
19
|
+
this.onLateFixedUpdateSet = new Set();
|
|
20
|
+
this.onLateUpdateSet = new Set();
|
|
21
|
+
this.onRenderUpdateSet = new Set();
|
|
22
|
+
this.entitySystemMap = new Map();
|
|
23
|
+
this.serviceClasses = new Set();
|
|
24
|
+
this.services = [];
|
|
25
|
+
this.resolveFrame = () => undefined;
|
|
26
|
+
this.addQueue = [];
|
|
27
|
+
this.removeQueue = [];
|
|
28
|
+
this._started = false;
|
|
29
|
+
this._frameCount = 0;
|
|
30
|
+
this._fixedFrameCount = 0;
|
|
31
|
+
this.signalMappings = new Map();
|
|
32
|
+
this.staticSignalMappings = new Map();
|
|
33
|
+
this.signalMapBindings = new Map();
|
|
34
|
+
this.injector.map(GameEngine).toValue(this);
|
|
35
|
+
this.onPrepare = this.injector.getSignal(EngineSignals.OnPrepare);
|
|
36
|
+
this.onStart = this.injector.getSignal(EngineSignals.OnStart);
|
|
37
|
+
this.onRender = this.injector.getSignal(EngineSignals.OnRender);
|
|
38
|
+
this.onFixedUpdate = this.injector.getSignal(EngineSignals.OnFixedUpdate);
|
|
39
|
+
this.onUpdate = this.injector.getSignal(EngineSignals.OnUpdate);
|
|
40
|
+
this.onLateUpdate = this.injector.getSignal(EngineSignals.OnLateUpdate);
|
|
41
|
+
this.onPrePhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysics);
|
|
42
|
+
this.onPostPhysicsUpdate = this.injector.getSignal(EngineSignals.OnPostPhysics);
|
|
43
|
+
this.onLateFixedUpdate = this.injector.getSignal(EngineSignals.onLateFixedUpdate);
|
|
44
|
+
this.setupClock();
|
|
45
|
+
this.prepareFrame();
|
|
46
|
+
}
|
|
47
|
+
get started() { return this._started; }
|
|
48
|
+
get frameCount() { return this._frameCount; }
|
|
49
|
+
get fixedFrameCount() { return this._fixedFrameCount; }
|
|
50
|
+
get numEntities() { return this.entitySystemMap.size; }
|
|
51
|
+
static createDefault(options) {
|
|
52
|
+
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
53
|
+
const clock = new GameClock({
|
|
54
|
+
fixedDeltaTime: opts.fixedDeltaTime,
|
|
55
|
+
autoStart: false,
|
|
56
|
+
});
|
|
57
|
+
const injector = new EcsInjector();
|
|
58
|
+
const engine = new GameEngine(injector, clock);
|
|
59
|
+
engine.installPlugins(opts.plugins);
|
|
60
|
+
return engine;
|
|
61
|
+
}
|
|
62
|
+
static createDefaultWithInjector(injector, options) {
|
|
63
|
+
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
64
|
+
const clock = new GameClock({
|
|
65
|
+
fixedDeltaTime: opts.fixedDeltaTime,
|
|
66
|
+
autoStart: false,
|
|
67
|
+
});
|
|
68
|
+
const engine = new GameEngine(injector, clock);
|
|
69
|
+
engine.installPlugins(opts.plugins);
|
|
70
|
+
return engine;
|
|
71
|
+
}
|
|
72
|
+
addService(service) {
|
|
73
|
+
this.mapAnnotatedSignals(service);
|
|
74
|
+
service.onStart && service.onStart();
|
|
75
|
+
service.onPreFixedUpdate && this.onPreFixedUpdateSet.add(service);
|
|
76
|
+
service.onFixedUpdate && this.onFixedUpdateSet.add(service);
|
|
77
|
+
service.onUpdate && this.onUpdateSet.add(service);
|
|
78
|
+
service.onLateUpdate && this.onLateUpdateSet.add(service);
|
|
79
|
+
service.onPhysicsUpdate && this.onPhysicsUpdateSet.add(service);
|
|
80
|
+
service.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(service);
|
|
81
|
+
service.onLateFixedUpdate && this.onLateFixedUpdateSet.add(service);
|
|
82
|
+
service.onRender && this.onRenderUpdateSet.add(service);
|
|
83
|
+
this.services.push(service);
|
|
84
|
+
}
|
|
85
|
+
installPlugins(plugins) {
|
|
86
|
+
plugins.forEach(plugin => {
|
|
87
|
+
plugin.onPrepare && plugin.onPrepare(this);
|
|
88
|
+
});
|
|
89
|
+
plugins.forEach(plugin => {
|
|
90
|
+
plugin.onStart && plugin.onStart(this);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
registerSystem(systemClass) {
|
|
94
|
+
this.mapStaticAnnotatedSignals(systemClass);
|
|
95
|
+
if (this._started)
|
|
96
|
+
throw new Error('Register Systems before engine is started');
|
|
97
|
+
this.injector.registerSystem(systemClass);
|
|
98
|
+
}
|
|
99
|
+
registerService(serviceClass) {
|
|
100
|
+
this.mapStaticAnnotatedSignals(serviceClass);
|
|
101
|
+
if (this._started)
|
|
102
|
+
throw new Error('Register Services before engine is started');
|
|
103
|
+
this.injector.map(serviceClass).toSingleton();
|
|
104
|
+
this.serviceClasses.add(serviceClass);
|
|
105
|
+
}
|
|
106
|
+
getService(serviceClass) {
|
|
107
|
+
return this.injector.get(serviceClass);
|
|
108
|
+
}
|
|
109
|
+
start() {
|
|
110
|
+
this._started = true;
|
|
111
|
+
for (const serviceClass of this.serviceClasses) {
|
|
112
|
+
const service = this.injector.get(serviceClass);
|
|
113
|
+
this.addService(service);
|
|
114
|
+
}
|
|
115
|
+
this.clock.start();
|
|
116
|
+
this.onStart.dispatch();
|
|
117
|
+
}
|
|
118
|
+
setupClock() {
|
|
119
|
+
this.clock.onPrepare.add(this.prepareFrame, this);
|
|
120
|
+
this.clock.onEarlyUpdate.add(({ time, deltaTime }) => {
|
|
121
|
+
for (const system of this.onEarlyUpdateSet) {
|
|
122
|
+
system.onEarlyUpdate(time, deltaTime);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
this.clock.onFixedUpdate.add((params) => {
|
|
126
|
+
const { time, deltaTime } = params;
|
|
127
|
+
for (const system of this.onPreFixedUpdateSet) {
|
|
128
|
+
system.onPreFixedUpdate(time, deltaTime);
|
|
129
|
+
}
|
|
130
|
+
for (const system of this.onFixedUpdateSet) {
|
|
131
|
+
system.onFixedUpdate(time, deltaTime);
|
|
132
|
+
}
|
|
133
|
+
this.onFixedUpdate.dispatch(params);
|
|
134
|
+
for (const system of this.onPhysicsUpdateSet) {
|
|
135
|
+
system.onPhysicsUpdate(time, deltaTime);
|
|
136
|
+
}
|
|
137
|
+
this.onPostPhysicsUpdate.dispatch(params);
|
|
138
|
+
for (const system of this.onPostPhysicsUpdateSet) {
|
|
139
|
+
system.onPostPhysicsUpdate(time, deltaTime);
|
|
140
|
+
}
|
|
141
|
+
this.onLateFixedUpdate.dispatch(params);
|
|
142
|
+
for (const system of this.onLateFixedUpdateSet) {
|
|
143
|
+
system.onLateFixedUpdate(time, deltaTime);
|
|
144
|
+
}
|
|
145
|
+
this._fixedFrameCount++;
|
|
146
|
+
});
|
|
147
|
+
this.clock.onUpdate.add(onUpdateParams => {
|
|
148
|
+
const { time, deltaTime, alpha } = onUpdateParams;
|
|
149
|
+
for (const system of this.onUpdateSet) {
|
|
150
|
+
system.onUpdate(time, deltaTime, alpha);
|
|
151
|
+
}
|
|
152
|
+
this.onUpdate.dispatch(onUpdateParams);
|
|
153
|
+
for (const system of this.onLateUpdateSet) {
|
|
154
|
+
system.onLateUpdate(time, deltaTime, alpha);
|
|
155
|
+
}
|
|
156
|
+
this.onLateUpdate.dispatch(onUpdateParams);
|
|
157
|
+
for (const system of this.onRenderUpdateSet) {
|
|
158
|
+
system.onRender(time, deltaTime, alpha);
|
|
159
|
+
}
|
|
160
|
+
this.onRender.dispatch(onUpdateParams);
|
|
161
|
+
this._frameCount++;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
add(entity) {
|
|
165
|
+
return new Promise(resolve => this.addQueue.push([entity, resolve]));
|
|
166
|
+
}
|
|
167
|
+
waitFrame() {
|
|
168
|
+
return this.framePromise;
|
|
169
|
+
}
|
|
170
|
+
async remove(entity) {
|
|
171
|
+
if (entity.markRemoval)
|
|
172
|
+
return;
|
|
173
|
+
entity.markRemoval = true;
|
|
174
|
+
return new Promise(resolve => this.removeQueue.push([entity, resolve]));
|
|
175
|
+
}
|
|
176
|
+
stop() {
|
|
177
|
+
this.clock.stop();
|
|
178
|
+
}
|
|
179
|
+
runAction(action) {
|
|
180
|
+
return action(this);
|
|
181
|
+
}
|
|
182
|
+
getSignal(signalId) {
|
|
183
|
+
return this.injector.getSignal(signalId);
|
|
184
|
+
}
|
|
185
|
+
mapStaticAnnotatedSignals(target) {
|
|
186
|
+
let staticSignalMap = this.getStaticSignalMap(target);
|
|
187
|
+
if (staticSignalMap.length === 0)
|
|
188
|
+
return;
|
|
189
|
+
const bindings = [];
|
|
190
|
+
for (const [key, signal] of staticSignalMap) {
|
|
191
|
+
bindings.push(signal.add(target[key], target));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
mapAnnotatedSignals(target) {
|
|
195
|
+
const signalMap = this.getSignalMap(target.constructor);
|
|
196
|
+
if (signalMap.length === 0)
|
|
197
|
+
return;
|
|
198
|
+
const bindings = [];
|
|
199
|
+
for (const [key, signal] of signalMap) {
|
|
200
|
+
bindings.push(signal.add(target[key], target));
|
|
201
|
+
}
|
|
202
|
+
this.signalMapBindings.set(target, bindings);
|
|
203
|
+
}
|
|
204
|
+
unmapAnnotatedSignals(target) {
|
|
205
|
+
const signalBindings = this.signalMapBindings.get(target);
|
|
206
|
+
if (!signalBindings)
|
|
207
|
+
return;
|
|
208
|
+
for (const binding of signalBindings) {
|
|
209
|
+
binding.detach();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
getSignalMap(target) {
|
|
213
|
+
return putIfAbsent(this.signalMappings, target, () => {
|
|
214
|
+
const handlers = signalHandlers.get(target);
|
|
215
|
+
if (!handlers)
|
|
216
|
+
return [];
|
|
217
|
+
const result = [];
|
|
218
|
+
for (const [key, signalId] of handlers) {
|
|
219
|
+
result.push([key, this.getSignal(signalId)]);
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
getStaticSignalMap(target) {
|
|
225
|
+
return putIfAbsent(this.staticSignalMappings, target, () => {
|
|
226
|
+
const handlers = staticSignalHandlers.get(target);
|
|
227
|
+
if (!handlers)
|
|
228
|
+
return [];
|
|
229
|
+
const result = [];
|
|
230
|
+
for (const [key, signalId] of handlers) {
|
|
231
|
+
result.push([key, this.getSignal(signalId)]);
|
|
232
|
+
}
|
|
233
|
+
return result;
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
dispose() {
|
|
237
|
+
this.clock.stop();
|
|
238
|
+
for (const systems of this.entitySystemMap.values()) {
|
|
239
|
+
for (const system of systems) {
|
|
240
|
+
system.system.onEnd && system.system.onEnd();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
for (const service of this.services) {
|
|
244
|
+
service.onEnd && service.onEnd();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
prepareFrame() {
|
|
248
|
+
for (const [entity, resolve] of this.removeQueue) {
|
|
249
|
+
const entities = entity.getAllEntities();
|
|
250
|
+
for (const entity of entities) {
|
|
251
|
+
entity.markRemoval = false;
|
|
252
|
+
if (!entity.gameEngine) {
|
|
253
|
+
console.log(entity);
|
|
254
|
+
}
|
|
255
|
+
entity.gameEngine = undefined;
|
|
256
|
+
const systemContexts = this.entitySystemMap.get(entity);
|
|
257
|
+
this.entitySystemMap.delete(entity);
|
|
258
|
+
if (systemContexts) {
|
|
259
|
+
for (const context of systemContexts) {
|
|
260
|
+
context.dispose();
|
|
261
|
+
const system = context.system;
|
|
262
|
+
this.unmapAnnotatedSignals(system);
|
|
263
|
+
system.onEnd && system.onEnd();
|
|
264
|
+
system.onPreFixedUpdate && this.onPreFixedUpdateSet.delete(system);
|
|
265
|
+
system.onFixedUpdate && this.onFixedUpdateSet.delete(system);
|
|
266
|
+
system.onEarlyUpdate && this.onEarlyUpdateSet.delete(system);
|
|
267
|
+
system.onUpdate && this.onUpdateSet.delete(system);
|
|
268
|
+
system.onLateUpdate && this.onLateUpdateSet.delete(system);
|
|
269
|
+
system.onPhysicsUpdate && this.onPhysicsUpdateSet.delete(system);
|
|
270
|
+
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.delete(system);
|
|
271
|
+
system.onLateFixedUpdate && this.onLateFixedUpdateSet.delete(system);
|
|
272
|
+
system.onRender && this.onRenderUpdateSet.delete(system);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
entity.onRemove.dispatch();
|
|
276
|
+
entity.onRemove.detachAll();
|
|
277
|
+
}
|
|
278
|
+
resolve();
|
|
279
|
+
}
|
|
280
|
+
this.removeQueue = [];
|
|
281
|
+
for (const [entity, resolve] of this.addQueue) {
|
|
282
|
+
const preparePromises = [];
|
|
283
|
+
const nexSystemContexts = [];
|
|
284
|
+
const entities = entity.getAllEntities();
|
|
285
|
+
for (const entity of entities) {
|
|
286
|
+
if (entity.gameEngine)
|
|
287
|
+
throw new Error('Entity already added to a gameEngine');
|
|
288
|
+
entity.gameEngine = this;
|
|
289
|
+
const systemContexts = this.injector.createSystems(entity);
|
|
290
|
+
for (const context of systemContexts) {
|
|
291
|
+
context.system.onPrepare && preparePromises.push(context.system.onPrepare());
|
|
292
|
+
nexSystemContexts.push(context);
|
|
293
|
+
}
|
|
294
|
+
this.entitySystemMap.set(entity, systemContexts);
|
|
295
|
+
}
|
|
296
|
+
const startSystems = () => {
|
|
297
|
+
for (const context of nexSystemContexts) {
|
|
298
|
+
const system = context.system;
|
|
299
|
+
this.mapAnnotatedSignals(system);
|
|
300
|
+
system.onStart && system.onStart();
|
|
301
|
+
system.onPreFixedUpdate && this.onPreFixedUpdateSet.add(system);
|
|
302
|
+
system.onFixedUpdate && this.onFixedUpdateSet.add(system);
|
|
303
|
+
system.onEarlyUpdate && this.onEarlyUpdateSet.add(system);
|
|
304
|
+
system.onUpdate && this.onUpdateSet.add(system);
|
|
305
|
+
system.onLateUpdate && this.onLateUpdateSet.add(system);
|
|
306
|
+
system.onPhysicsUpdate && this.onPhysicsUpdateSet.add(system);
|
|
307
|
+
system.onPostPhysicsUpdate && this.onPostPhysicsUpdateSet.add(system);
|
|
308
|
+
system.onLateFixedUpdate && this.onLateFixedUpdateSet.add(system);
|
|
309
|
+
system.onRender && this.onRenderUpdateSet.add(system);
|
|
310
|
+
}
|
|
311
|
+
resolve();
|
|
312
|
+
};
|
|
313
|
+
if (preparePromises.length === 0) {
|
|
314
|
+
startSystems();
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
Promise.all(preparePromises).then(startSystems);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
this.addQueue = [];
|
|
321
|
+
this.resolveFrame();
|
|
322
|
+
this.framePromise = new Promise(resolve => {
|
|
323
|
+
this.resolveFrame = resolve;
|
|
324
|
+
});
|
|
325
|
+
this.onPrepare.dispatch();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
328
|
//# sourceMappingURL=gameEngine.js.map
|