@zylem/game-lib 0.5.1 → 0.6.0
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 -0
- package/dist/behaviors.d.ts +1 -3
- package/dist/behaviors.js.map +1 -1
- package/dist/blueprints-BOCc3Wve.d.ts +26 -0
- package/dist/{camera-Dk-fOVZE.d.ts → camera-CpbDr4-V.d.ts} +19 -45
- package/dist/camera.d.ts +2 -2
- package/dist/camera.js +217 -113
- package/dist/camera.js.map +1 -1
- package/dist/{core-C2mjetAd.d.ts → core-CZhozNRH.d.ts} +77 -42
- package/dist/core.d.ts +6 -5
- package/dist/core.js +1676 -695
- package/dist/core.js.map +1 -1
- package/dist/entities-BAxfJOkk.d.ts +307 -0
- package/dist/entities.d.ts +4 -267
- package/dist/entities.js +213 -90
- package/dist/entities.js.map +1 -1
- package/dist/entity-Bq_eNEDI.d.ts +28 -0
- package/dist/{entity-bQElAdpo.d.ts → entity-COvRtFNG.d.ts} +68 -20
- package/dist/main.d.ts +88 -12
- package/dist/main.js +1811 -810
- package/dist/main.js.map +1 -1
- package/dist/{stage-CrmY7V0i.d.ts → stage-types-CD21XoIU.d.ts} +90 -39
- package/dist/stage.d.ts +40 -20
- package/dist/stage.js +1210 -674
- package/dist/stage.js.map +1 -1
- package/package.json +10 -10
- package/dist/entity-spawner-DNnLYnZq.d.ts +0 -11
package/dist/main.js
CHANGED
|
@@ -40,10 +40,64 @@ var init_path_utils = __esm({
|
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// src/lib/game/game-event-bus.ts
|
|
44
|
+
var GameEventBus, gameEventBus;
|
|
45
|
+
var init_game_event_bus = __esm({
|
|
46
|
+
"src/lib/game/game-event-bus.ts"() {
|
|
47
|
+
"use strict";
|
|
48
|
+
GameEventBus = class {
|
|
49
|
+
listeners = /* @__PURE__ */ new Map();
|
|
50
|
+
/**
|
|
51
|
+
* Subscribe to an event type.
|
|
52
|
+
*/
|
|
53
|
+
on(event, callback) {
|
|
54
|
+
if (!this.listeners.has(event)) {
|
|
55
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
56
|
+
}
|
|
57
|
+
this.listeners.get(event).add(callback);
|
|
58
|
+
return () => this.off(event, callback);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Unsubscribe from an event type.
|
|
62
|
+
*/
|
|
63
|
+
off(event, callback) {
|
|
64
|
+
this.listeners.get(event)?.delete(callback);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Emit an event to all subscribers.
|
|
68
|
+
*/
|
|
69
|
+
emit(event, payload) {
|
|
70
|
+
const callbacks = this.listeners.get(event);
|
|
71
|
+
if (!callbacks) return;
|
|
72
|
+
for (const cb of callbacks) {
|
|
73
|
+
try {
|
|
74
|
+
cb(payload);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error(`Error in event handler for ${event}`, e);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Clear all listeners.
|
|
82
|
+
*/
|
|
83
|
+
dispose() {
|
|
84
|
+
this.listeners.clear();
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
gameEventBus = new GameEventBus();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
43
91
|
// src/lib/game/game-state.ts
|
|
44
92
|
import { proxy, subscribe } from "valtio/vanilla";
|
|
45
93
|
function setGlobal(path, value) {
|
|
94
|
+
const previousValue = getByPath(state.globals, path);
|
|
46
95
|
setByPath(state.globals, path, value);
|
|
96
|
+
gameEventBus.emit("game:state:updated", {
|
|
97
|
+
path,
|
|
98
|
+
value,
|
|
99
|
+
previousValue
|
|
100
|
+
});
|
|
47
101
|
}
|
|
48
102
|
function createGlobal(path, defaultValue) {
|
|
49
103
|
const existing = getByPath(state.globals, path);
|
|
@@ -58,17 +112,22 @@ function getGlobal(path) {
|
|
|
58
112
|
}
|
|
59
113
|
function onGlobalChange(path, callback) {
|
|
60
114
|
let previous = getByPath(state.globals, path);
|
|
61
|
-
|
|
115
|
+
const unsub = subscribe(state.globals, () => {
|
|
62
116
|
const current = getByPath(state.globals, path);
|
|
63
117
|
if (current !== previous) {
|
|
64
118
|
previous = current;
|
|
65
119
|
callback(current);
|
|
66
120
|
}
|
|
67
121
|
});
|
|
122
|
+
activeSubscriptions.add(unsub);
|
|
123
|
+
return () => {
|
|
124
|
+
unsub();
|
|
125
|
+
activeSubscriptions.delete(unsub);
|
|
126
|
+
};
|
|
68
127
|
}
|
|
69
128
|
function onGlobalChanges(paths, callback) {
|
|
70
129
|
let previousValues = paths.map((p) => getByPath(state.globals, p));
|
|
71
|
-
|
|
130
|
+
const unsub = subscribe(state.globals, () => {
|
|
72
131
|
const currentValues = paths.map((p) => getByPath(state.globals, p));
|
|
73
132
|
const hasChange = currentValues.some((val, i) => val !== previousValues[i]);
|
|
74
133
|
if (hasChange) {
|
|
@@ -76,6 +135,11 @@ function onGlobalChanges(paths, callback) {
|
|
|
76
135
|
callback(currentValues);
|
|
77
136
|
}
|
|
78
137
|
});
|
|
138
|
+
activeSubscriptions.add(unsub);
|
|
139
|
+
return () => {
|
|
140
|
+
unsub();
|
|
141
|
+
activeSubscriptions.delete(unsub);
|
|
142
|
+
};
|
|
79
143
|
}
|
|
80
144
|
function getGlobals() {
|
|
81
145
|
return state.globals;
|
|
@@ -88,16 +152,24 @@ function initGlobals(globals) {
|
|
|
88
152
|
function resetGlobals() {
|
|
89
153
|
state.globals = {};
|
|
90
154
|
}
|
|
91
|
-
|
|
155
|
+
function clearGlobalSubscriptions() {
|
|
156
|
+
for (const unsub of activeSubscriptions) {
|
|
157
|
+
unsub();
|
|
158
|
+
}
|
|
159
|
+
activeSubscriptions.clear();
|
|
160
|
+
}
|
|
161
|
+
var state, activeSubscriptions;
|
|
92
162
|
var init_game_state = __esm({
|
|
93
163
|
"src/lib/game/game-state.ts"() {
|
|
94
164
|
"use strict";
|
|
95
165
|
init_path_utils();
|
|
166
|
+
init_game_event_bus();
|
|
96
167
|
state = proxy({
|
|
97
168
|
id: "",
|
|
98
169
|
globals: {},
|
|
99
170
|
time: 0
|
|
100
171
|
});
|
|
172
|
+
activeSubscriptions = /* @__PURE__ */ new Set();
|
|
101
173
|
}
|
|
102
174
|
});
|
|
103
175
|
|
|
@@ -112,6 +184,9 @@ function setPaused(paused) {
|
|
|
112
184
|
function getDebugTool() {
|
|
113
185
|
return debugState.tool;
|
|
114
186
|
}
|
|
187
|
+
function setDebugTool(tool) {
|
|
188
|
+
debugState.tool = tool;
|
|
189
|
+
}
|
|
115
190
|
function setSelectedEntity(entity) {
|
|
116
191
|
debugState.selectedEntity = entity;
|
|
117
192
|
}
|
|
@@ -163,21 +238,76 @@ var init_base_node = __esm({
|
|
|
163
238
|
uuid = "";
|
|
164
239
|
name = "";
|
|
165
240
|
markedForRemoval = false;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Lifecycle callback arrays - use onSetup(), onUpdate(), etc. to add callbacks
|
|
243
|
+
*/
|
|
244
|
+
lifecycleCallbacks = {
|
|
245
|
+
setup: [],
|
|
246
|
+
loaded: [],
|
|
247
|
+
update: [],
|
|
248
|
+
destroy: [],
|
|
249
|
+
cleanup: []
|
|
175
250
|
};
|
|
176
251
|
constructor(args = []) {
|
|
177
252
|
const options = args.filter((arg) => !(arg instanceof _BaseNode)).reduce((acc, opt) => ({ ...acc, ...opt }), {});
|
|
178
253
|
this.options = options;
|
|
179
254
|
this.uuid = nanoid();
|
|
180
255
|
}
|
|
256
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
257
|
+
// Fluent API for adding lifecycle callbacks
|
|
258
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
259
|
+
/**
|
|
260
|
+
* Add setup callbacks to be executed in order during nodeSetup
|
|
261
|
+
*/
|
|
262
|
+
onSetup(...callbacks) {
|
|
263
|
+
this.lifecycleCallbacks.setup.push(...callbacks);
|
|
264
|
+
return this;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Add loaded callbacks to be executed in order during nodeLoaded
|
|
268
|
+
*/
|
|
269
|
+
onLoaded(...callbacks) {
|
|
270
|
+
this.lifecycleCallbacks.loaded.push(...callbacks);
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Add update callbacks to be executed in order during nodeUpdate
|
|
275
|
+
*/
|
|
276
|
+
onUpdate(...callbacks) {
|
|
277
|
+
this.lifecycleCallbacks.update.push(...callbacks);
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Add destroy callbacks to be executed in order during nodeDestroy
|
|
282
|
+
*/
|
|
283
|
+
onDestroy(...callbacks) {
|
|
284
|
+
this.lifecycleCallbacks.destroy.push(...callbacks);
|
|
285
|
+
return this;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Add cleanup callbacks to be executed in order during nodeCleanup
|
|
289
|
+
*/
|
|
290
|
+
onCleanup(...callbacks) {
|
|
291
|
+
this.lifecycleCallbacks.cleanup.push(...callbacks);
|
|
292
|
+
return this;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Prepend setup callbacks (run before existing ones)
|
|
296
|
+
*/
|
|
297
|
+
prependSetup(...callbacks) {
|
|
298
|
+
this.lifecycleCallbacks.setup.unshift(...callbacks);
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Prepend update callbacks (run before existing ones)
|
|
303
|
+
*/
|
|
304
|
+
prependUpdate(...callbacks) {
|
|
305
|
+
this.lifecycleCallbacks.update.unshift(...callbacks);
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
309
|
+
// Tree structure
|
|
310
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
181
311
|
setParent(parent) {
|
|
182
312
|
this.parent = parent;
|
|
183
313
|
}
|
|
@@ -201,6 +331,9 @@ var init_base_node = __esm({
|
|
|
201
331
|
isComposite() {
|
|
202
332
|
return this.children.length > 0;
|
|
203
333
|
}
|
|
334
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
335
|
+
// Node lifecycle execution - runs internal + callback arrays
|
|
336
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
204
337
|
nodeSetup(params) {
|
|
205
338
|
if (DEBUG_FLAG) {
|
|
206
339
|
}
|
|
@@ -208,8 +341,8 @@ var init_base_node = __esm({
|
|
|
208
341
|
if (typeof this._setup === "function") {
|
|
209
342
|
this._setup(params);
|
|
210
343
|
}
|
|
211
|
-
|
|
212
|
-
|
|
344
|
+
for (const callback of this.lifecycleCallbacks.setup) {
|
|
345
|
+
callback(params);
|
|
213
346
|
}
|
|
214
347
|
this.children.forEach((child) => child.nodeSetup(params));
|
|
215
348
|
}
|
|
@@ -220,21 +353,40 @@ var init_base_node = __esm({
|
|
|
220
353
|
if (typeof this._update === "function") {
|
|
221
354
|
this._update(params);
|
|
222
355
|
}
|
|
223
|
-
|
|
224
|
-
|
|
356
|
+
for (const callback of this.lifecycleCallbacks.update) {
|
|
357
|
+
callback(params);
|
|
225
358
|
}
|
|
226
359
|
this.children.forEach((child) => child.nodeUpdate(params));
|
|
227
360
|
}
|
|
228
361
|
nodeDestroy(params) {
|
|
229
362
|
this.children.forEach((child) => child.nodeDestroy(params));
|
|
230
|
-
|
|
231
|
-
|
|
363
|
+
for (const callback of this.lifecycleCallbacks.destroy) {
|
|
364
|
+
callback(params);
|
|
232
365
|
}
|
|
233
366
|
if (typeof this._destroy === "function") {
|
|
234
367
|
this._destroy(params);
|
|
235
368
|
}
|
|
236
369
|
this.markedForRemoval = true;
|
|
237
370
|
}
|
|
371
|
+
async nodeLoaded(params) {
|
|
372
|
+
if (typeof this._loaded === "function") {
|
|
373
|
+
await this._loaded(params);
|
|
374
|
+
}
|
|
375
|
+
for (const callback of this.lifecycleCallbacks.loaded) {
|
|
376
|
+
callback(params);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async nodeCleanup(params) {
|
|
380
|
+
for (const callback of this.lifecycleCallbacks.cleanup) {
|
|
381
|
+
callback(params);
|
|
382
|
+
}
|
|
383
|
+
if (typeof this._cleanup === "function") {
|
|
384
|
+
await this._cleanup(params);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
388
|
+
// Options
|
|
389
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
238
390
|
getOptions() {
|
|
239
391
|
return this.options;
|
|
240
392
|
}
|
|
@@ -250,57 +402,54 @@ import {
|
|
|
250
402
|
defineSystem,
|
|
251
403
|
defineQuery,
|
|
252
404
|
defineComponent,
|
|
253
|
-
Types
|
|
405
|
+
Types,
|
|
406
|
+
removeQuery
|
|
254
407
|
} from "bitecs";
|
|
255
408
|
import { Quaternion } from "three";
|
|
256
409
|
function createTransformSystem(stage) {
|
|
257
|
-
const
|
|
410
|
+
const queryTerms = [position, rotation];
|
|
411
|
+
const transformQuery = defineQuery(queryTerms);
|
|
258
412
|
const stageEntities = stage._childrenMap;
|
|
259
|
-
|
|
413
|
+
const system = defineSystem((world) => {
|
|
260
414
|
const entities = transformQuery(world);
|
|
261
415
|
if (stageEntities === void 0) {
|
|
262
416
|
return world;
|
|
263
417
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const id = entities[key];
|
|
267
|
-
const stageEntity = value;
|
|
268
|
-
if (stageEntity === void 0 || !stageEntity?.body || stageEntity.markedForRemoval) {
|
|
418
|
+
for (const [key, stageEntity] of stageEntities) {
|
|
419
|
+
if (!stageEntity?.body || stageEntity.markedForRemoval) {
|
|
269
420
|
continue;
|
|
270
421
|
}
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
422
|
+
const id = entities[key];
|
|
423
|
+
const body = stageEntity.body;
|
|
424
|
+
const target = stageEntity.group ?? stageEntity.mesh;
|
|
425
|
+
const translation = body.translation();
|
|
426
|
+
position.x[id] = translation.x;
|
|
427
|
+
position.y[id] = translation.y;
|
|
428
|
+
position.z[id] = translation.z;
|
|
429
|
+
if (target) {
|
|
430
|
+
target.position.set(translation.x, translation.y, translation.z);
|
|
279
431
|
}
|
|
280
432
|
if (stageEntity.controlledRotation) {
|
|
281
433
|
continue;
|
|
282
434
|
}
|
|
283
|
-
const
|
|
284
|
-
rotation.x[id] =
|
|
285
|
-
rotation.y[id] =
|
|
286
|
-
rotation.z[id] =
|
|
287
|
-
rotation.w[id] =
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
rotation.z[id],
|
|
292
|
-
rotation.w[id]
|
|
293
|
-
);
|
|
294
|
-
if (stageEntity.group) {
|
|
295
|
-
stageEntity.group.setRotationFromQuaternion(newRotation);
|
|
296
|
-
} else if (stageEntity.mesh) {
|
|
297
|
-
stageEntity.mesh.setRotationFromQuaternion(newRotation);
|
|
435
|
+
const rot = body.rotation();
|
|
436
|
+
rotation.x[id] = rot.x;
|
|
437
|
+
rotation.y[id] = rot.y;
|
|
438
|
+
rotation.z[id] = rot.z;
|
|
439
|
+
rotation.w[id] = rot.w;
|
|
440
|
+
if (target) {
|
|
441
|
+
_tempQuaternion.set(rot.x, rot.y, rot.z, rot.w);
|
|
442
|
+
target.setRotationFromQuaternion(_tempQuaternion);
|
|
298
443
|
}
|
|
299
444
|
}
|
|
300
445
|
return world;
|
|
301
446
|
});
|
|
447
|
+
const destroy2 = (world) => {
|
|
448
|
+
removeQuery(world, transformQuery);
|
|
449
|
+
};
|
|
450
|
+
return { system, destroy: destroy2 };
|
|
302
451
|
}
|
|
303
|
-
var position, rotation, scale;
|
|
452
|
+
var position, rotation, scale, _tempQuaternion;
|
|
304
453
|
var init_transformable_system = __esm({
|
|
305
454
|
"src/lib/systems/transformable.system.ts"() {
|
|
306
455
|
"use strict";
|
|
@@ -320,6 +469,7 @@ var init_transformable_system = __esm({
|
|
|
320
469
|
y: Types.f32,
|
|
321
470
|
z: Types.f32
|
|
322
471
|
});
|
|
472
|
+
_tempQuaternion = new Quaternion();
|
|
323
473
|
}
|
|
324
474
|
});
|
|
325
475
|
|
|
@@ -343,11 +493,6 @@ var init_entity = __esm({
|
|
|
343
493
|
custom = {};
|
|
344
494
|
debugInfo = {};
|
|
345
495
|
debugMaterial;
|
|
346
|
-
lifeCycleDelegate = {
|
|
347
|
-
setup: [],
|
|
348
|
-
update: [],
|
|
349
|
-
destroy: []
|
|
350
|
-
};
|
|
351
496
|
collisionDelegate = {
|
|
352
497
|
collision: []
|
|
353
498
|
};
|
|
@@ -372,67 +517,40 @@ var init_entity = __esm({
|
|
|
372
517
|
this.name = this.options.name || "";
|
|
373
518
|
return this;
|
|
374
519
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
...this.lifeCycleDelegate,
|
|
379
|
-
setup: combineCallbacks
|
|
380
|
-
};
|
|
381
|
-
return this;
|
|
382
|
-
}
|
|
383
|
-
onUpdate(...callbacks) {
|
|
384
|
-
const combineCallbacks = [...this.lifeCycleDelegate.update ?? [], ...callbacks];
|
|
385
|
-
this.lifeCycleDelegate = {
|
|
386
|
-
...this.lifeCycleDelegate,
|
|
387
|
-
update: combineCallbacks
|
|
388
|
-
};
|
|
389
|
-
return this;
|
|
390
|
-
}
|
|
391
|
-
onDestroy(...callbacks) {
|
|
392
|
-
this.lifeCycleDelegate = {
|
|
393
|
-
...this.lifeCycleDelegate,
|
|
394
|
-
destroy: callbacks.length > 0 ? callbacks : void 0
|
|
395
|
-
};
|
|
396
|
-
return this;
|
|
397
|
-
}
|
|
520
|
+
/**
|
|
521
|
+
* Add collision callbacks
|
|
522
|
+
*/
|
|
398
523
|
onCollision(...callbacks) {
|
|
399
|
-
this.collisionDelegate
|
|
400
|
-
|
|
401
|
-
};
|
|
524
|
+
const existing = this.collisionDelegate.collision ?? [];
|
|
525
|
+
this.collisionDelegate.collision = [...existing, ...callbacks];
|
|
402
526
|
return this;
|
|
403
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Entity-specific setup - runs behavior callbacks
|
|
530
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.setup)
|
|
531
|
+
*/
|
|
404
532
|
_setup(params) {
|
|
405
533
|
this.behaviorCallbackMap.setup.forEach((callback) => {
|
|
406
534
|
callback({ ...params, me: this });
|
|
407
535
|
});
|
|
408
|
-
if (this.lifeCycleDelegate.setup?.length) {
|
|
409
|
-
const callbacks = this.lifeCycleDelegate.setup;
|
|
410
|
-
callbacks.forEach((callback) => {
|
|
411
|
-
callback({ ...params, me: this });
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
536
|
}
|
|
415
537
|
async _loaded(_params) {
|
|
416
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* Entity-specific update - updates materials and runs behavior callbacks
|
|
541
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.update)
|
|
542
|
+
*/
|
|
417
543
|
_update(params) {
|
|
418
544
|
this.updateMaterials(params);
|
|
419
|
-
if (this.lifeCycleDelegate.update?.length) {
|
|
420
|
-
const callbacks = this.lifeCycleDelegate.update;
|
|
421
|
-
callbacks.forEach((callback) => {
|
|
422
|
-
callback({ ...params, me: this });
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
545
|
this.behaviorCallbackMap.update.forEach((callback) => {
|
|
426
546
|
callback({ ...params, me: this });
|
|
427
547
|
});
|
|
428
548
|
}
|
|
549
|
+
/**
|
|
550
|
+
* Entity-specific destroy - runs behavior callbacks
|
|
551
|
+
* (User callbacks are handled by BaseNode's lifecycleCallbacks.destroy)
|
|
552
|
+
*/
|
|
429
553
|
_destroy(params) {
|
|
430
|
-
if (this.lifeCycleDelegate.destroy?.length) {
|
|
431
|
-
const callbacks = this.lifeCycleDelegate.destroy;
|
|
432
|
-
callbacks.forEach((callback) => {
|
|
433
|
-
callback({ ...params, me: this });
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
554
|
this.behaviorCallbackMap.destroy.forEach((callback) => {
|
|
437
555
|
callback({ ...params, me: this });
|
|
438
556
|
});
|
|
@@ -722,6 +840,23 @@ var init_animation = __esm({
|
|
|
722
840
|
this._currentAction = action;
|
|
723
841
|
this._currentKey = key;
|
|
724
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Dispose of all animation resources
|
|
845
|
+
*/
|
|
846
|
+
dispose() {
|
|
847
|
+
Object.values(this._actions).forEach((action) => {
|
|
848
|
+
action.stop();
|
|
849
|
+
});
|
|
850
|
+
if (this._mixer) {
|
|
851
|
+
this._mixer.stopAllAction();
|
|
852
|
+
this._mixer.uncacheRoot(this.target);
|
|
853
|
+
this._mixer = null;
|
|
854
|
+
}
|
|
855
|
+
this._actions = {};
|
|
856
|
+
this._animations = [];
|
|
857
|
+
this._currentAction = null;
|
|
858
|
+
this._currentKey = "";
|
|
859
|
+
}
|
|
725
860
|
get currentAnimationKey() {
|
|
726
861
|
return this._currentKey;
|
|
727
862
|
}
|
|
@@ -1220,7 +1355,7 @@ var init_actor = __esm({
|
|
|
1220
1355
|
return new ZylemActor(options);
|
|
1221
1356
|
}
|
|
1222
1357
|
};
|
|
1223
|
-
ACTOR_TYPE = Symbol("Actor");
|
|
1358
|
+
ACTOR_TYPE = /* @__PURE__ */ Symbol("Actor");
|
|
1224
1359
|
ZylemActor = class extends GameEntity {
|
|
1225
1360
|
static type = ACTOR_TYPE;
|
|
1226
1361
|
_object = null;
|
|
@@ -1231,9 +1366,7 @@ var init_actor = __esm({
|
|
|
1231
1366
|
constructor(options) {
|
|
1232
1367
|
super();
|
|
1233
1368
|
this.options = { ...actorDefaults, ...options };
|
|
1234
|
-
this.
|
|
1235
|
-
update: [this.actorUpdate.bind(this)]
|
|
1236
|
-
};
|
|
1369
|
+
this.prependUpdate(this.actorUpdate.bind(this));
|
|
1237
1370
|
this.controlledRotation = true;
|
|
1238
1371
|
}
|
|
1239
1372
|
async load() {
|
|
@@ -1253,6 +1386,34 @@ var init_actor = __esm({
|
|
|
1253
1386
|
async actorUpdate(params) {
|
|
1254
1387
|
this._animationDelegate?.update(params.delta);
|
|
1255
1388
|
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Clean up actor resources including animations, models, and groups
|
|
1391
|
+
*/
|
|
1392
|
+
actorDestroy() {
|
|
1393
|
+
if (this._animationDelegate) {
|
|
1394
|
+
this._animationDelegate.dispose();
|
|
1395
|
+
this._animationDelegate = null;
|
|
1396
|
+
}
|
|
1397
|
+
if (this._object) {
|
|
1398
|
+
this._object.traverse((child) => {
|
|
1399
|
+
if (child.isMesh) {
|
|
1400
|
+
const mesh = child;
|
|
1401
|
+
mesh.geometry?.dispose();
|
|
1402
|
+
if (Array.isArray(mesh.material)) {
|
|
1403
|
+
mesh.material.forEach((m) => m.dispose());
|
|
1404
|
+
} else if (mesh.material) {
|
|
1405
|
+
mesh.material.dispose();
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
});
|
|
1409
|
+
this._object = null;
|
|
1410
|
+
}
|
|
1411
|
+
if (this.group) {
|
|
1412
|
+
this.group.clear();
|
|
1413
|
+
this.group = null;
|
|
1414
|
+
}
|
|
1415
|
+
this._modelFileNames = [];
|
|
1416
|
+
}
|
|
1256
1417
|
async loadModels() {
|
|
1257
1418
|
if (this._modelFileNames.length === 0) return;
|
|
1258
1419
|
const promises = this._modelFileNames.map((file) => this._assetLoader.loadFile(file));
|
|
@@ -1312,25 +1473,17 @@ var init_actor = __esm({
|
|
|
1312
1473
|
}
|
|
1313
1474
|
});
|
|
1314
1475
|
|
|
1315
|
-
// src/lib/collision/
|
|
1476
|
+
// src/lib/collision/world.ts
|
|
1477
|
+
import RAPIER from "@dimforge/rapier3d-compat";
|
|
1316
1478
|
function isCollisionHandlerDelegate(obj) {
|
|
1317
1479
|
return typeof obj?.handlePostCollision === "function" && typeof obj?.handleIntersectionEvent === "function";
|
|
1318
1480
|
}
|
|
1319
|
-
var init_collision_delegate = __esm({
|
|
1320
|
-
"src/lib/collision/collision-delegate.ts"() {
|
|
1321
|
-
"use strict";
|
|
1322
|
-
}
|
|
1323
|
-
});
|
|
1324
|
-
|
|
1325
|
-
// src/lib/collision/world.ts
|
|
1326
|
-
import RAPIER from "@dimforge/rapier3d-compat";
|
|
1327
1481
|
var ZylemWorld;
|
|
1328
1482
|
var init_world = __esm({
|
|
1329
1483
|
"src/lib/collision/world.ts"() {
|
|
1330
1484
|
"use strict";
|
|
1331
1485
|
init_game_state();
|
|
1332
1486
|
init_actor();
|
|
1333
|
-
init_collision_delegate();
|
|
1334
1487
|
ZylemWorld = class {
|
|
1335
1488
|
type = "World";
|
|
1336
1489
|
world;
|
|
@@ -1536,7 +1689,11 @@ var init_zylem_scene = __esm({
|
|
|
1536
1689
|
* Setup camera with the scene
|
|
1537
1690
|
*/
|
|
1538
1691
|
setupCamera(scene, camera2) {
|
|
1539
|
-
|
|
1692
|
+
if (camera2.cameraRig) {
|
|
1693
|
+
scene.add(camera2.cameraRig);
|
|
1694
|
+
} else {
|
|
1695
|
+
scene.add(camera2.camera);
|
|
1696
|
+
}
|
|
1540
1697
|
camera2.setup(scene);
|
|
1541
1698
|
}
|
|
1542
1699
|
/**
|
|
@@ -1597,7 +1754,7 @@ var init_zylem_scene = __esm({
|
|
|
1597
1754
|
|
|
1598
1755
|
// src/lib/stage/stage-state.ts
|
|
1599
1756
|
import { Color as Color5, Vector3 as Vector35 } from "three";
|
|
1600
|
-
import { proxy as proxy3, subscribe as
|
|
1757
|
+
import { proxy as proxy3, subscribe as subscribe3 } from "valtio/vanilla";
|
|
1601
1758
|
function getOrCreateVariableProxy(target) {
|
|
1602
1759
|
let store = variableProxyStore.get(target);
|
|
1603
1760
|
if (!store) {
|
|
@@ -1627,7 +1784,7 @@ function getVariable(target, path) {
|
|
|
1627
1784
|
function onVariableChange(target, path, callback) {
|
|
1628
1785
|
const store = getOrCreateVariableProxy(target);
|
|
1629
1786
|
let previous = getByPath(store, path);
|
|
1630
|
-
return
|
|
1787
|
+
return subscribe3(store, () => {
|
|
1631
1788
|
const current = getByPath(store, path);
|
|
1632
1789
|
if (current !== previous) {
|
|
1633
1790
|
previous = current;
|
|
@@ -1638,7 +1795,7 @@ function onVariableChange(target, path, callback) {
|
|
|
1638
1795
|
function onVariableChanges(target, paths, callback) {
|
|
1639
1796
|
const store = getOrCreateVariableProxy(target);
|
|
1640
1797
|
let previousValues = paths.map((p) => getByPath(store, p));
|
|
1641
|
-
return
|
|
1798
|
+
return subscribe3(store, () => {
|
|
1642
1799
|
const currentValues = paths.map((p) => getByPath(store, p));
|
|
1643
1800
|
const hasChange = currentValues.some((val, i) => val !== previousValues[i]);
|
|
1644
1801
|
if (hasChange) {
|
|
@@ -1735,68 +1892,355 @@ var init_lifecycle_base = __esm({
|
|
|
1735
1892
|
}
|
|
1736
1893
|
});
|
|
1737
1894
|
|
|
1738
|
-
// src/lib/
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
import { Vector3 as Vector37 } from "three";
|
|
1755
|
-
var ThirdPersonCamera;
|
|
1756
|
-
var init_third_person = __esm({
|
|
1757
|
-
"src/lib/camera/third-person.ts"() {
|
|
1895
|
+
// src/lib/stage/debug-entity-cursor.ts
|
|
1896
|
+
import {
|
|
1897
|
+
Box3,
|
|
1898
|
+
BoxGeometry,
|
|
1899
|
+
Color as Color7,
|
|
1900
|
+
EdgesGeometry,
|
|
1901
|
+
Group as Group4,
|
|
1902
|
+
LineBasicMaterial,
|
|
1903
|
+
LineSegments,
|
|
1904
|
+
Mesh as Mesh4,
|
|
1905
|
+
MeshBasicMaterial,
|
|
1906
|
+
Vector3 as Vector37
|
|
1907
|
+
} from "three";
|
|
1908
|
+
var DebugEntityCursor;
|
|
1909
|
+
var init_debug_entity_cursor = __esm({
|
|
1910
|
+
"src/lib/stage/debug-entity-cursor.ts"() {
|
|
1758
1911
|
"use strict";
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
* Setup the third person camera controller
|
|
1770
|
-
*/
|
|
1771
|
-
setup(params) {
|
|
1772
|
-
const { screenResolution, renderer, scene, camera: camera2 } = params;
|
|
1773
|
-
this.screenResolution = screenResolution;
|
|
1774
|
-
this.renderer = renderer;
|
|
1912
|
+
DebugEntityCursor = class {
|
|
1913
|
+
scene;
|
|
1914
|
+
container;
|
|
1915
|
+
fillMesh;
|
|
1916
|
+
edgeLines;
|
|
1917
|
+
currentColor = new Color7(65280);
|
|
1918
|
+
bbox = new Box3();
|
|
1919
|
+
size = new Vector37();
|
|
1920
|
+
center = new Vector37();
|
|
1921
|
+
constructor(scene) {
|
|
1775
1922
|
this.scene = scene;
|
|
1776
|
-
|
|
1923
|
+
const initialGeometry = new BoxGeometry(1, 1, 1);
|
|
1924
|
+
this.fillMesh = new Mesh4(
|
|
1925
|
+
initialGeometry,
|
|
1926
|
+
new MeshBasicMaterial({
|
|
1927
|
+
color: this.currentColor,
|
|
1928
|
+
transparent: true,
|
|
1929
|
+
opacity: 0.12,
|
|
1930
|
+
depthWrite: false
|
|
1931
|
+
})
|
|
1932
|
+
);
|
|
1933
|
+
const edges = new EdgesGeometry(initialGeometry);
|
|
1934
|
+
this.edgeLines = new LineSegments(
|
|
1935
|
+
edges,
|
|
1936
|
+
new LineBasicMaterial({ color: this.currentColor, linewidth: 1 })
|
|
1937
|
+
);
|
|
1938
|
+
this.container = new Group4();
|
|
1939
|
+
this.container.name = "DebugEntityCursor";
|
|
1940
|
+
this.container.add(this.fillMesh);
|
|
1941
|
+
this.container.add(this.edgeLines);
|
|
1942
|
+
this.container.visible = false;
|
|
1943
|
+
this.scene.add(this.container);
|
|
1944
|
+
}
|
|
1945
|
+
setColor(color) {
|
|
1946
|
+
this.currentColor.set(color);
|
|
1947
|
+
this.fillMesh.material.color.set(this.currentColor);
|
|
1948
|
+
this.edgeLines.material.color.set(this.currentColor);
|
|
1777
1949
|
}
|
|
1778
1950
|
/**
|
|
1779
|
-
* Update the
|
|
1951
|
+
* Update the cursor to enclose the provided Object3D using a world-space AABB.
|
|
1780
1952
|
*/
|
|
1781
|
-
|
|
1782
|
-
if (!
|
|
1953
|
+
updateFromObject(object) {
|
|
1954
|
+
if (!object) {
|
|
1955
|
+
this.hide();
|
|
1783
1956
|
return;
|
|
1784
1957
|
}
|
|
1785
|
-
|
|
1786
|
-
this.
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
/**
|
|
1790
|
-
* Handle resize events
|
|
1791
|
-
*/
|
|
1792
|
-
resize(width, height) {
|
|
1793
|
-
if (this.screenResolution) {
|
|
1794
|
-
this.screenResolution.set(width, height);
|
|
1958
|
+
this.bbox.setFromObject(object);
|
|
1959
|
+
if (!isFinite(this.bbox.min.x) || !isFinite(this.bbox.max.x)) {
|
|
1960
|
+
this.hide();
|
|
1961
|
+
return;
|
|
1795
1962
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1963
|
+
this.bbox.getSize(this.size);
|
|
1964
|
+
this.bbox.getCenter(this.center);
|
|
1965
|
+
const newGeom = new BoxGeometry(
|
|
1966
|
+
Math.max(this.size.x, 1e-6),
|
|
1967
|
+
Math.max(this.size.y, 1e-6),
|
|
1968
|
+
Math.max(this.size.z, 1e-6)
|
|
1969
|
+
);
|
|
1970
|
+
this.fillMesh.geometry.dispose();
|
|
1971
|
+
this.fillMesh.geometry = newGeom;
|
|
1972
|
+
const newEdges = new EdgesGeometry(newGeom);
|
|
1973
|
+
this.edgeLines.geometry.dispose();
|
|
1974
|
+
this.edgeLines.geometry = newEdges;
|
|
1975
|
+
this.container.position.copy(this.center);
|
|
1976
|
+
this.container.visible = true;
|
|
1977
|
+
}
|
|
1978
|
+
hide() {
|
|
1979
|
+
this.container.visible = false;
|
|
1980
|
+
}
|
|
1981
|
+
dispose() {
|
|
1982
|
+
this.scene.remove(this.container);
|
|
1983
|
+
this.fillMesh.geometry.dispose();
|
|
1984
|
+
this.fillMesh.material.dispose();
|
|
1985
|
+
this.edgeLines.geometry.dispose();
|
|
1986
|
+
this.edgeLines.material.dispose();
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
|
|
1992
|
+
// src/lib/stage/stage-debug-delegate.ts
|
|
1993
|
+
import { Ray } from "@dimforge/rapier3d-compat";
|
|
1994
|
+
import { BufferAttribute, BufferGeometry as BufferGeometry4, LineBasicMaterial as LineBasicMaterial2, LineSegments as LineSegments2, Raycaster, Vector2 as Vector22 } from "three";
|
|
1995
|
+
var SELECT_TOOL_COLOR, DELETE_TOOL_COLOR, StageDebugDelegate;
|
|
1996
|
+
var init_stage_debug_delegate = __esm({
|
|
1997
|
+
"src/lib/stage/stage-debug-delegate.ts"() {
|
|
1998
|
+
"use strict";
|
|
1999
|
+
init_debug_state();
|
|
2000
|
+
init_debug_entity_cursor();
|
|
2001
|
+
SELECT_TOOL_COLOR = 2293538;
|
|
2002
|
+
DELETE_TOOL_COLOR = 16724787;
|
|
2003
|
+
StageDebugDelegate = class {
|
|
2004
|
+
stage;
|
|
2005
|
+
options;
|
|
2006
|
+
mouseNdc = new Vector22(-2, -2);
|
|
2007
|
+
raycaster = new Raycaster();
|
|
2008
|
+
isMouseDown = false;
|
|
2009
|
+
disposeFns = [];
|
|
2010
|
+
debugCursor = null;
|
|
2011
|
+
debugLines = null;
|
|
2012
|
+
constructor(stage, options) {
|
|
2013
|
+
this.stage = stage;
|
|
2014
|
+
this.options = {
|
|
2015
|
+
maxRayDistance: options?.maxRayDistance ?? 5e3,
|
|
2016
|
+
addEntityFactory: options?.addEntityFactory ?? null
|
|
2017
|
+
};
|
|
2018
|
+
if (this.stage.scene) {
|
|
2019
|
+
this.debugLines = new LineSegments2(
|
|
2020
|
+
new BufferGeometry4(),
|
|
2021
|
+
new LineBasicMaterial2({ vertexColors: true })
|
|
2022
|
+
);
|
|
2023
|
+
this.stage.scene.scene.add(this.debugLines);
|
|
2024
|
+
this.debugLines.visible = true;
|
|
2025
|
+
this.debugCursor = new DebugEntityCursor(this.stage.scene.scene);
|
|
2026
|
+
}
|
|
2027
|
+
this.attachDomListeners();
|
|
2028
|
+
}
|
|
2029
|
+
update() {
|
|
2030
|
+
if (!debugState.enabled) return;
|
|
2031
|
+
if (!this.stage.scene || !this.stage.world || !this.stage.cameraRef) return;
|
|
2032
|
+
const { world, cameraRef } = this.stage;
|
|
2033
|
+
if (this.debugLines) {
|
|
2034
|
+
const { vertices, colors } = world.world.debugRender();
|
|
2035
|
+
this.debugLines.geometry.setAttribute("position", new BufferAttribute(vertices, 3));
|
|
2036
|
+
this.debugLines.geometry.setAttribute("color", new BufferAttribute(colors, 4));
|
|
2037
|
+
}
|
|
2038
|
+
const tool = getDebugTool();
|
|
2039
|
+
const isCursorTool = tool === "select" || tool === "delete";
|
|
2040
|
+
this.raycaster.setFromCamera(this.mouseNdc, cameraRef.camera);
|
|
2041
|
+
const origin = this.raycaster.ray.origin.clone();
|
|
2042
|
+
const direction = this.raycaster.ray.direction.clone().normalize();
|
|
2043
|
+
const rapierRay = new Ray(
|
|
2044
|
+
{ x: origin.x, y: origin.y, z: origin.z },
|
|
2045
|
+
{ x: direction.x, y: direction.y, z: direction.z }
|
|
2046
|
+
);
|
|
2047
|
+
const hit = world.world.castRay(rapierRay, this.options.maxRayDistance, true);
|
|
2048
|
+
if (hit && isCursorTool) {
|
|
2049
|
+
const rigidBody = hit.collider?._parent;
|
|
2050
|
+
const hoveredUuid2 = rigidBody?.userData?.uuid;
|
|
2051
|
+
if (hoveredUuid2) {
|
|
2052
|
+
const entity = this.stage._debugMap.get(hoveredUuid2);
|
|
2053
|
+
if (entity) setHoveredEntity(entity);
|
|
2054
|
+
} else {
|
|
2055
|
+
resetHoveredEntity();
|
|
2056
|
+
}
|
|
2057
|
+
if (this.isMouseDown) {
|
|
2058
|
+
this.handleActionOnHit(hoveredUuid2 ?? null, origin, direction, hit.toi);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
this.isMouseDown = false;
|
|
2062
|
+
const hoveredUuid = getHoveredEntity();
|
|
2063
|
+
if (!hoveredUuid) {
|
|
2064
|
+
this.debugCursor?.hide();
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
const hoveredEntity = this.stage._debugMap.get(`${hoveredUuid}`);
|
|
2068
|
+
const targetObject = hoveredEntity?.group ?? hoveredEntity?.mesh ?? null;
|
|
2069
|
+
if (!targetObject) {
|
|
2070
|
+
this.debugCursor?.hide();
|
|
2071
|
+
return;
|
|
2072
|
+
}
|
|
2073
|
+
switch (tool) {
|
|
2074
|
+
case "select":
|
|
2075
|
+
this.debugCursor?.setColor(SELECT_TOOL_COLOR);
|
|
2076
|
+
break;
|
|
2077
|
+
case "delete":
|
|
2078
|
+
this.debugCursor?.setColor(DELETE_TOOL_COLOR);
|
|
2079
|
+
break;
|
|
2080
|
+
default:
|
|
2081
|
+
this.debugCursor?.setColor(16777215);
|
|
2082
|
+
break;
|
|
2083
|
+
}
|
|
2084
|
+
this.debugCursor?.updateFromObject(targetObject);
|
|
2085
|
+
}
|
|
2086
|
+
dispose() {
|
|
2087
|
+
this.disposeFns.forEach((fn) => fn());
|
|
2088
|
+
this.disposeFns = [];
|
|
2089
|
+
this.debugCursor?.dispose();
|
|
2090
|
+
if (this.debugLines && this.stage.scene) {
|
|
2091
|
+
this.stage.scene.scene.remove(this.debugLines);
|
|
2092
|
+
this.debugLines.geometry.dispose();
|
|
2093
|
+
this.debugLines.material.dispose();
|
|
2094
|
+
this.debugLines = null;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
handleActionOnHit(hoveredUuid, origin, direction, toi) {
|
|
2098
|
+
const tool = getDebugTool();
|
|
2099
|
+
switch (tool) {
|
|
2100
|
+
case "select": {
|
|
2101
|
+
if (hoveredUuid) {
|
|
2102
|
+
const entity = this.stage._debugMap.get(hoveredUuid);
|
|
2103
|
+
if (entity) setSelectedEntity(entity);
|
|
2104
|
+
}
|
|
2105
|
+
break;
|
|
2106
|
+
}
|
|
2107
|
+
case "delete": {
|
|
2108
|
+
if (hoveredUuid) {
|
|
2109
|
+
this.stage.removeEntityByUuid(hoveredUuid);
|
|
2110
|
+
}
|
|
2111
|
+
break;
|
|
2112
|
+
}
|
|
2113
|
+
case "scale": {
|
|
2114
|
+
if (!this.options.addEntityFactory) break;
|
|
2115
|
+
const hitPosition = origin.clone().add(direction.clone().multiplyScalar(toi));
|
|
2116
|
+
const newNode = this.options.addEntityFactory({ position: hitPosition });
|
|
2117
|
+
if (newNode) {
|
|
2118
|
+
Promise.resolve(newNode).then((node) => {
|
|
2119
|
+
if (node) this.stage.spawnEntity(node);
|
|
2120
|
+
}).catch(() => {
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
break;
|
|
2124
|
+
}
|
|
2125
|
+
default:
|
|
2126
|
+
break;
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
attachDomListeners() {
|
|
2130
|
+
const canvas = this.stage.cameraRef?.renderer.domElement ?? this.stage.scene?.zylemCamera.renderer.domElement;
|
|
2131
|
+
if (!canvas) return;
|
|
2132
|
+
const onMouseMove = (e) => {
|
|
2133
|
+
const rect2 = canvas.getBoundingClientRect();
|
|
2134
|
+
const x = (e.clientX - rect2.left) / rect2.width * 2 - 1;
|
|
2135
|
+
const y = -((e.clientY - rect2.top) / rect2.height * 2 - 1);
|
|
2136
|
+
this.mouseNdc.set(x, y);
|
|
2137
|
+
};
|
|
2138
|
+
const onMouseDown = (e) => {
|
|
2139
|
+
this.isMouseDown = true;
|
|
2140
|
+
};
|
|
2141
|
+
canvas.addEventListener("mousemove", onMouseMove);
|
|
2142
|
+
canvas.addEventListener("mousedown", onMouseDown);
|
|
2143
|
+
this.disposeFns.push(() => canvas.removeEventListener("mousemove", onMouseMove));
|
|
2144
|
+
this.disposeFns.push(() => canvas.removeEventListener("mousedown", onMouseDown));
|
|
2145
|
+
}
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
});
|
|
2149
|
+
|
|
2150
|
+
// src/lib/stage/stage-camera-debug-delegate.ts
|
|
2151
|
+
import { subscribe as subscribe4 } from "valtio/vanilla";
|
|
2152
|
+
var StageCameraDebugDelegate;
|
|
2153
|
+
var init_stage_camera_debug_delegate = __esm({
|
|
2154
|
+
"src/lib/stage/stage-camera-debug-delegate.ts"() {
|
|
2155
|
+
"use strict";
|
|
2156
|
+
init_debug_state();
|
|
2157
|
+
StageCameraDebugDelegate = class {
|
|
2158
|
+
stage;
|
|
2159
|
+
constructor(stage) {
|
|
2160
|
+
this.stage = stage;
|
|
2161
|
+
}
|
|
2162
|
+
subscribe(listener) {
|
|
2163
|
+
const notify = () => listener(this.snapshot());
|
|
2164
|
+
notify();
|
|
2165
|
+
return subscribe4(debugState, notify);
|
|
2166
|
+
}
|
|
2167
|
+
resolveTarget(uuid) {
|
|
2168
|
+
const entity = this.stage._debugMap.get(uuid) || this.stage.world?.collisionMap.get(uuid) || null;
|
|
2169
|
+
const target = entity?.group ?? entity?.mesh ?? null;
|
|
2170
|
+
return target ?? null;
|
|
2171
|
+
}
|
|
2172
|
+
snapshot() {
|
|
2173
|
+
return {
|
|
2174
|
+
enabled: debugState.enabled,
|
|
2175
|
+
selected: debugState.selectedEntity ? [debugState.selectedEntity.uuid] : []
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
|
|
2182
|
+
// src/lib/camera/perspective.ts
|
|
2183
|
+
var Perspectives;
|
|
2184
|
+
var init_perspective = __esm({
|
|
2185
|
+
"src/lib/camera/perspective.ts"() {
|
|
2186
|
+
"use strict";
|
|
2187
|
+
Perspectives = {
|
|
2188
|
+
FirstPerson: "first-person",
|
|
2189
|
+
ThirdPerson: "third-person",
|
|
2190
|
+
Isometric: "isometric",
|
|
2191
|
+
Flat2D: "flat-2d",
|
|
2192
|
+
Fixed2D: "fixed-2d"
|
|
2193
|
+
};
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
|
|
2197
|
+
// src/lib/camera/third-person.ts
|
|
2198
|
+
import { Vector3 as Vector39 } from "three";
|
|
2199
|
+
var ThirdPersonCamera;
|
|
2200
|
+
var init_third_person = __esm({
|
|
2201
|
+
"src/lib/camera/third-person.ts"() {
|
|
2202
|
+
"use strict";
|
|
2203
|
+
ThirdPersonCamera = class {
|
|
2204
|
+
distance;
|
|
2205
|
+
screenResolution = null;
|
|
2206
|
+
renderer = null;
|
|
2207
|
+
scene = null;
|
|
2208
|
+
cameraRef = null;
|
|
2209
|
+
constructor() {
|
|
2210
|
+
this.distance = new Vector39(0, 5, 8);
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Setup the third person camera controller
|
|
2214
|
+
*/
|
|
2215
|
+
setup(params) {
|
|
2216
|
+
const { screenResolution, renderer, scene, camera: camera2 } = params;
|
|
2217
|
+
this.screenResolution = screenResolution;
|
|
2218
|
+
this.renderer = renderer;
|
|
2219
|
+
this.scene = scene;
|
|
2220
|
+
this.cameraRef = camera2;
|
|
2221
|
+
}
|
|
2222
|
+
/**
|
|
2223
|
+
* Update the third person camera
|
|
2224
|
+
*/
|
|
2225
|
+
update(delta) {
|
|
2226
|
+
if (!this.cameraRef.target) {
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
const desiredCameraPosition = this.cameraRef.target.group.position.clone().add(this.distance);
|
|
2230
|
+
this.cameraRef.camera.position.lerp(desiredCameraPosition, 0.1);
|
|
2231
|
+
this.cameraRef.camera.lookAt(this.cameraRef.target.group.position);
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* Handle resize events
|
|
2235
|
+
*/
|
|
2236
|
+
resize(width, height) {
|
|
2237
|
+
if (this.screenResolution) {
|
|
2238
|
+
this.screenResolution.set(width, height);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
/**
|
|
2242
|
+
* Set the distance from the target
|
|
2243
|
+
*/
|
|
1800
2244
|
setDistance(distance) {
|
|
1801
2245
|
this.distance = distance;
|
|
1802
2246
|
}
|
|
@@ -1901,41 +2345,217 @@ var init_render_pass = __esm({
|
|
|
1901
2345
|
} else {
|
|
1902
2346
|
renderer.setRenderTarget(writeBuffer);
|
|
1903
2347
|
}
|
|
1904
|
-
this.fsQuad.render(renderer);
|
|
2348
|
+
this.fsQuad.render(renderer);
|
|
2349
|
+
}
|
|
2350
|
+
material() {
|
|
2351
|
+
return new THREE.ShaderMaterial({
|
|
2352
|
+
uniforms: {
|
|
2353
|
+
iTime: { value: 0 },
|
|
2354
|
+
tDiffuse: { value: null },
|
|
2355
|
+
tDepth: { value: null },
|
|
2356
|
+
tNormal: { value: null },
|
|
2357
|
+
resolution: {
|
|
2358
|
+
value: new THREE.Vector4(
|
|
2359
|
+
this.resolution.x,
|
|
2360
|
+
this.resolution.y,
|
|
2361
|
+
1 / this.resolution.x,
|
|
2362
|
+
1 / this.resolution.y
|
|
2363
|
+
)
|
|
2364
|
+
}
|
|
2365
|
+
},
|
|
2366
|
+
vertexShader: standard_default2,
|
|
2367
|
+
fragmentShader: standard_default
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
dispose() {
|
|
2371
|
+
try {
|
|
2372
|
+
this.fsQuad?.dispose?.();
|
|
2373
|
+
} catch {
|
|
2374
|
+
}
|
|
2375
|
+
try {
|
|
2376
|
+
this.rgbRenderTarget?.dispose?.();
|
|
2377
|
+
this.normalRenderTarget?.dispose?.();
|
|
2378
|
+
} catch {
|
|
2379
|
+
}
|
|
2380
|
+
try {
|
|
2381
|
+
this.normalMaterial?.dispose?.();
|
|
2382
|
+
} catch {
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
}
|
|
2387
|
+
});
|
|
2388
|
+
|
|
2389
|
+
// src/lib/camera/camera-debug-delegate.ts
|
|
2390
|
+
import { Vector3 as Vector310 } from "three";
|
|
2391
|
+
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
2392
|
+
var CameraOrbitController;
|
|
2393
|
+
var init_camera_debug_delegate = __esm({
|
|
2394
|
+
"src/lib/camera/camera-debug-delegate.ts"() {
|
|
2395
|
+
"use strict";
|
|
2396
|
+
CameraOrbitController = class {
|
|
2397
|
+
camera;
|
|
2398
|
+
domElement;
|
|
2399
|
+
orbitControls = null;
|
|
2400
|
+
orbitTarget = null;
|
|
2401
|
+
orbitTargetWorldPos = new Vector310();
|
|
2402
|
+
debugDelegate = null;
|
|
2403
|
+
debugUnsubscribe = null;
|
|
2404
|
+
debugStateSnapshot = { enabled: false, selected: [] };
|
|
2405
|
+
// Saved camera state for restoration when exiting debug mode
|
|
2406
|
+
savedCameraPosition = null;
|
|
2407
|
+
savedCameraQuaternion = null;
|
|
2408
|
+
savedCameraZoom = null;
|
|
2409
|
+
constructor(camera2, domElement) {
|
|
2410
|
+
this.camera = camera2;
|
|
2411
|
+
this.domElement = domElement;
|
|
2412
|
+
}
|
|
2413
|
+
/**
|
|
2414
|
+
* Check if debug mode is currently active (orbit controls enabled).
|
|
2415
|
+
*/
|
|
2416
|
+
get isActive() {
|
|
2417
|
+
return this.debugStateSnapshot.enabled;
|
|
2418
|
+
}
|
|
2419
|
+
/**
|
|
2420
|
+
* Update orbit controls each frame.
|
|
2421
|
+
* Should be called from the camera's update loop.
|
|
2422
|
+
*/
|
|
2423
|
+
update() {
|
|
2424
|
+
if (this.orbitControls && this.orbitTarget) {
|
|
2425
|
+
this.orbitTarget.getWorldPosition(this.orbitTargetWorldPos);
|
|
2426
|
+
this.orbitControls.target.copy(this.orbitTargetWorldPos);
|
|
2427
|
+
}
|
|
2428
|
+
this.orbitControls?.update();
|
|
2429
|
+
}
|
|
2430
|
+
/**
|
|
2431
|
+
* Attach a delegate to react to debug state changes.
|
|
2432
|
+
*/
|
|
2433
|
+
setDebugDelegate(delegate) {
|
|
2434
|
+
if (this.debugDelegate === delegate) {
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
this.detachDebugDelegate();
|
|
2438
|
+
this.debugDelegate = delegate;
|
|
2439
|
+
if (!delegate) {
|
|
2440
|
+
this.applyDebugState({ enabled: false, selected: [] });
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
const unsubscribe = delegate.subscribe((state2) => {
|
|
2444
|
+
this.applyDebugState(state2);
|
|
2445
|
+
});
|
|
2446
|
+
this.debugUnsubscribe = () => {
|
|
2447
|
+
unsubscribe?.();
|
|
2448
|
+
};
|
|
2449
|
+
}
|
|
2450
|
+
/**
|
|
2451
|
+
* Clean up resources.
|
|
2452
|
+
*/
|
|
2453
|
+
dispose() {
|
|
2454
|
+
this.disableOrbitControls();
|
|
2455
|
+
this.detachDebugDelegate();
|
|
2456
|
+
}
|
|
2457
|
+
/**
|
|
2458
|
+
* Get the current debug state snapshot.
|
|
2459
|
+
*/
|
|
2460
|
+
get debugState() {
|
|
2461
|
+
return this.debugStateSnapshot;
|
|
2462
|
+
}
|
|
2463
|
+
applyDebugState(state2) {
|
|
2464
|
+
const wasEnabled = this.debugStateSnapshot.enabled;
|
|
2465
|
+
this.debugStateSnapshot = {
|
|
2466
|
+
enabled: state2.enabled,
|
|
2467
|
+
selected: [...state2.selected]
|
|
2468
|
+
};
|
|
2469
|
+
if (state2.enabled && !wasEnabled) {
|
|
2470
|
+
this.saveCameraState();
|
|
2471
|
+
this.enableOrbitControls();
|
|
2472
|
+
this.updateOrbitTargetFromSelection(state2.selected);
|
|
2473
|
+
} else if (!state2.enabled && wasEnabled) {
|
|
2474
|
+
this.orbitTarget = null;
|
|
2475
|
+
this.disableOrbitControls();
|
|
2476
|
+
this.restoreCameraState();
|
|
2477
|
+
} else if (state2.enabled) {
|
|
2478
|
+
this.updateOrbitTargetFromSelection(state2.selected);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
enableOrbitControls() {
|
|
2482
|
+
if (this.orbitControls) {
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
this.orbitControls = new OrbitControls(this.camera, this.domElement);
|
|
2486
|
+
this.orbitControls.enableDamping = true;
|
|
2487
|
+
this.orbitControls.dampingFactor = 0.05;
|
|
2488
|
+
this.orbitControls.screenSpacePanning = false;
|
|
2489
|
+
this.orbitControls.minDistance = 1;
|
|
2490
|
+
this.orbitControls.maxDistance = 500;
|
|
2491
|
+
this.orbitControls.maxPolarAngle = Math.PI / 2;
|
|
2492
|
+
this.orbitControls.target.set(0, 0, 0);
|
|
2493
|
+
}
|
|
2494
|
+
disableOrbitControls() {
|
|
2495
|
+
if (!this.orbitControls) {
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
this.orbitControls.dispose();
|
|
2499
|
+
this.orbitControls = null;
|
|
2500
|
+
}
|
|
2501
|
+
updateOrbitTargetFromSelection(selected) {
|
|
2502
|
+
if (!this.debugDelegate || selected.length === 0) {
|
|
2503
|
+
this.orbitTarget = null;
|
|
2504
|
+
if (this.orbitControls) {
|
|
2505
|
+
this.orbitControls.target.set(0, 0, 0);
|
|
2506
|
+
}
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
for (let i = selected.length - 1; i >= 0; i -= 1) {
|
|
2510
|
+
const uuid = selected[i];
|
|
2511
|
+
const targetObject = this.debugDelegate.resolveTarget(uuid);
|
|
2512
|
+
if (targetObject) {
|
|
2513
|
+
this.orbitTarget = targetObject;
|
|
2514
|
+
if (this.orbitControls) {
|
|
2515
|
+
targetObject.getWorldPosition(this.orbitTargetWorldPos);
|
|
2516
|
+
this.orbitControls.target.copy(this.orbitTargetWorldPos);
|
|
2517
|
+
}
|
|
2518
|
+
return;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
this.orbitTarget = null;
|
|
1905
2522
|
}
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
this.resolution.x,
|
|
1916
|
-
this.resolution.y,
|
|
1917
|
-
1 / this.resolution.x,
|
|
1918
|
-
1 / this.resolution.y
|
|
1919
|
-
)
|
|
1920
|
-
}
|
|
1921
|
-
},
|
|
1922
|
-
vertexShader: standard_default2,
|
|
1923
|
-
fragmentShader: standard_default
|
|
1924
|
-
});
|
|
2523
|
+
detachDebugDelegate() {
|
|
2524
|
+
if (this.debugUnsubscribe) {
|
|
2525
|
+
try {
|
|
2526
|
+
this.debugUnsubscribe();
|
|
2527
|
+
} catch {
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
this.debugUnsubscribe = null;
|
|
2531
|
+
this.debugDelegate = null;
|
|
1925
2532
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
2533
|
+
/**
|
|
2534
|
+
* Save camera position, rotation, and zoom before entering debug mode.
|
|
2535
|
+
*/
|
|
2536
|
+
saveCameraState() {
|
|
2537
|
+
this.savedCameraPosition = this.camera.position.clone();
|
|
2538
|
+
this.savedCameraQuaternion = this.camera.quaternion.clone();
|
|
2539
|
+
if ("zoom" in this.camera) {
|
|
2540
|
+
this.savedCameraZoom = this.camera.zoom;
|
|
1930
2541
|
}
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
2542
|
+
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Restore camera position, rotation, and zoom when exiting debug mode.
|
|
2545
|
+
*/
|
|
2546
|
+
restoreCameraState() {
|
|
2547
|
+
if (this.savedCameraPosition) {
|
|
2548
|
+
this.camera.position.copy(this.savedCameraPosition);
|
|
2549
|
+
this.savedCameraPosition = null;
|
|
1935
2550
|
}
|
|
1936
|
-
|
|
1937
|
-
this.
|
|
1938
|
-
|
|
2551
|
+
if (this.savedCameraQuaternion) {
|
|
2552
|
+
this.camera.quaternion.copy(this.savedCameraQuaternion);
|
|
2553
|
+
this.savedCameraQuaternion = null;
|
|
2554
|
+
}
|
|
2555
|
+
if (this.savedCameraZoom !== null && "zoom" in this.camera) {
|
|
2556
|
+
this.camera.zoom = this.savedCameraZoom;
|
|
2557
|
+
this.camera.updateProjectionMatrix?.();
|
|
2558
|
+
this.savedCameraZoom = null;
|
|
1939
2559
|
}
|
|
1940
2560
|
}
|
|
1941
2561
|
};
|
|
@@ -1943,8 +2563,7 @@ var init_render_pass = __esm({
|
|
|
1943
2563
|
});
|
|
1944
2564
|
|
|
1945
2565
|
// src/lib/camera/zylem-camera.ts
|
|
1946
|
-
import { PerspectiveCamera, Vector3 as
|
|
1947
|
-
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
2566
|
+
import { PerspectiveCamera, Vector3 as Vector311, Object3D as Object3D6, OrthographicCamera, WebGLRenderer as WebGLRenderer3 } from "three";
|
|
1948
2567
|
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
|
|
1949
2568
|
var ZylemCamera;
|
|
1950
2569
|
var init_zylem_camera = __esm({
|
|
@@ -1954,24 +2573,21 @@ var init_zylem_camera = __esm({
|
|
|
1954
2573
|
init_third_person();
|
|
1955
2574
|
init_fixed_2d();
|
|
1956
2575
|
init_render_pass();
|
|
2576
|
+
init_camera_debug_delegate();
|
|
1957
2577
|
ZylemCamera = class {
|
|
1958
|
-
cameraRig;
|
|
2578
|
+
cameraRig = null;
|
|
1959
2579
|
camera;
|
|
1960
2580
|
screenResolution;
|
|
1961
2581
|
renderer;
|
|
1962
2582
|
composer;
|
|
1963
2583
|
_perspective;
|
|
1964
|
-
orbitControls = null;
|
|
1965
2584
|
target = null;
|
|
1966
2585
|
sceneRef = null;
|
|
1967
2586
|
frustumSize = 10;
|
|
1968
2587
|
// Perspective controller delegation
|
|
1969
2588
|
perspectiveController = null;
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
debugStateSnapshot = { enabled: false, selected: [] };
|
|
1973
|
-
orbitTarget = null;
|
|
1974
|
-
orbitTargetWorldPos = new Vector38();
|
|
2589
|
+
// Debug/orbit controls delegation
|
|
2590
|
+
orbitController = null;
|
|
1975
2591
|
constructor(perspective, screenResolution, frustumSize = 10) {
|
|
1976
2592
|
this._perspective = perspective;
|
|
1977
2593
|
this.screenResolution = screenResolution;
|
|
@@ -1982,26 +2598,23 @@ var init_zylem_camera = __esm({
|
|
|
1982
2598
|
this.composer = new EffectComposer(this.renderer);
|
|
1983
2599
|
const aspectRatio = screenResolution.x / screenResolution.y;
|
|
1984
2600
|
this.camera = this.createCameraForPerspective(aspectRatio);
|
|
1985
|
-
this.
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2601
|
+
if (this.needsRig()) {
|
|
2602
|
+
this.cameraRig = new Object3D6();
|
|
2603
|
+
this.cameraRig.position.set(0, 3, 10);
|
|
2604
|
+
this.cameraRig.add(this.camera);
|
|
2605
|
+
this.camera.lookAt(new Vector311(0, 2, 0));
|
|
2606
|
+
} else {
|
|
2607
|
+
this.camera.position.set(0, 0, 10);
|
|
2608
|
+
this.camera.lookAt(new Vector311(0, 0, 0));
|
|
2609
|
+
}
|
|
1989
2610
|
this.initializePerspectiveController();
|
|
2611
|
+
this.orbitController = new CameraOrbitController(this.camera, this.renderer.domElement);
|
|
1990
2612
|
}
|
|
1991
2613
|
/**
|
|
1992
2614
|
* Setup the camera with a scene
|
|
1993
2615
|
*/
|
|
1994
2616
|
async setup(scene) {
|
|
1995
2617
|
this.sceneRef = scene;
|
|
1996
|
-
if (this.orbitControls === null) {
|
|
1997
|
-
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
1998
|
-
this.orbitControls.enableDamping = true;
|
|
1999
|
-
this.orbitControls.dampingFactor = 0.05;
|
|
2000
|
-
this.orbitControls.screenSpacePanning = false;
|
|
2001
|
-
this.orbitControls.minDistance = 1;
|
|
2002
|
-
this.orbitControls.maxDistance = 500;
|
|
2003
|
-
this.orbitControls.maxPolarAngle = Math.PI / 2;
|
|
2004
|
-
}
|
|
2005
2618
|
let renderResolution = this.screenResolution.clone().divideScalar(2);
|
|
2006
2619
|
renderResolution.x |= 0;
|
|
2007
2620
|
renderResolution.y |= 0;
|
|
@@ -2023,16 +2636,18 @@ var init_zylem_camera = __esm({
|
|
|
2023
2636
|
* Update camera and render
|
|
2024
2637
|
*/
|
|
2025
2638
|
update(delta) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
this.orbitControls.target.copy(this.orbitTargetWorldPos);
|
|
2029
|
-
}
|
|
2030
|
-
this.orbitControls?.update();
|
|
2031
|
-
if (this.perspectiveController) {
|
|
2639
|
+
this.orbitController?.update();
|
|
2640
|
+
if (this.perspectiveController && !this.isDebugModeActive()) {
|
|
2032
2641
|
this.perspectiveController.update(delta);
|
|
2033
2642
|
}
|
|
2034
2643
|
this.composer.render(delta);
|
|
2035
2644
|
}
|
|
2645
|
+
/**
|
|
2646
|
+
* Check if debug mode is active (orbit controls taking over camera)
|
|
2647
|
+
*/
|
|
2648
|
+
isDebugModeActive() {
|
|
2649
|
+
return this.orbitController?.isActive ?? false;
|
|
2650
|
+
}
|
|
2036
2651
|
/**
|
|
2037
2652
|
* Dispose renderer, composer, controls, and detach from scene
|
|
2038
2653
|
*/
|
|
@@ -2042,7 +2657,7 @@ var init_zylem_camera = __esm({
|
|
|
2042
2657
|
} catch {
|
|
2043
2658
|
}
|
|
2044
2659
|
try {
|
|
2045
|
-
this.
|
|
2660
|
+
this.orbitController?.dispose();
|
|
2046
2661
|
} catch {
|
|
2047
2662
|
}
|
|
2048
2663
|
try {
|
|
@@ -2054,28 +2669,13 @@ var init_zylem_camera = __esm({
|
|
|
2054
2669
|
this.renderer.dispose();
|
|
2055
2670
|
} catch {
|
|
2056
2671
|
}
|
|
2057
|
-
this.detachDebugDelegate();
|
|
2058
2672
|
this.sceneRef = null;
|
|
2059
2673
|
}
|
|
2060
2674
|
/**
|
|
2061
2675
|
* Attach a delegate to react to debug state changes.
|
|
2062
2676
|
*/
|
|
2063
2677
|
setDebugDelegate(delegate) {
|
|
2064
|
-
|
|
2065
|
-
return;
|
|
2066
|
-
}
|
|
2067
|
-
this.detachDebugDelegate();
|
|
2068
|
-
this.debugDelegate = delegate;
|
|
2069
|
-
if (!delegate) {
|
|
2070
|
-
this.applyDebugState({ enabled: false, selected: [] });
|
|
2071
|
-
return;
|
|
2072
|
-
}
|
|
2073
|
-
const unsubscribe = delegate.subscribe((state2) => {
|
|
2074
|
-
this.applyDebugState(state2);
|
|
2075
|
-
});
|
|
2076
|
-
this.debugUnsubscribe = () => {
|
|
2077
|
-
unsubscribe?.();
|
|
2078
|
-
};
|
|
2678
|
+
this.orbitController?.setDebugDelegate(delegate);
|
|
2079
2679
|
}
|
|
2080
2680
|
/**
|
|
2081
2681
|
* Resize camera and renderer
|
|
@@ -2167,15 +2767,31 @@ var init_zylem_camera = __esm({
|
|
|
2167
2767
|
if (this._perspective === Perspectives.Flat2D || this._perspective === Perspectives.Fixed2D) {
|
|
2168
2768
|
this.frustumSize = position2.z;
|
|
2169
2769
|
}
|
|
2170
|
-
this.cameraRig
|
|
2770
|
+
if (this.cameraRig) {
|
|
2771
|
+
this.cameraRig.position.set(position2.x, position2.y, position2.z);
|
|
2772
|
+
} else {
|
|
2773
|
+
this.camera.position.set(position2.x, position2.y, position2.z);
|
|
2774
|
+
}
|
|
2171
2775
|
}
|
|
2172
2776
|
move(position2) {
|
|
2173
2777
|
this.moveCamera(position2);
|
|
2174
2778
|
}
|
|
2175
2779
|
rotate(pitch, yaw, roll) {
|
|
2176
|
-
this.cameraRig
|
|
2177
|
-
|
|
2178
|
-
|
|
2780
|
+
if (this.cameraRig) {
|
|
2781
|
+
this.cameraRig.rotateX(pitch);
|
|
2782
|
+
this.cameraRig.rotateY(yaw);
|
|
2783
|
+
this.cameraRig.rotateZ(roll);
|
|
2784
|
+
} else {
|
|
2785
|
+
this.camera.rotateX(pitch);
|
|
2786
|
+
this.camera.rotateY(yaw);
|
|
2787
|
+
this.camera.rotateZ(roll);
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
/**
|
|
2791
|
+
* Check if this perspective type needs a camera rig
|
|
2792
|
+
*/
|
|
2793
|
+
needsRig() {
|
|
2794
|
+
return this._perspective === Perspectives.ThirdPerson;
|
|
2179
2795
|
}
|
|
2180
2796
|
/**
|
|
2181
2797
|
* Get the DOM element for the renderer
|
|
@@ -2183,348 +2799,221 @@ var init_zylem_camera = __esm({
|
|
|
2183
2799
|
getDomElement() {
|
|
2184
2800
|
return this.renderer.domElement;
|
|
2185
2801
|
}
|
|
2186
|
-
applyDebugState(state2) {
|
|
2187
|
-
this.debugStateSnapshot = {
|
|
2188
|
-
enabled: state2.enabled,
|
|
2189
|
-
selected: [...state2.selected]
|
|
2190
|
-
};
|
|
2191
|
-
if (state2.enabled) {
|
|
2192
|
-
this.enableOrbitControls();
|
|
2193
|
-
this.updateOrbitTargetFromSelection(state2.selected);
|
|
2194
|
-
} else {
|
|
2195
|
-
this.orbitTarget = null;
|
|
2196
|
-
this.disableOrbitControls();
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
enableOrbitControls() {
|
|
2200
|
-
if (this.orbitControls) {
|
|
2201
|
-
return;
|
|
2202
|
-
}
|
|
2203
|
-
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
2204
|
-
this.orbitControls.enableDamping = true;
|
|
2205
|
-
this.orbitControls.dampingFactor = 0.05;
|
|
2206
|
-
this.orbitControls.screenSpacePanning = false;
|
|
2207
|
-
this.orbitControls.minDistance = 1;
|
|
2208
|
-
this.orbitControls.maxDistance = 500;
|
|
2209
|
-
this.orbitControls.maxPolarAngle = Math.PI / 2;
|
|
2210
|
-
}
|
|
2211
|
-
disableOrbitControls() {
|
|
2212
|
-
if (!this.orbitControls) {
|
|
2213
|
-
return;
|
|
2214
|
-
}
|
|
2215
|
-
this.orbitControls.dispose();
|
|
2216
|
-
this.orbitControls = null;
|
|
2217
|
-
}
|
|
2218
|
-
updateOrbitTargetFromSelection(selected) {
|
|
2219
|
-
if (!this.debugDelegate || selected.length === 0) {
|
|
2220
|
-
this.orbitTarget = null;
|
|
2221
|
-
return;
|
|
2222
|
-
}
|
|
2223
|
-
for (let i = selected.length - 1; i >= 0; i -= 1) {
|
|
2224
|
-
const uuid = selected[i];
|
|
2225
|
-
const targetObject = this.debugDelegate.resolveTarget(uuid);
|
|
2226
|
-
if (targetObject) {
|
|
2227
|
-
this.orbitTarget = targetObject;
|
|
2228
|
-
if (this.orbitControls) {
|
|
2229
|
-
targetObject.getWorldPosition(this.orbitTargetWorldPos);
|
|
2230
|
-
this.orbitControls.target.copy(this.orbitTargetWorldPos);
|
|
2231
|
-
}
|
|
2232
|
-
return;
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
this.orbitTarget = null;
|
|
2236
|
-
}
|
|
2237
|
-
detachDebugDelegate() {
|
|
2238
|
-
if (this.debugUnsubscribe) {
|
|
2239
|
-
try {
|
|
2240
|
-
this.debugUnsubscribe();
|
|
2241
|
-
} catch {
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
this.debugUnsubscribe = null;
|
|
2245
|
-
this.debugDelegate = null;
|
|
2246
|
-
}
|
|
2247
2802
|
};
|
|
2248
2803
|
}
|
|
2249
2804
|
});
|
|
2250
2805
|
|
|
2251
|
-
// src/lib/
|
|
2252
|
-
import { Vector2 as
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
if (options.perspective === "fixed-2d") {
|
|
2257
|
-
frustumSize = options.zoom || 10;
|
|
2258
|
-
}
|
|
2259
|
-
const zylemCamera = new ZylemCamera(options.perspective || "third-person", screenResolution, frustumSize);
|
|
2260
|
-
zylemCamera.move(options.position || new Vector39(0, 0, 0));
|
|
2261
|
-
zylemCamera.camera.lookAt(options.target || new Vector39(0, 0, 0));
|
|
2262
|
-
return new CameraWrapper(zylemCamera);
|
|
2263
|
-
}
|
|
2264
|
-
var CameraWrapper;
|
|
2265
|
-
var init_camera = __esm({
|
|
2266
|
-
"src/lib/camera/camera.ts"() {
|
|
2806
|
+
// src/lib/stage/stage-camera-delegate.ts
|
|
2807
|
+
import { Vector2 as Vector25 } from "three";
|
|
2808
|
+
var StageCameraDelegate;
|
|
2809
|
+
var init_stage_camera_delegate = __esm({
|
|
2810
|
+
"src/lib/stage/stage-camera-delegate.ts"() {
|
|
2267
2811
|
"use strict";
|
|
2268
2812
|
init_zylem_camera();
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
};
|
|
2275
|
-
}
|
|
2276
|
-
});
|
|
2277
|
-
|
|
2278
|
-
// src/lib/stage/debug-entity-cursor.ts
|
|
2279
|
-
import {
|
|
2280
|
-
Box3,
|
|
2281
|
-
BoxGeometry,
|
|
2282
|
-
Color as Color7,
|
|
2283
|
-
EdgesGeometry,
|
|
2284
|
-
Group as Group4,
|
|
2285
|
-
LineBasicMaterial,
|
|
2286
|
-
LineSegments,
|
|
2287
|
-
Mesh as Mesh4,
|
|
2288
|
-
MeshBasicMaterial,
|
|
2289
|
-
Vector3 as Vector310
|
|
2290
|
-
} from "three";
|
|
2291
|
-
var DebugEntityCursor;
|
|
2292
|
-
var init_debug_entity_cursor = __esm({
|
|
2293
|
-
"src/lib/stage/debug-entity-cursor.ts"() {
|
|
2294
|
-
"use strict";
|
|
2295
|
-
DebugEntityCursor = class {
|
|
2296
|
-
scene;
|
|
2297
|
-
container;
|
|
2298
|
-
fillMesh;
|
|
2299
|
-
edgeLines;
|
|
2300
|
-
currentColor = new Color7(65280);
|
|
2301
|
-
bbox = new Box3();
|
|
2302
|
-
size = new Vector310();
|
|
2303
|
-
center = new Vector310();
|
|
2304
|
-
constructor(scene) {
|
|
2305
|
-
this.scene = scene;
|
|
2306
|
-
const initialGeometry = new BoxGeometry(1, 1, 1);
|
|
2307
|
-
this.fillMesh = new Mesh4(
|
|
2308
|
-
initialGeometry,
|
|
2309
|
-
new MeshBasicMaterial({
|
|
2310
|
-
color: this.currentColor,
|
|
2311
|
-
transparent: true,
|
|
2312
|
-
opacity: 0.12,
|
|
2313
|
-
depthWrite: false
|
|
2314
|
-
})
|
|
2315
|
-
);
|
|
2316
|
-
const edges = new EdgesGeometry(initialGeometry);
|
|
2317
|
-
this.edgeLines = new LineSegments(
|
|
2318
|
-
edges,
|
|
2319
|
-
new LineBasicMaterial({ color: this.currentColor, linewidth: 1 })
|
|
2320
|
-
);
|
|
2321
|
-
this.container = new Group4();
|
|
2322
|
-
this.container.name = "DebugEntityCursor";
|
|
2323
|
-
this.container.add(this.fillMesh);
|
|
2324
|
-
this.container.add(this.edgeLines);
|
|
2325
|
-
this.container.visible = false;
|
|
2326
|
-
this.scene.add(this.container);
|
|
2327
|
-
}
|
|
2328
|
-
setColor(color) {
|
|
2329
|
-
this.currentColor.set(color);
|
|
2330
|
-
this.fillMesh.material.color.set(this.currentColor);
|
|
2331
|
-
this.edgeLines.material.color.set(this.currentColor);
|
|
2813
|
+
init_perspective();
|
|
2814
|
+
StageCameraDelegate = class {
|
|
2815
|
+
stage;
|
|
2816
|
+
constructor(stage) {
|
|
2817
|
+
this.stage = stage;
|
|
2332
2818
|
}
|
|
2333
2819
|
/**
|
|
2334
|
-
*
|
|
2820
|
+
* Create a default third-person camera based on window size.
|
|
2335
2821
|
*/
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
this.bbox.setFromObject(object);
|
|
2342
|
-
if (!isFinite(this.bbox.min.x) || !isFinite(this.bbox.max.x)) {
|
|
2343
|
-
this.hide();
|
|
2344
|
-
return;
|
|
2345
|
-
}
|
|
2346
|
-
this.bbox.getSize(this.size);
|
|
2347
|
-
this.bbox.getCenter(this.center);
|
|
2348
|
-
const newGeom = new BoxGeometry(
|
|
2349
|
-
Math.max(this.size.x, 1e-6),
|
|
2350
|
-
Math.max(this.size.y, 1e-6),
|
|
2351
|
-
Math.max(this.size.z, 1e-6)
|
|
2352
|
-
);
|
|
2353
|
-
this.fillMesh.geometry.dispose();
|
|
2354
|
-
this.fillMesh.geometry = newGeom;
|
|
2355
|
-
const newEdges = new EdgesGeometry(newGeom);
|
|
2356
|
-
this.edgeLines.geometry.dispose();
|
|
2357
|
-
this.edgeLines.geometry = newEdges;
|
|
2358
|
-
this.container.position.copy(this.center);
|
|
2359
|
-
this.container.visible = true;
|
|
2360
|
-
}
|
|
2361
|
-
hide() {
|
|
2362
|
-
this.container.visible = false;
|
|
2822
|
+
createDefaultCamera() {
|
|
2823
|
+
const width = window.innerWidth;
|
|
2824
|
+
const height = window.innerHeight;
|
|
2825
|
+
const screenResolution = new Vector25(width, height);
|
|
2826
|
+
return new ZylemCamera(Perspectives.ThirdPerson, screenResolution);
|
|
2363
2827
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2828
|
+
/**
|
|
2829
|
+
* Resolve the camera to use for the stage.
|
|
2830
|
+
* Uses the provided camera, stage camera wrapper, or creates a default.
|
|
2831
|
+
*
|
|
2832
|
+
* @param cameraOverride Optional camera override
|
|
2833
|
+
* @param cameraWrapper Optional camera wrapper from stage options
|
|
2834
|
+
* @returns The resolved ZylemCamera instance
|
|
2835
|
+
*/
|
|
2836
|
+
resolveCamera(cameraOverride, cameraWrapper) {
|
|
2837
|
+
if (cameraOverride) {
|
|
2838
|
+
return cameraOverride;
|
|
2839
|
+
}
|
|
2840
|
+
if (cameraWrapper) {
|
|
2841
|
+
return cameraWrapper.cameraRef;
|
|
2842
|
+
}
|
|
2843
|
+
return this.createDefaultCamera();
|
|
2370
2844
|
}
|
|
2371
2845
|
};
|
|
2372
2846
|
}
|
|
2373
2847
|
});
|
|
2374
2848
|
|
|
2375
|
-
// src/lib/stage/stage-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
var init_stage_debug_delegate = __esm({
|
|
2380
|
-
"src/lib/stage/stage-debug-delegate.ts"() {
|
|
2849
|
+
// src/lib/stage/stage-loading-delegate.ts
|
|
2850
|
+
var StageLoadingDelegate;
|
|
2851
|
+
var init_stage_loading_delegate = __esm({
|
|
2852
|
+
"src/lib/stage/stage-loading-delegate.ts"() {
|
|
2381
2853
|
"use strict";
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2854
|
+
init_game_event_bus();
|
|
2855
|
+
StageLoadingDelegate = class {
|
|
2856
|
+
loadingHandlers = [];
|
|
2857
|
+
stageName;
|
|
2858
|
+
stageIndex;
|
|
2859
|
+
/**
|
|
2860
|
+
* Set stage context for event bus emissions.
|
|
2861
|
+
*/
|
|
2862
|
+
setStageContext(stageName, stageIndex) {
|
|
2863
|
+
this.stageName = stageName;
|
|
2864
|
+
this.stageIndex = stageIndex;
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Subscribe to loading events.
|
|
2868
|
+
*
|
|
2869
|
+
* @param callback Invoked for each loading event (start, progress, complete)
|
|
2870
|
+
* @returns Unsubscribe function
|
|
2871
|
+
*/
|
|
2872
|
+
onLoading(callback) {
|
|
2873
|
+
this.loadingHandlers.push(callback);
|
|
2874
|
+
return () => {
|
|
2875
|
+
this.loadingHandlers = this.loadingHandlers.filter((h) => h !== callback);
|
|
2400
2876
|
};
|
|
2401
|
-
if (this.stage.scene) {
|
|
2402
|
-
this.debugLines = new LineSegments2(
|
|
2403
|
-
new BufferGeometry4(),
|
|
2404
|
-
new LineBasicMaterial2({ vertexColors: true })
|
|
2405
|
-
);
|
|
2406
|
-
this.stage.scene.scene.add(this.debugLines);
|
|
2407
|
-
this.debugLines.visible = true;
|
|
2408
|
-
this.debugCursor = new DebugEntityCursor(this.stage.scene.scene);
|
|
2409
|
-
}
|
|
2410
|
-
this.attachDomListeners();
|
|
2411
2877
|
}
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
this.raycaster.setFromCamera(this.mouseNdc, cameraRef.camera);
|
|
2424
|
-
const origin = this.raycaster.ray.origin.clone();
|
|
2425
|
-
const direction = this.raycaster.ray.direction.clone().normalize();
|
|
2426
|
-
const rapierRay = new Ray(
|
|
2427
|
-
{ x: origin.x, y: origin.y, z: origin.z },
|
|
2428
|
-
{ x: direction.x, y: direction.y, z: direction.z }
|
|
2429
|
-
);
|
|
2430
|
-
const hit = world.world.castRay(rapierRay, this.options.maxRayDistance, true);
|
|
2431
|
-
if (hit && isCursorTool) {
|
|
2432
|
-
const rigidBody = hit.collider?._parent;
|
|
2433
|
-
const hoveredUuid2 = rigidBody?.userData?.uuid;
|
|
2434
|
-
if (hoveredUuid2) {
|
|
2435
|
-
const entity = this.stage._debugMap.get(hoveredUuid2);
|
|
2436
|
-
if (entity) setHoveredEntity(entity);
|
|
2437
|
-
} else {
|
|
2438
|
-
resetHoveredEntity();
|
|
2439
|
-
}
|
|
2440
|
-
if (this.isMouseDown) {
|
|
2441
|
-
this.handleActionOnHit(hoveredUuid2 ?? null, origin, direction, hit.toi);
|
|
2878
|
+
/**
|
|
2879
|
+
* Emit a loading event to all subscribers and to the game event bus.
|
|
2880
|
+
*
|
|
2881
|
+
* @param event The loading event to broadcast
|
|
2882
|
+
*/
|
|
2883
|
+
emit(event) {
|
|
2884
|
+
for (const handler of this.loadingHandlers) {
|
|
2885
|
+
try {
|
|
2886
|
+
handler(event);
|
|
2887
|
+
} catch (e) {
|
|
2888
|
+
console.error("Loading handler failed", e);
|
|
2442
2889
|
}
|
|
2443
2890
|
}
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
this.
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
}
|
|
2456
|
-
switch (tool) {
|
|
2457
|
-
case "select":
|
|
2458
|
-
this.debugCursor?.setColor(SELECT_TOOL_COLOR);
|
|
2459
|
-
break;
|
|
2460
|
-
case "delete":
|
|
2461
|
-
this.debugCursor?.setColor(DELETE_TOOL_COLOR);
|
|
2462
|
-
break;
|
|
2463
|
-
default:
|
|
2464
|
-
this.debugCursor?.setColor(16777215);
|
|
2465
|
-
break;
|
|
2891
|
+
const payload = {
|
|
2892
|
+
...event,
|
|
2893
|
+
stageName: this.stageName,
|
|
2894
|
+
stageIndex: this.stageIndex
|
|
2895
|
+
};
|
|
2896
|
+
if (event.type === "start") {
|
|
2897
|
+
gameEventBus.emit("stage:loading:start", payload);
|
|
2898
|
+
} else if (event.type === "progress") {
|
|
2899
|
+
gameEventBus.emit("stage:loading:progress", payload);
|
|
2900
|
+
} else if (event.type === "complete") {
|
|
2901
|
+
gameEventBus.emit("stage:loading:complete", payload);
|
|
2466
2902
|
}
|
|
2467
|
-
this.debugCursor?.updateFromObject(targetObject);
|
|
2468
2903
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
this.stage.scene.scene.remove(this.debugLines);
|
|
2475
|
-
this.debugLines.geometry.dispose();
|
|
2476
|
-
this.debugLines.material.dispose();
|
|
2477
|
-
this.debugLines = null;
|
|
2478
|
-
}
|
|
2904
|
+
/**
|
|
2905
|
+
* Emit a start loading event.
|
|
2906
|
+
*/
|
|
2907
|
+
emitStart(message = "Loading stage...") {
|
|
2908
|
+
this.emit({ type: "start", message, progress: 0 });
|
|
2479
2909
|
}
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
if (entity) setSelectedEntity(entity);
|
|
2487
|
-
}
|
|
2488
|
-
break;
|
|
2489
|
-
}
|
|
2490
|
-
case "delete": {
|
|
2491
|
-
if (hoveredUuid) {
|
|
2492
|
-
this.stage.removeEntityByUuid(hoveredUuid);
|
|
2493
|
-
}
|
|
2494
|
-
break;
|
|
2495
|
-
}
|
|
2496
|
-
case "scale": {
|
|
2497
|
-
if (!this.options.addEntityFactory) break;
|
|
2498
|
-
const hitPosition = origin.clone().add(direction.clone().multiplyScalar(toi));
|
|
2499
|
-
const newNode = this.options.addEntityFactory({ position: hitPosition });
|
|
2500
|
-
if (newNode) {
|
|
2501
|
-
Promise.resolve(newNode).then((node) => {
|
|
2502
|
-
if (node) this.stage.spawnEntity(node);
|
|
2503
|
-
}).catch(() => {
|
|
2504
|
-
});
|
|
2505
|
-
}
|
|
2506
|
-
break;
|
|
2507
|
-
}
|
|
2508
|
-
default:
|
|
2509
|
-
break;
|
|
2510
|
-
}
|
|
2910
|
+
/**
|
|
2911
|
+
* Emit a progress loading event.
|
|
2912
|
+
*/
|
|
2913
|
+
emitProgress(message, current, total) {
|
|
2914
|
+
const progress = total > 0 ? current / total : 0;
|
|
2915
|
+
this.emit({ type: "progress", message, progress, current, total });
|
|
2511
2916
|
}
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2917
|
+
/**
|
|
2918
|
+
* Emit a complete loading event.
|
|
2919
|
+
*/
|
|
2920
|
+
emitComplete(message = "Stage loaded") {
|
|
2921
|
+
this.emit({ type: "complete", message, progress: 1 });
|
|
2922
|
+
}
|
|
2923
|
+
/**
|
|
2924
|
+
* Clear all loading handlers.
|
|
2925
|
+
*/
|
|
2926
|
+
dispose() {
|
|
2927
|
+
this.loadingHandlers = [];
|
|
2928
|
+
}
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
});
|
|
2932
|
+
|
|
2933
|
+
// src/lib/core/utility/options-parser.ts
|
|
2934
|
+
function isBaseNode(item) {
|
|
2935
|
+
return !!item && typeof item === "object" && typeof item.create === "function";
|
|
2936
|
+
}
|
|
2937
|
+
function isThenable(item) {
|
|
2938
|
+
return !!item && typeof item.then === "function";
|
|
2939
|
+
}
|
|
2940
|
+
function isCameraWrapper(item) {
|
|
2941
|
+
return !!item && typeof item === "object" && item.constructor?.name === "CameraWrapper";
|
|
2942
|
+
}
|
|
2943
|
+
function isConfigObject(item) {
|
|
2944
|
+
if (!item || typeof item !== "object") return false;
|
|
2945
|
+
if (isBaseNode(item)) return false;
|
|
2946
|
+
if (isCameraWrapper(item)) return false;
|
|
2947
|
+
if (isThenable(item)) return false;
|
|
2948
|
+
if (typeof item.then === "function") return false;
|
|
2949
|
+
return item.constructor === Object || item.constructor?.name === "Object";
|
|
2950
|
+
}
|
|
2951
|
+
function isEntityInput(item) {
|
|
2952
|
+
if (!item) return false;
|
|
2953
|
+
if (isBaseNode(item)) return true;
|
|
2954
|
+
if (typeof item === "function") return true;
|
|
2955
|
+
if (isThenable(item)) return true;
|
|
2956
|
+
return false;
|
|
2957
|
+
}
|
|
2958
|
+
var init_options_parser = __esm({
|
|
2959
|
+
"src/lib/core/utility/options-parser.ts"() {
|
|
2960
|
+
"use strict";
|
|
2961
|
+
}
|
|
2962
|
+
});
|
|
2963
|
+
|
|
2964
|
+
// src/lib/stage/stage-config.ts
|
|
2965
|
+
import { Vector3 as Vector312 } from "three";
|
|
2966
|
+
function createDefaultStageConfig() {
|
|
2967
|
+
return new StageConfig(
|
|
2968
|
+
{
|
|
2969
|
+
p1: ["gamepad-1", "keyboard-1"],
|
|
2970
|
+
p2: ["gamepad-2", "keyboard-2"]
|
|
2971
|
+
},
|
|
2972
|
+
ZylemBlueColor,
|
|
2973
|
+
null,
|
|
2974
|
+
new Vector312(0, 0, 0),
|
|
2975
|
+
{}
|
|
2976
|
+
);
|
|
2977
|
+
}
|
|
2978
|
+
function parseStageOptions(options = []) {
|
|
2979
|
+
const defaults = createDefaultStageConfig();
|
|
2980
|
+
let config = {};
|
|
2981
|
+
const entities = [];
|
|
2982
|
+
const asyncEntities = [];
|
|
2983
|
+
let camera2;
|
|
2984
|
+
for (const item of options) {
|
|
2985
|
+
if (isCameraWrapper(item)) {
|
|
2986
|
+
camera2 = item;
|
|
2987
|
+
} else if (isBaseNode(item)) {
|
|
2988
|
+
entities.push(item);
|
|
2989
|
+
} else if (isEntityInput(item) && !isBaseNode(item)) {
|
|
2990
|
+
asyncEntities.push(item);
|
|
2991
|
+
} else if (isConfigObject(item)) {
|
|
2992
|
+
config = { ...config, ...item };
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
const resolvedConfig = new StageConfig(
|
|
2996
|
+
config.inputs ?? defaults.inputs,
|
|
2997
|
+
config.backgroundColor ?? defaults.backgroundColor,
|
|
2998
|
+
config.backgroundImage ?? defaults.backgroundImage,
|
|
2999
|
+
config.gravity ?? defaults.gravity,
|
|
3000
|
+
config.variables ?? defaults.variables
|
|
3001
|
+
);
|
|
3002
|
+
return { config: resolvedConfig, entities, asyncEntities, camera: camera2 };
|
|
3003
|
+
}
|
|
3004
|
+
var StageConfig;
|
|
3005
|
+
var init_stage_config = __esm({
|
|
3006
|
+
"src/lib/stage/stage-config.ts"() {
|
|
3007
|
+
"use strict";
|
|
3008
|
+
init_options_parser();
|
|
3009
|
+
init_vector();
|
|
3010
|
+
StageConfig = class {
|
|
3011
|
+
constructor(inputs, backgroundColor, backgroundImage, gravity, variables) {
|
|
3012
|
+
this.inputs = inputs;
|
|
3013
|
+
this.backgroundColor = backgroundColor;
|
|
3014
|
+
this.backgroundImage = backgroundImage;
|
|
3015
|
+
this.gravity = gravity;
|
|
3016
|
+
this.variables = variables;
|
|
2528
3017
|
}
|
|
2529
3018
|
};
|
|
2530
3019
|
}
|
|
@@ -2532,7 +3021,8 @@ var init_stage_debug_delegate = __esm({
|
|
|
2532
3021
|
|
|
2533
3022
|
// src/lib/stage/zylem-stage.ts
|
|
2534
3023
|
import { addComponent, addEntity, createWorld as createECS, removeEntity } from "bitecs";
|
|
2535
|
-
import { Color as
|
|
3024
|
+
import { Color as Color9, Vector3 as Vector313 } from "three";
|
|
3025
|
+
import { subscribe as subscribe5 } from "valtio/vanilla";
|
|
2536
3026
|
import { nanoid as nanoid2 } from "nanoid";
|
|
2537
3027
|
var STAGE_TYPE, ZylemStage;
|
|
2538
3028
|
var init_zylem_stage = __esm({
|
|
@@ -2546,12 +3036,13 @@ var init_zylem_stage = __esm({
|
|
|
2546
3036
|
init_game_state();
|
|
2547
3037
|
init_lifecycle_base();
|
|
2548
3038
|
init_transformable_system();
|
|
2549
|
-
init_base_node();
|
|
2550
|
-
init_perspective();
|
|
2551
|
-
init_camera();
|
|
2552
3039
|
init_stage_debug_delegate();
|
|
3040
|
+
init_stage_camera_debug_delegate();
|
|
3041
|
+
init_stage_camera_delegate();
|
|
3042
|
+
init_stage_loading_delegate();
|
|
2553
3043
|
init_entity();
|
|
2554
|
-
|
|
3044
|
+
init_stage_config();
|
|
3045
|
+
init_options_parser();
|
|
2555
3046
|
STAGE_TYPE = "Stage";
|
|
2556
3047
|
ZylemStage = class extends LifeCycleBase {
|
|
2557
3048
|
type = STAGE_TYPE;
|
|
@@ -2562,7 +3053,7 @@ var init_zylem_stage = __esm({
|
|
|
2562
3053
|
p1: ["gamepad-1", "keyboard"],
|
|
2563
3054
|
p2: ["gamepad-2", "keyboard"]
|
|
2564
3055
|
},
|
|
2565
|
-
gravity: new
|
|
3056
|
+
gravity: new Vector313(0, 0, 0),
|
|
2566
3057
|
variables: {},
|
|
2567
3058
|
entities: []
|
|
2568
3059
|
};
|
|
@@ -2577,16 +3068,19 @@ var init_zylem_stage = __esm({
|
|
|
2577
3068
|
isLoaded = false;
|
|
2578
3069
|
_debugMap = /* @__PURE__ */ new Map();
|
|
2579
3070
|
entityAddedHandlers = [];
|
|
2580
|
-
loadingHandlers = [];
|
|
2581
3071
|
ecs = createECS();
|
|
2582
3072
|
testSystem = null;
|
|
2583
3073
|
transformSystem = null;
|
|
2584
3074
|
debugDelegate = null;
|
|
2585
3075
|
cameraDebugDelegate = null;
|
|
3076
|
+
debugStateUnsubscribe = null;
|
|
2586
3077
|
uuid;
|
|
2587
3078
|
wrapperRef = null;
|
|
2588
3079
|
camera;
|
|
2589
3080
|
cameraRef = null;
|
|
3081
|
+
// Delegates
|
|
3082
|
+
cameraDelegate;
|
|
3083
|
+
loadingDelegate;
|
|
2590
3084
|
/**
|
|
2591
3085
|
* Create a new stage.
|
|
2592
3086
|
* @param options Stage options: partial config, camera, and initial entities or factories
|
|
@@ -2596,49 +3090,22 @@ var init_zylem_stage = __esm({
|
|
|
2596
3090
|
this.world = null;
|
|
2597
3091
|
this.scene = null;
|
|
2598
3092
|
this.uuid = nanoid2();
|
|
2599
|
-
|
|
2600
|
-
this.
|
|
2601
|
-
|
|
2602
|
-
this.
|
|
2603
|
-
this.
|
|
2604
|
-
this.
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
entities.push(item);
|
|
2616
|
-
} else if (this.isEntityInput(item)) {
|
|
2617
|
-
asyncEntities.push(item);
|
|
2618
|
-
} else if (this.isZylemStageConfig(item)) {
|
|
2619
|
-
config = { ...config, ...item };
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
return { config, entities, asyncEntities, camera: camera2 };
|
|
2623
|
-
}
|
|
2624
|
-
isZylemStageConfig(item) {
|
|
2625
|
-
return item && typeof item === "object" && !(item instanceof BaseNode) && !(item instanceof CameraWrapper);
|
|
2626
|
-
}
|
|
2627
|
-
isBaseNode(item) {
|
|
2628
|
-
return item && typeof item === "object" && typeof item.create === "function";
|
|
2629
|
-
}
|
|
2630
|
-
isCameraWrapper(item) {
|
|
2631
|
-
return item && typeof item === "object" && item.constructor.name === "CameraWrapper";
|
|
2632
|
-
}
|
|
2633
|
-
isEntityInput(item) {
|
|
2634
|
-
if (!item) return false;
|
|
2635
|
-
if (this.isBaseNode(item)) return true;
|
|
2636
|
-
if (typeof item === "function") return true;
|
|
2637
|
-
if (typeof item === "object" && typeof item.then === "function") return true;
|
|
2638
|
-
return false;
|
|
2639
|
-
}
|
|
2640
|
-
isThenable(value) {
|
|
2641
|
-
return !!value && typeof value.then === "function";
|
|
3093
|
+
this.cameraDelegate = new StageCameraDelegate(this);
|
|
3094
|
+
this.loadingDelegate = new StageLoadingDelegate();
|
|
3095
|
+
const parsed = parseStageOptions(options);
|
|
3096
|
+
this.camera = parsed.camera;
|
|
3097
|
+
this.children = parsed.entities;
|
|
3098
|
+
this.pendingEntities = parsed.asyncEntities;
|
|
3099
|
+
this.saveState({
|
|
3100
|
+
...this.state,
|
|
3101
|
+
inputs: parsed.config.inputs,
|
|
3102
|
+
backgroundColor: parsed.config.backgroundColor,
|
|
3103
|
+
backgroundImage: parsed.config.backgroundImage,
|
|
3104
|
+
gravity: parsed.config.gravity,
|
|
3105
|
+
variables: parsed.config.variables,
|
|
3106
|
+
entities: []
|
|
3107
|
+
});
|
|
3108
|
+
this.gravity = parsed.config.gravity ?? new Vector313(0, 0, 0);
|
|
2642
3109
|
}
|
|
2643
3110
|
handleEntityImmediatelyOrQueue(entity) {
|
|
2644
3111
|
if (this.isLoaded) {
|
|
@@ -2659,42 +3126,47 @@ var init_zylem_stage = __esm({
|
|
|
2659
3126
|
}
|
|
2660
3127
|
setState() {
|
|
2661
3128
|
const { backgroundColor, backgroundImage } = this.state;
|
|
2662
|
-
const color = backgroundColor instanceof
|
|
3129
|
+
const color = backgroundColor instanceof Color9 ? backgroundColor : new Color9(backgroundColor);
|
|
2663
3130
|
setStageBackgroundColor(color);
|
|
2664
3131
|
setStageBackgroundImage(backgroundImage);
|
|
2665
3132
|
setStageVariables(this.state.variables ?? {});
|
|
2666
3133
|
}
|
|
2667
3134
|
/**
|
|
2668
3135
|
* Load and initialize the stage's scene and world.
|
|
3136
|
+
* Uses generator pattern to yield control to event loop for real-time progress.
|
|
2669
3137
|
* @param id DOM element id for the renderer container
|
|
2670
3138
|
* @param camera Optional camera override
|
|
2671
3139
|
*/
|
|
2672
3140
|
async load(id, camera2) {
|
|
2673
3141
|
this.setState();
|
|
2674
|
-
const zylemCamera =
|
|
3142
|
+
const zylemCamera = this.cameraDelegate.resolveCamera(camera2, this.camera);
|
|
2675
3143
|
this.cameraRef = zylemCamera;
|
|
2676
3144
|
this.scene = new ZylemScene(id, zylemCamera, this.state);
|
|
2677
|
-
const physicsWorld = await ZylemWorld.loadPhysics(this.gravity ?? new
|
|
3145
|
+
const physicsWorld = await ZylemWorld.loadPhysics(this.gravity ?? new Vector313(0, 0, 0));
|
|
2678
3146
|
this.world = new ZylemWorld(physicsWorld);
|
|
2679
3147
|
this.scene.setup();
|
|
2680
|
-
this.
|
|
3148
|
+
this.loadingDelegate.emitStart();
|
|
3149
|
+
await this.runEntityLoadGenerator();
|
|
3150
|
+
this.transformSystem = createTransformSystem(this);
|
|
3151
|
+
this.isLoaded = true;
|
|
3152
|
+
this.loadingDelegate.emitComplete();
|
|
3153
|
+
}
|
|
3154
|
+
/**
|
|
3155
|
+
* Generator that yields between entity loads for real-time progress updates.
|
|
3156
|
+
*/
|
|
3157
|
+
*entityLoadGenerator() {
|
|
2681
3158
|
const total = this.children.length + this.pendingEntities.length + this.pendingPromises.length;
|
|
2682
3159
|
let current = 0;
|
|
2683
|
-
for (
|
|
3160
|
+
for (const child of this.children) {
|
|
2684
3161
|
this.spawnEntity(child);
|
|
2685
3162
|
current++;
|
|
2686
|
-
|
|
2687
|
-
type: "progress",
|
|
2688
|
-
message: `Loaded entity ${child.name || "unknown"}`,
|
|
2689
|
-
progress: current / total,
|
|
2690
|
-
current,
|
|
2691
|
-
total
|
|
2692
|
-
});
|
|
3163
|
+
yield { current, total, name: child.name || "unknown" };
|
|
2693
3164
|
}
|
|
2694
3165
|
if (this.pendingEntities.length) {
|
|
2695
3166
|
this.enqueue(...this.pendingEntities);
|
|
2696
3167
|
current += this.pendingEntities.length;
|
|
2697
3168
|
this.pendingEntities = [];
|
|
3169
|
+
yield { current, total, name: "pending entities" };
|
|
2698
3170
|
}
|
|
2699
3171
|
if (this.pendingPromises.length) {
|
|
2700
3172
|
for (const promise of this.pendingPromises) {
|
|
@@ -2704,24 +3176,44 @@ var init_zylem_stage = __esm({
|
|
|
2704
3176
|
}
|
|
2705
3177
|
current += this.pendingPromises.length;
|
|
2706
3178
|
this.pendingPromises = [];
|
|
3179
|
+
yield { current, total, name: "async entities" };
|
|
2707
3180
|
}
|
|
2708
|
-
this.transformSystem = createTransformSystem(this);
|
|
2709
|
-
this.isLoaded = true;
|
|
2710
|
-
this.emitLoading({ type: "complete", message: "Stage loaded", progress: 1 });
|
|
2711
3181
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
3182
|
+
/**
|
|
3183
|
+
* Runs the entity load generator, yielding to the event loop between loads.
|
|
3184
|
+
* This allows the browser to process events and update the UI in real-time.
|
|
3185
|
+
*/
|
|
3186
|
+
async runEntityLoadGenerator() {
|
|
3187
|
+
const gen = this.entityLoadGenerator();
|
|
3188
|
+
for (const progress of gen) {
|
|
3189
|
+
this.loadingDelegate.emitProgress(`Loaded ${progress.name}`, progress.current, progress.total);
|
|
3190
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
3191
|
+
}
|
|
2717
3192
|
}
|
|
2718
3193
|
_setup(params) {
|
|
2719
3194
|
if (!this.scene || !this.world) {
|
|
2720
3195
|
this.logMissingEntities();
|
|
2721
3196
|
return;
|
|
2722
3197
|
}
|
|
2723
|
-
|
|
3198
|
+
this.updateDebugDelegate();
|
|
3199
|
+
this.debugStateUnsubscribe = subscribe5(debugState, () => {
|
|
3200
|
+
this.updateDebugDelegate();
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
updateDebugDelegate() {
|
|
3204
|
+
if (debugState.enabled && !this.debugDelegate && this.scene && this.world) {
|
|
2724
3205
|
this.debugDelegate = new StageDebugDelegate(this);
|
|
3206
|
+
if (this.cameraRef && !this.cameraDebugDelegate) {
|
|
3207
|
+
this.cameraDebugDelegate = new StageCameraDebugDelegate(this);
|
|
3208
|
+
this.cameraRef.setDebugDelegate(this.cameraDebugDelegate);
|
|
3209
|
+
}
|
|
3210
|
+
} else if (!debugState.enabled && this.debugDelegate) {
|
|
3211
|
+
this.debugDelegate.dispose();
|
|
3212
|
+
this.debugDelegate = null;
|
|
3213
|
+
if (this.cameraRef) {
|
|
3214
|
+
this.cameraRef.setDebugDelegate(null);
|
|
3215
|
+
}
|
|
3216
|
+
this.cameraDebugDelegate = null;
|
|
2725
3217
|
}
|
|
2726
3218
|
}
|
|
2727
3219
|
_update(params) {
|
|
@@ -2731,7 +3223,7 @@ var init_zylem_stage = __esm({
|
|
|
2731
3223
|
return;
|
|
2732
3224
|
}
|
|
2733
3225
|
this.world.update(params);
|
|
2734
|
-
this.transformSystem(this.ecs);
|
|
3226
|
+
this.transformSystem?.system(this.ecs);
|
|
2735
3227
|
this._childrenMap.forEach((child, eid) => {
|
|
2736
3228
|
child.nodeUpdate({
|
|
2737
3229
|
...params,
|
|
@@ -2765,13 +3257,20 @@ var init_zylem_stage = __esm({
|
|
|
2765
3257
|
this._debugMap.clear();
|
|
2766
3258
|
this.world?.destroy();
|
|
2767
3259
|
this.scene?.destroy();
|
|
3260
|
+
if (this.debugStateUnsubscribe) {
|
|
3261
|
+
this.debugStateUnsubscribe();
|
|
3262
|
+
this.debugStateUnsubscribe = null;
|
|
3263
|
+
}
|
|
2768
3264
|
this.debugDelegate?.dispose();
|
|
3265
|
+
this.debugDelegate = null;
|
|
2769
3266
|
this.cameraRef?.setDebugDelegate(null);
|
|
2770
3267
|
this.cameraDebugDelegate = null;
|
|
2771
3268
|
this.isLoaded = false;
|
|
2772
3269
|
this.world = null;
|
|
2773
3270
|
this.scene = null;
|
|
2774
3271
|
this.cameraRef = null;
|
|
3272
|
+
this.transformSystem?.destroy(this.ecs);
|
|
3273
|
+
this.transformSystem = null;
|
|
2775
3274
|
resetStageVariables();
|
|
2776
3275
|
clearVariables(this);
|
|
2777
3276
|
}
|
|
@@ -2852,13 +3351,7 @@ var init_zylem_stage = __esm({
|
|
|
2852
3351
|
};
|
|
2853
3352
|
}
|
|
2854
3353
|
onLoading(callback) {
|
|
2855
|
-
this.
|
|
2856
|
-
return () => {
|
|
2857
|
-
this.loadingHandlers = this.loadingHandlers.filter((h) => h !== callback);
|
|
2858
|
-
};
|
|
2859
|
-
}
|
|
2860
|
-
emitLoading(event) {
|
|
2861
|
-
this.loadingHandlers.forEach((h) => h(event));
|
|
3354
|
+
return this.loadingDelegate.onLoading(callback);
|
|
2862
3355
|
}
|
|
2863
3356
|
/**
|
|
2864
3357
|
* Remove an entity and its resources by its UUID.
|
|
@@ -2915,16 +3408,16 @@ var init_zylem_stage = __esm({
|
|
|
2915
3408
|
enqueue(...items) {
|
|
2916
3409
|
for (const item of items) {
|
|
2917
3410
|
if (!item) continue;
|
|
2918
|
-
if (
|
|
3411
|
+
if (isBaseNode(item)) {
|
|
2919
3412
|
this.handleEntityImmediatelyOrQueue(item);
|
|
2920
3413
|
continue;
|
|
2921
3414
|
}
|
|
2922
3415
|
if (typeof item === "function") {
|
|
2923
3416
|
try {
|
|
2924
3417
|
const result = item();
|
|
2925
|
-
if (
|
|
3418
|
+
if (isBaseNode(result)) {
|
|
2926
3419
|
this.handleEntityImmediatelyOrQueue(result);
|
|
2927
|
-
} else if (
|
|
3420
|
+
} else if (isThenable(result)) {
|
|
2928
3421
|
this.handlePromiseWithSpawnOnResolve(result);
|
|
2929
3422
|
}
|
|
2930
3423
|
} catch (error) {
|
|
@@ -2932,7 +3425,7 @@ var init_zylem_stage = __esm({
|
|
|
2932
3425
|
}
|
|
2933
3426
|
continue;
|
|
2934
3427
|
}
|
|
2935
|
-
if (
|
|
3428
|
+
if (isThenable(item)) {
|
|
2936
3429
|
this.handlePromiseWithSpawnOnResolve(item);
|
|
2937
3430
|
}
|
|
2938
3431
|
}
|
|
@@ -2941,9 +3434,36 @@ var init_zylem_stage = __esm({
|
|
|
2941
3434
|
}
|
|
2942
3435
|
});
|
|
2943
3436
|
|
|
3437
|
+
// src/lib/camera/camera.ts
|
|
3438
|
+
import { Vector2 as Vector27, Vector3 as Vector314 } from "three";
|
|
3439
|
+
function camera(options) {
|
|
3440
|
+
const screenResolution = options.screenResolution || new Vector27(window.innerWidth, window.innerHeight);
|
|
3441
|
+
let frustumSize = 10;
|
|
3442
|
+
if (options.perspective === "fixed-2d") {
|
|
3443
|
+
frustumSize = options.zoom || 10;
|
|
3444
|
+
}
|
|
3445
|
+
const zylemCamera = new ZylemCamera(options.perspective || "third-person", screenResolution, frustumSize);
|
|
3446
|
+
zylemCamera.move(options.position || new Vector314(0, 0, 0));
|
|
3447
|
+
zylemCamera.camera.lookAt(options.target || new Vector314(0, 0, 0));
|
|
3448
|
+
return new CameraWrapper(zylemCamera);
|
|
3449
|
+
}
|
|
3450
|
+
var CameraWrapper;
|
|
3451
|
+
var init_camera = __esm({
|
|
3452
|
+
"src/lib/camera/camera.ts"() {
|
|
3453
|
+
"use strict";
|
|
3454
|
+
init_zylem_camera();
|
|
3455
|
+
CameraWrapper = class {
|
|
3456
|
+
cameraRef;
|
|
3457
|
+
constructor(camera2) {
|
|
3458
|
+
this.cameraRef = camera2;
|
|
3459
|
+
}
|
|
3460
|
+
};
|
|
3461
|
+
}
|
|
3462
|
+
});
|
|
3463
|
+
|
|
2944
3464
|
// src/lib/stage/stage-default.ts
|
|
2945
3465
|
import { proxy as proxy4 } from "valtio/vanilla";
|
|
2946
|
-
import { Vector3 as
|
|
3466
|
+
import { Vector3 as Vector315 } from "three";
|
|
2947
3467
|
function getStageOptions(options) {
|
|
2948
3468
|
const defaults = getStageDefaultConfig();
|
|
2949
3469
|
let originalConfig = {};
|
|
@@ -2974,7 +3494,7 @@ var init_stage_default = __esm({
|
|
|
2974
3494
|
p1: ["gamepad-1", "keyboard"],
|
|
2975
3495
|
p2: ["gamepad-2", "keyboard"]
|
|
2976
3496
|
},
|
|
2977
|
-
gravity: new
|
|
3497
|
+
gravity: new Vector315(0, 0, 0),
|
|
2978
3498
|
variables: {}
|
|
2979
3499
|
};
|
|
2980
3500
|
stageDefaultsState = proxy4({
|
|
@@ -2999,30 +3519,58 @@ var init_stage = __esm({
|
|
|
2999
3519
|
Stage = class {
|
|
3000
3520
|
wrappedStage;
|
|
3001
3521
|
options = [];
|
|
3002
|
-
//
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3522
|
+
// Entities added after construction, consumed on each load
|
|
3523
|
+
_pendingEntities = [];
|
|
3524
|
+
// Lifecycle callback arrays
|
|
3525
|
+
setupCallbacks = [];
|
|
3526
|
+
updateCallbacks = [];
|
|
3527
|
+
destroyCallbacks = [];
|
|
3528
|
+
pendingLoadingCallbacks = [];
|
|
3009
3529
|
constructor(options) {
|
|
3010
3530
|
this.options = options;
|
|
3011
3531
|
this.wrappedStage = null;
|
|
3012
3532
|
}
|
|
3013
3533
|
async load(id, camera2) {
|
|
3014
3534
|
stageState.entities = [];
|
|
3015
|
-
|
|
3535
|
+
const loadOptions = [...this.options, ...this._pendingEntities];
|
|
3536
|
+
this._pendingEntities = [];
|
|
3537
|
+
this.wrappedStage = new ZylemStage(loadOptions);
|
|
3016
3538
|
this.wrappedStage.wrapperRef = this;
|
|
3539
|
+
this.pendingLoadingCallbacks.forEach((cb) => {
|
|
3540
|
+
this.wrappedStage.onLoading(cb);
|
|
3541
|
+
});
|
|
3542
|
+
this.pendingLoadingCallbacks = [];
|
|
3017
3543
|
const zylemCamera = camera2 instanceof CameraWrapper ? camera2.cameraRef : camera2;
|
|
3018
3544
|
await this.wrappedStage.load(id, zylemCamera);
|
|
3019
3545
|
this.wrappedStage.onEntityAdded((child) => {
|
|
3020
3546
|
const next = this.wrappedStage.buildEntityState(child);
|
|
3021
3547
|
stageState.entities = [...stageState.entities, next];
|
|
3022
3548
|
}, { replayExisting: true });
|
|
3549
|
+
this.applyLifecycleCallbacks();
|
|
3550
|
+
}
|
|
3551
|
+
applyLifecycleCallbacks() {
|
|
3552
|
+
if (!this.wrappedStage) return;
|
|
3553
|
+
if (this.setupCallbacks.length > 0) {
|
|
3554
|
+
this.wrappedStage.setup = (params) => {
|
|
3555
|
+
const extended = { ...params, stage: this };
|
|
3556
|
+
this.setupCallbacks.forEach((cb) => cb(extended));
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
if (this.updateCallbacks.length > 0) {
|
|
3560
|
+
this.wrappedStage.update = (params) => {
|
|
3561
|
+
const extended = { ...params, stage: this };
|
|
3562
|
+
this.updateCallbacks.forEach((cb) => cb(extended));
|
|
3563
|
+
};
|
|
3564
|
+
}
|
|
3565
|
+
if (this.destroyCallbacks.length > 0) {
|
|
3566
|
+
this.wrappedStage.destroy = (params) => {
|
|
3567
|
+
const extended = { ...params, stage: this };
|
|
3568
|
+
this.destroyCallbacks.forEach((cb) => cb(extended));
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3023
3571
|
}
|
|
3024
3572
|
async addEntities(entities) {
|
|
3025
|
-
this.
|
|
3573
|
+
this._pendingEntities.push(...entities);
|
|
3026
3574
|
if (!this.wrappedStage) {
|
|
3027
3575
|
return;
|
|
3028
3576
|
}
|
|
@@ -3047,28 +3595,57 @@ var init_stage = __esm({
|
|
|
3047
3595
|
start(params) {
|
|
3048
3596
|
this.wrappedStage?.nodeSetup(params);
|
|
3049
3597
|
}
|
|
3598
|
+
// Fluent API for adding lifecycle callbacks
|
|
3050
3599
|
onUpdate(...callbacks) {
|
|
3051
|
-
|
|
3052
|
-
|
|
3600
|
+
this.updateCallbacks.push(...callbacks);
|
|
3601
|
+
if (this.wrappedStage) {
|
|
3602
|
+
this.wrappedStage.update = (params) => {
|
|
3603
|
+
const extended = { ...params, stage: this };
|
|
3604
|
+
this.updateCallbacks.forEach((cb) => cb(extended));
|
|
3605
|
+
};
|
|
3053
3606
|
}
|
|
3054
|
-
this
|
|
3055
|
-
const extended = { ...params, stage: this };
|
|
3056
|
-
callbacks.forEach((cb) => cb(extended));
|
|
3057
|
-
};
|
|
3607
|
+
return this;
|
|
3058
3608
|
}
|
|
3059
|
-
onSetup(
|
|
3060
|
-
this.
|
|
3609
|
+
onSetup(...callbacks) {
|
|
3610
|
+
this.setupCallbacks.push(...callbacks);
|
|
3611
|
+
if (this.wrappedStage) {
|
|
3612
|
+
this.wrappedStage.setup = (params) => {
|
|
3613
|
+
const extended = { ...params, stage: this };
|
|
3614
|
+
this.setupCallbacks.forEach((cb) => cb(extended));
|
|
3615
|
+
};
|
|
3616
|
+
}
|
|
3617
|
+
return this;
|
|
3061
3618
|
}
|
|
3062
|
-
onDestroy(
|
|
3063
|
-
this.
|
|
3619
|
+
onDestroy(...callbacks) {
|
|
3620
|
+
this.destroyCallbacks.push(...callbacks);
|
|
3621
|
+
if (this.wrappedStage) {
|
|
3622
|
+
this.wrappedStage.destroy = (params) => {
|
|
3623
|
+
const extended = { ...params, stage: this };
|
|
3624
|
+
this.destroyCallbacks.forEach((cb) => cb(extended));
|
|
3625
|
+
};
|
|
3626
|
+
}
|
|
3627
|
+
return this;
|
|
3064
3628
|
}
|
|
3065
3629
|
onLoading(callback) {
|
|
3066
3630
|
if (!this.wrappedStage) {
|
|
3631
|
+
this.pendingLoadingCallbacks.push(callback);
|
|
3067
3632
|
return () => {
|
|
3633
|
+
this.pendingLoadingCallbacks = this.pendingLoadingCallbacks.filter((c) => c !== callback);
|
|
3068
3634
|
};
|
|
3069
3635
|
}
|
|
3070
3636
|
return this.wrappedStage.onLoading(callback);
|
|
3071
3637
|
}
|
|
3638
|
+
/**
|
|
3639
|
+
* Find an entity by name on the current stage.
|
|
3640
|
+
* @param name The name of the entity to find
|
|
3641
|
+
* @param type Optional type symbol for type inference (e.g., TEXT_TYPE, SPRITE_TYPE)
|
|
3642
|
+
* @returns The entity if found, or undefined
|
|
3643
|
+
* @example stage.getEntityByName('scoreText', TEXT_TYPE)
|
|
3644
|
+
*/
|
|
3645
|
+
getEntityByName(name, type) {
|
|
3646
|
+
const entity = this.wrappedStage?.children.find((c) => c.name === name);
|
|
3647
|
+
return entity;
|
|
3648
|
+
}
|
|
3072
3649
|
};
|
|
3073
3650
|
}
|
|
3074
3651
|
});
|
|
@@ -3909,8 +4486,202 @@ var GameCanvas = class {
|
|
|
3909
4486
|
}
|
|
3910
4487
|
};
|
|
3911
4488
|
|
|
3912
|
-
// src/lib/game/
|
|
4489
|
+
// src/lib/game/game-debug-delegate.ts
|
|
4490
|
+
init_debug_state();
|
|
3913
4491
|
import Stats from "stats.js";
|
|
4492
|
+
import { subscribe as subscribe2 } from "valtio/vanilla";
|
|
4493
|
+
var GameDebugDelegate = class {
|
|
4494
|
+
statsRef = null;
|
|
4495
|
+
unsubscribe = null;
|
|
4496
|
+
constructor() {
|
|
4497
|
+
this.updateDebugUI();
|
|
4498
|
+
this.unsubscribe = subscribe2(debugState, () => {
|
|
4499
|
+
this.updateDebugUI();
|
|
4500
|
+
});
|
|
4501
|
+
}
|
|
4502
|
+
/**
|
|
4503
|
+
* Called every frame - wraps stats.begin()
|
|
4504
|
+
*/
|
|
4505
|
+
begin() {
|
|
4506
|
+
this.statsRef?.begin();
|
|
4507
|
+
}
|
|
4508
|
+
/**
|
|
4509
|
+
* Called every frame - wraps stats.end()
|
|
4510
|
+
*/
|
|
4511
|
+
end() {
|
|
4512
|
+
this.statsRef?.end();
|
|
4513
|
+
}
|
|
4514
|
+
updateDebugUI() {
|
|
4515
|
+
if (debugState.enabled && !this.statsRef) {
|
|
4516
|
+
this.statsRef = new Stats();
|
|
4517
|
+
this.statsRef.showPanel(0);
|
|
4518
|
+
this.statsRef.dom.style.position = "absolute";
|
|
4519
|
+
this.statsRef.dom.style.bottom = "0";
|
|
4520
|
+
this.statsRef.dom.style.right = "0";
|
|
4521
|
+
this.statsRef.dom.style.top = "auto";
|
|
4522
|
+
this.statsRef.dom.style.left = "auto";
|
|
4523
|
+
document.body.appendChild(this.statsRef.dom);
|
|
4524
|
+
} else if (!debugState.enabled && this.statsRef) {
|
|
4525
|
+
if (this.statsRef.dom.parentNode) {
|
|
4526
|
+
this.statsRef.dom.parentNode.removeChild(this.statsRef.dom);
|
|
4527
|
+
}
|
|
4528
|
+
this.statsRef = null;
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
dispose() {
|
|
4532
|
+
if (this.unsubscribe) {
|
|
4533
|
+
this.unsubscribe();
|
|
4534
|
+
this.unsubscribe = null;
|
|
4535
|
+
}
|
|
4536
|
+
if (this.statsRef?.dom?.parentNode) {
|
|
4537
|
+
this.statsRef.dom.parentNode.removeChild(this.statsRef.dom);
|
|
4538
|
+
}
|
|
4539
|
+
this.statsRef = null;
|
|
4540
|
+
}
|
|
4541
|
+
};
|
|
4542
|
+
|
|
4543
|
+
// src/lib/game/game-loading-delegate.ts
|
|
4544
|
+
var GAME_LOADING_EVENT = "GAME_LOADING_EVENT";
|
|
4545
|
+
var GameLoadingDelegate = class {
|
|
4546
|
+
loadingHandlers = [];
|
|
4547
|
+
stageLoadingUnsubscribes = [];
|
|
4548
|
+
/**
|
|
4549
|
+
* Subscribe to loading events from the game.
|
|
4550
|
+
* Events include stage context (stageName, stageIndex).
|
|
4551
|
+
*
|
|
4552
|
+
* @param callback Invoked for each loading event
|
|
4553
|
+
* @returns Unsubscribe function
|
|
4554
|
+
*/
|
|
4555
|
+
onLoading(callback) {
|
|
4556
|
+
this.loadingHandlers.push(callback);
|
|
4557
|
+
return () => {
|
|
4558
|
+
this.loadingHandlers = this.loadingHandlers.filter((h) => h !== callback);
|
|
4559
|
+
};
|
|
4560
|
+
}
|
|
4561
|
+
/**
|
|
4562
|
+
* Emit a loading event to all subscribers and dispatch to window.
|
|
4563
|
+
*/
|
|
4564
|
+
emit(event) {
|
|
4565
|
+
for (const handler of this.loadingHandlers) {
|
|
4566
|
+
console.log("Game loading event", event);
|
|
4567
|
+
try {
|
|
4568
|
+
handler(event);
|
|
4569
|
+
} catch (e) {
|
|
4570
|
+
console.error("Game loading handler failed", e);
|
|
4571
|
+
}
|
|
4572
|
+
}
|
|
4573
|
+
if (typeof window !== "undefined") {
|
|
4574
|
+
window.dispatchEvent(new CustomEvent(GAME_LOADING_EVENT, { detail: event }));
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
/**
|
|
4578
|
+
* Wire up a stage's loading events to this delegate.
|
|
4579
|
+
*
|
|
4580
|
+
* @param stage The stage to wire up
|
|
4581
|
+
* @param stageIndex The index of the stage
|
|
4582
|
+
*/
|
|
4583
|
+
wireStageLoading(stage, stageIndex) {
|
|
4584
|
+
const unsub = stage.onLoading((event) => {
|
|
4585
|
+
this.emit({
|
|
4586
|
+
type: event.type,
|
|
4587
|
+
message: event.message ?? "",
|
|
4588
|
+
progress: event.progress ?? 0,
|
|
4589
|
+
current: event.current,
|
|
4590
|
+
total: event.total,
|
|
4591
|
+
stageName: stage.uuid ?? `Stage ${stageIndex}`,
|
|
4592
|
+
stageIndex
|
|
4593
|
+
});
|
|
4594
|
+
});
|
|
4595
|
+
if (typeof unsub === "function") {
|
|
4596
|
+
this.stageLoadingUnsubscribes.push(unsub);
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
/**
|
|
4600
|
+
* Unsubscribe from all stage loading events.
|
|
4601
|
+
*/
|
|
4602
|
+
unwireAllStages() {
|
|
4603
|
+
for (const unsub of this.stageLoadingUnsubscribes) {
|
|
4604
|
+
try {
|
|
4605
|
+
unsub();
|
|
4606
|
+
} catch {
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
this.stageLoadingUnsubscribes = [];
|
|
4610
|
+
}
|
|
4611
|
+
/**
|
|
4612
|
+
* Clean up all handlers.
|
|
4613
|
+
*/
|
|
4614
|
+
dispose() {
|
|
4615
|
+
this.unwireAllStages();
|
|
4616
|
+
this.loadingHandlers = [];
|
|
4617
|
+
}
|
|
4618
|
+
};
|
|
4619
|
+
|
|
4620
|
+
// src/lib/game/zylem-game.ts
|
|
4621
|
+
init_game_event_bus();
|
|
4622
|
+
|
|
4623
|
+
// src/lib/game/game-renderer-observer.ts
|
|
4624
|
+
var GameRendererObserver = class {
|
|
4625
|
+
container = null;
|
|
4626
|
+
camera = null;
|
|
4627
|
+
gameCanvas = null;
|
|
4628
|
+
config = null;
|
|
4629
|
+
mounted = false;
|
|
4630
|
+
setGameCanvas(canvas) {
|
|
4631
|
+
this.gameCanvas = canvas;
|
|
4632
|
+
this.tryMount();
|
|
4633
|
+
}
|
|
4634
|
+
setConfig(config) {
|
|
4635
|
+
this.config = config;
|
|
4636
|
+
this.tryMount();
|
|
4637
|
+
}
|
|
4638
|
+
setContainer(container) {
|
|
4639
|
+
this.container = container;
|
|
4640
|
+
this.tryMount();
|
|
4641
|
+
}
|
|
4642
|
+
setCamera(camera2) {
|
|
4643
|
+
this.camera = camera2;
|
|
4644
|
+
this.tryMount();
|
|
4645
|
+
}
|
|
4646
|
+
/**
|
|
4647
|
+
* Attempt to mount renderer if all dependencies are available.
|
|
4648
|
+
*/
|
|
4649
|
+
tryMount() {
|
|
4650
|
+
if (this.mounted) return;
|
|
4651
|
+
if (!this.container || !this.camera || !this.gameCanvas) return;
|
|
4652
|
+
const dom = this.camera.getDomElement();
|
|
4653
|
+
const internal = this.config?.internalResolution;
|
|
4654
|
+
this.gameCanvas.mountRenderer(dom, (cssW, cssH) => {
|
|
4655
|
+
if (!this.camera) return;
|
|
4656
|
+
if (internal) {
|
|
4657
|
+
this.camera.setPixelRatio(1);
|
|
4658
|
+
this.camera.resize(internal.width, internal.height);
|
|
4659
|
+
} else {
|
|
4660
|
+
const dpr = window.devicePixelRatio || 1;
|
|
4661
|
+
this.camera.setPixelRatio(dpr);
|
|
4662
|
+
this.camera.resize(cssW, cssH);
|
|
4663
|
+
}
|
|
4664
|
+
});
|
|
4665
|
+
this.mounted = true;
|
|
4666
|
+
}
|
|
4667
|
+
/**
|
|
4668
|
+
* Reset state for stage transitions.
|
|
4669
|
+
*/
|
|
4670
|
+
reset() {
|
|
4671
|
+
this.camera = null;
|
|
4672
|
+
this.mounted = false;
|
|
4673
|
+
}
|
|
4674
|
+
dispose() {
|
|
4675
|
+
this.container = null;
|
|
4676
|
+
this.camera = null;
|
|
4677
|
+
this.gameCanvas = null;
|
|
4678
|
+
this.config = null;
|
|
4679
|
+
this.mounted = false;
|
|
4680
|
+
}
|
|
4681
|
+
};
|
|
4682
|
+
|
|
4683
|
+
// src/lib/game/zylem-game.ts
|
|
4684
|
+
var ZYLEM_STATE_DISPATCH = "zylem:state:dispatch";
|
|
3914
4685
|
var ZylemGame = class _ZylemGame {
|
|
3915
4686
|
id;
|
|
3916
4687
|
initialGlobals = {};
|
|
@@ -3925,7 +4696,6 @@ var ZylemGame = class _ZylemGame {
|
|
|
3925
4696
|
timer;
|
|
3926
4697
|
inputManager;
|
|
3927
4698
|
wrapperRef;
|
|
3928
|
-
statsRef = null;
|
|
3929
4699
|
defaultCamera = null;
|
|
3930
4700
|
container = null;
|
|
3931
4701
|
canvas = null;
|
|
@@ -3934,6 +4704,10 @@ var ZylemGame = class _ZylemGame {
|
|
|
3934
4704
|
gameCanvas = null;
|
|
3935
4705
|
animationFrameId = null;
|
|
3936
4706
|
isDisposed = false;
|
|
4707
|
+
debugDelegate = null;
|
|
4708
|
+
loadingDelegate = new GameLoadingDelegate();
|
|
4709
|
+
rendererObserver = new GameRendererObserver();
|
|
4710
|
+
eventBusUnsubscribes = [];
|
|
3937
4711
|
static FRAME_LIMIT = 120;
|
|
3938
4712
|
static FRAME_DURATION = 1e3 / _ZylemGame.FRAME_LIMIT;
|
|
3939
4713
|
static MAX_DELTA_SECONDS = 1 / 30;
|
|
@@ -3965,42 +4739,33 @@ var ZylemGame = class _ZylemGame {
|
|
|
3965
4739
|
this.gameCanvas.applyBodyBackground();
|
|
3966
4740
|
this.gameCanvas.mountCanvas();
|
|
3967
4741
|
this.gameCanvas.centerIfFullscreen();
|
|
4742
|
+
this.rendererObserver.setGameCanvas(this.gameCanvas);
|
|
4743
|
+
if (this.resolvedConfig) {
|
|
4744
|
+
this.rendererObserver.setConfig(this.resolvedConfig);
|
|
4745
|
+
}
|
|
4746
|
+
if (this.container) {
|
|
4747
|
+
this.rendererObserver.setContainer(this.container);
|
|
4748
|
+
}
|
|
4749
|
+
this.subscribeToEventBus();
|
|
3968
4750
|
}
|
|
3969
4751
|
loadDebugOptions(options) {
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
this.statsRef = new Stats();
|
|
3973
|
-
this.statsRef.showPanel(0);
|
|
3974
|
-
this.statsRef.dom.style.position = "absolute";
|
|
3975
|
-
this.statsRef.dom.style.bottom = "0";
|
|
3976
|
-
this.statsRef.dom.style.right = "0";
|
|
3977
|
-
this.statsRef.dom.style.top = "auto";
|
|
3978
|
-
this.statsRef.dom.style.left = "auto";
|
|
3979
|
-
document.body.appendChild(this.statsRef.dom);
|
|
4752
|
+
if (options.debug !== void 0) {
|
|
4753
|
+
debugState.enabled = Boolean(options.debug);
|
|
3980
4754
|
}
|
|
4755
|
+
this.debugDelegate = new GameDebugDelegate();
|
|
3981
4756
|
}
|
|
3982
|
-
|
|
4757
|
+
loadStage(stage, stageIndex = 0) {
|
|
3983
4758
|
this.unloadCurrentStage();
|
|
3984
4759
|
const config = stage.options[0];
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
if (internal) {
|
|
3995
|
-
this.defaultCamera.setPixelRatio(1);
|
|
3996
|
-
this.defaultCamera.resize(internal.width, internal.height);
|
|
3997
|
-
} else {
|
|
3998
|
-
const dpr = window.devicePixelRatio || 1;
|
|
3999
|
-
this.defaultCamera.setPixelRatio(dpr);
|
|
4000
|
-
this.defaultCamera.resize(cssW, cssH);
|
|
4001
|
-
}
|
|
4002
|
-
});
|
|
4003
|
-
}
|
|
4760
|
+
this.loadingDelegate.wireStageLoading(stage, stageIndex);
|
|
4761
|
+
return stage.load(this.id, config?.camera).then(() => {
|
|
4762
|
+
this.stageMap.set(stage.wrappedStage.uuid, stage);
|
|
4763
|
+
this.currentStageId = stage.wrappedStage.uuid;
|
|
4764
|
+
this.defaultCamera = stage.wrappedStage.cameraRef;
|
|
4765
|
+
if (this.defaultCamera) {
|
|
4766
|
+
this.rendererObserver.setCamera(this.defaultCamera);
|
|
4767
|
+
}
|
|
4768
|
+
});
|
|
4004
4769
|
}
|
|
4005
4770
|
unloadCurrentStage() {
|
|
4006
4771
|
if (!this.currentStageId) return;
|
|
@@ -4015,8 +4780,12 @@ var ZylemGame = class _ZylemGame {
|
|
|
4015
4780
|
} catch (e) {
|
|
4016
4781
|
console.error("Failed to destroy previous stage", e);
|
|
4017
4782
|
}
|
|
4783
|
+
current.wrappedStage = null;
|
|
4018
4784
|
}
|
|
4019
4785
|
this.stageMap.delete(this.currentStageId);
|
|
4786
|
+
this.currentStageId = "";
|
|
4787
|
+
this.defaultCamera = null;
|
|
4788
|
+
this.rendererObserver.reset();
|
|
4020
4789
|
}
|
|
4021
4790
|
setGlobals(options) {
|
|
4022
4791
|
this.initialGlobals = { ...options.globals };
|
|
@@ -4051,7 +4820,7 @@ var ZylemGame = class _ZylemGame {
|
|
|
4051
4820
|
this.loop(0);
|
|
4052
4821
|
}
|
|
4053
4822
|
loop(timestamp) {
|
|
4054
|
-
this.
|
|
4823
|
+
this.debugDelegate?.begin();
|
|
4055
4824
|
if (!isPaused()) {
|
|
4056
4825
|
this.timer.update(timestamp);
|
|
4057
4826
|
const stage = this.currentStage();
|
|
@@ -4061,14 +4830,14 @@ var ZylemGame = class _ZylemGame {
|
|
|
4061
4830
|
if (this.customUpdate) {
|
|
4062
4831
|
this.customUpdate(clampedParams);
|
|
4063
4832
|
}
|
|
4064
|
-
if (stage) {
|
|
4833
|
+
if (stage && stage.wrappedStage) {
|
|
4065
4834
|
stage.wrappedStage.nodeUpdate({ ...clampedParams, me: stage.wrappedStage });
|
|
4066
4835
|
}
|
|
4067
4836
|
this.totalTime += clampedParams.delta;
|
|
4068
4837
|
state.time = this.totalTime;
|
|
4069
4838
|
this.previousTimeStamp = timestamp;
|
|
4070
4839
|
}
|
|
4071
|
-
this.
|
|
4840
|
+
this.debugDelegate?.end();
|
|
4072
4841
|
this.outOfLoop();
|
|
4073
4842
|
if (!this.isDisposed) {
|
|
4074
4843
|
this.animationFrameId = requestAnimationFrame(this.loop.bind(this));
|
|
@@ -4081,9 +4850,13 @@ var ZylemGame = class _ZylemGame {
|
|
|
4081
4850
|
this.animationFrameId = null;
|
|
4082
4851
|
}
|
|
4083
4852
|
this.unloadCurrentStage();
|
|
4084
|
-
if (this.
|
|
4085
|
-
this.
|
|
4853
|
+
if (this.debugDelegate) {
|
|
4854
|
+
this.debugDelegate.dispose();
|
|
4855
|
+
this.debugDelegate = null;
|
|
4086
4856
|
}
|
|
4857
|
+
this.eventBusUnsubscribes.forEach((unsub) => unsub());
|
|
4858
|
+
this.eventBusUnsubscribes = [];
|
|
4859
|
+
this.rendererObserver.dispose();
|
|
4087
4860
|
this.timer.dispose();
|
|
4088
4861
|
if (this.customDestroy) {
|
|
4089
4862
|
this.customDestroy({
|
|
@@ -4104,6 +4877,52 @@ var ZylemGame = class _ZylemGame {
|
|
|
4104
4877
|
currentStage() {
|
|
4105
4878
|
return this.getStage(this.currentStageId);
|
|
4106
4879
|
}
|
|
4880
|
+
/**
|
|
4881
|
+
* Subscribe to loading events from the game.
|
|
4882
|
+
* Events include stage context (stageName, stageIndex).
|
|
4883
|
+
* @param callback Invoked for each loading event
|
|
4884
|
+
* @returns Unsubscribe function
|
|
4885
|
+
*/
|
|
4886
|
+
onLoading(callback) {
|
|
4887
|
+
return this.loadingDelegate.onLoading(callback);
|
|
4888
|
+
}
|
|
4889
|
+
/**
|
|
4890
|
+
* Subscribe to the game event bus for stage loading and state events.
|
|
4891
|
+
* Emits window events for cross-application communication.
|
|
4892
|
+
*/
|
|
4893
|
+
subscribeToEventBus() {
|
|
4894
|
+
const emitLoadingWindowEvent = (payload) => {
|
|
4895
|
+
if (typeof window !== "undefined") {
|
|
4896
|
+
const event = {
|
|
4897
|
+
type: payload.type,
|
|
4898
|
+
message: payload.message ?? "",
|
|
4899
|
+
progress: payload.progress ?? 0,
|
|
4900
|
+
current: payload.current,
|
|
4901
|
+
total: payload.total,
|
|
4902
|
+
stageName: payload.stageName,
|
|
4903
|
+
stageIndex: payload.stageIndex
|
|
4904
|
+
};
|
|
4905
|
+
window.dispatchEvent(new CustomEvent(GAME_LOADING_EVENT, { detail: event }));
|
|
4906
|
+
}
|
|
4907
|
+
};
|
|
4908
|
+
const emitStateDispatchEvent = (payload) => {
|
|
4909
|
+
if (typeof window !== "undefined") {
|
|
4910
|
+
const detail = {
|
|
4911
|
+
scope: "game",
|
|
4912
|
+
path: payload.path,
|
|
4913
|
+
value: payload.value,
|
|
4914
|
+
previousValue: payload.previousValue
|
|
4915
|
+
};
|
|
4916
|
+
window.dispatchEvent(new CustomEvent(ZYLEM_STATE_DISPATCH, { detail }));
|
|
4917
|
+
}
|
|
4918
|
+
};
|
|
4919
|
+
this.eventBusUnsubscribes.push(
|
|
4920
|
+
gameEventBus.on("stage:loading:start", emitLoadingWindowEvent),
|
|
4921
|
+
gameEventBus.on("stage:loading:progress", emitLoadingWindowEvent),
|
|
4922
|
+
gameEventBus.on("stage:loading:complete", emitLoadingWindowEvent),
|
|
4923
|
+
gameEventBus.on("game:state:updated", emitStateDispatchEvent)
|
|
4924
|
+
);
|
|
4925
|
+
}
|
|
4107
4926
|
};
|
|
4108
4927
|
|
|
4109
4928
|
// src/lib/game/game.ts
|
|
@@ -4234,7 +5053,7 @@ init_stage();
|
|
|
4234
5053
|
init_entity();
|
|
4235
5054
|
init_builder();
|
|
4236
5055
|
init_create();
|
|
4237
|
-
import { Color as
|
|
5056
|
+
import { Color as Color10, Group as Group5, Sprite as ThreeSprite, SpriteMaterial, CanvasTexture, LinearFilter, Vector2 as Vector28, ClampToEdgeWrapping } from "three";
|
|
4238
5057
|
|
|
4239
5058
|
// src/lib/entities/delegates/debug.ts
|
|
4240
5059
|
import { MeshStandardMaterial as MeshStandardMaterial2, MeshBasicMaterial as MeshBasicMaterial2, MeshPhongMaterial as MeshPhongMaterial2 } from "three";
|
|
@@ -4341,7 +5160,7 @@ var textDefaults = {
|
|
|
4341
5160
|
backgroundColor: null,
|
|
4342
5161
|
padding: 4,
|
|
4343
5162
|
stickToViewport: true,
|
|
4344
|
-
screenPosition: new
|
|
5163
|
+
screenPosition: new Vector28(24, 24),
|
|
4345
5164
|
zDistance: 1
|
|
4346
5165
|
};
|
|
4347
5166
|
var TextBuilder = class extends EntityBuilder {
|
|
@@ -4349,7 +5168,7 @@ var TextBuilder = class extends EntityBuilder {
|
|
|
4349
5168
|
return new ZylemText(options);
|
|
4350
5169
|
}
|
|
4351
5170
|
};
|
|
4352
|
-
var TEXT_TYPE = Symbol("Text");
|
|
5171
|
+
var TEXT_TYPE = /* @__PURE__ */ Symbol("Text");
|
|
4353
5172
|
var ZylemText = class _ZylemText extends GameEntity {
|
|
4354
5173
|
static type = TEXT_TYPE;
|
|
4355
5174
|
_sprite = null;
|
|
@@ -4362,12 +5181,20 @@ var ZylemText = class _ZylemText extends GameEntity {
|
|
|
4362
5181
|
constructor(options) {
|
|
4363
5182
|
super();
|
|
4364
5183
|
this.options = { ...textDefaults, ...options };
|
|
5184
|
+
this.prependSetup(this.textSetup.bind(this));
|
|
5185
|
+
this.prependUpdate(this.textUpdate.bind(this));
|
|
5186
|
+
this.onDestroy(this.textDestroy.bind(this));
|
|
5187
|
+
}
|
|
5188
|
+
create() {
|
|
5189
|
+
this._sprite = null;
|
|
5190
|
+
this._texture = null;
|
|
5191
|
+
this._canvas = null;
|
|
5192
|
+
this._ctx = null;
|
|
5193
|
+
this._lastCanvasW = 0;
|
|
5194
|
+
this._lastCanvasH = 0;
|
|
4365
5195
|
this.group = new Group5();
|
|
4366
5196
|
this.createSprite();
|
|
4367
|
-
|
|
4368
|
-
setup: [this.textSetup.bind(this)],
|
|
4369
|
-
update: [this.textUpdate.bind(this)]
|
|
4370
|
-
};
|
|
5197
|
+
return super.create();
|
|
4371
5198
|
}
|
|
4372
5199
|
createSprite() {
|
|
4373
5200
|
this._canvas = document.createElement("canvas");
|
|
@@ -4445,7 +5272,7 @@ var ZylemText = class _ZylemText extends GameEntity {
|
|
|
4445
5272
|
}
|
|
4446
5273
|
toCssColor(color) {
|
|
4447
5274
|
if (typeof color === "string") return color;
|
|
4448
|
-
const c = color instanceof
|
|
5275
|
+
const c = color instanceof Color10 ? color : new Color10(color);
|
|
4449
5276
|
return `#${c.getHexString()}`;
|
|
4450
5277
|
}
|
|
4451
5278
|
textSetup(params) {
|
|
@@ -4505,7 +5332,7 @@ var ZylemText = class _ZylemText extends GameEntity {
|
|
|
4505
5332
|
if (!this._sprite || !this._cameraRef) return;
|
|
4506
5333
|
const camera2 = this._cameraRef.camera;
|
|
4507
5334
|
const { width, height } = this.getResolution();
|
|
4508
|
-
const sp = this.options.screenPosition ?? new
|
|
5335
|
+
const sp = this.options.screenPosition ?? new Vector28(24, 24);
|
|
4509
5336
|
const { px, py } = this.getScreenPixels(sp, width, height);
|
|
4510
5337
|
const zDist = Math.max(1e-3, this.options.zDistance ?? 1);
|
|
4511
5338
|
const { worldHalfW, worldHalfH } = this.computeWorldExtents(camera2, zDist);
|
|
@@ -4533,6 +5360,24 @@ var ZylemText = class _ZylemText extends GameEntity {
|
|
|
4533
5360
|
sticky: this.options.stickToViewport
|
|
4534
5361
|
};
|
|
4535
5362
|
}
|
|
5363
|
+
/**
|
|
5364
|
+
* Dispose of Three.js resources when the entity is destroyed.
|
|
5365
|
+
*/
|
|
5366
|
+
async textDestroy() {
|
|
5367
|
+
this._texture?.dispose();
|
|
5368
|
+
if (this._sprite?.material) {
|
|
5369
|
+
this._sprite.material.dispose();
|
|
5370
|
+
}
|
|
5371
|
+
if (this._sprite) {
|
|
5372
|
+
this._sprite.removeFromParent();
|
|
5373
|
+
}
|
|
5374
|
+
this.group?.removeFromParent();
|
|
5375
|
+
this._sprite = null;
|
|
5376
|
+
this._texture = null;
|
|
5377
|
+
this._canvas = null;
|
|
5378
|
+
this._ctx = null;
|
|
5379
|
+
this._cameraRef = null;
|
|
5380
|
+
}
|
|
4536
5381
|
};
|
|
4537
5382
|
async function text(...args) {
|
|
4538
5383
|
return createEntity({
|
|
@@ -4550,20 +5395,20 @@ init_builder();
|
|
|
4550
5395
|
init_builder();
|
|
4551
5396
|
init_create();
|
|
4552
5397
|
import { ColliderDesc as ColliderDesc3 } from "@dimforge/rapier3d-compat";
|
|
4553
|
-
import { Color as
|
|
5398
|
+
import { Color as Color11, Euler, Group as Group6, Quaternion as Quaternion3, Vector3 as Vector316 } from "three";
|
|
4554
5399
|
import {
|
|
4555
5400
|
TextureLoader as TextureLoader3,
|
|
4556
5401
|
SpriteMaterial as SpriteMaterial2,
|
|
4557
5402
|
Sprite as ThreeSprite2
|
|
4558
5403
|
} from "three";
|
|
4559
5404
|
var spriteDefaults = {
|
|
4560
|
-
size: new
|
|
4561
|
-
position: new
|
|
5405
|
+
size: new Vector316(1, 1, 1),
|
|
5406
|
+
position: new Vector316(0, 0, 0),
|
|
4562
5407
|
collision: {
|
|
4563
5408
|
static: false
|
|
4564
5409
|
},
|
|
4565
5410
|
material: {
|
|
4566
|
-
color: new
|
|
5411
|
+
color: new Color11("#ffffff"),
|
|
4567
5412
|
shader: "standard"
|
|
4568
5413
|
},
|
|
4569
5414
|
images: [],
|
|
@@ -4571,7 +5416,7 @@ var spriteDefaults = {
|
|
|
4571
5416
|
};
|
|
4572
5417
|
var SpriteCollisionBuilder = class extends EntityCollisionBuilder {
|
|
4573
5418
|
collider(options) {
|
|
4574
|
-
const size = options.collisionSize || options.size || new
|
|
5419
|
+
const size = options.collisionSize || options.size || new Vector316(1, 1, 1);
|
|
4575
5420
|
const half = { x: size.x / 2, y: size.y / 2, z: size.z / 2 };
|
|
4576
5421
|
let colliderDesc = ColliderDesc3.cuboid(half.x, half.y, half.z);
|
|
4577
5422
|
return colliderDesc;
|
|
@@ -4582,7 +5427,7 @@ var SpriteBuilder = class extends EntityBuilder {
|
|
|
4582
5427
|
return new ZylemSprite(options);
|
|
4583
5428
|
}
|
|
4584
5429
|
};
|
|
4585
|
-
var SPRITE_TYPE = Symbol("Sprite");
|
|
5430
|
+
var SPRITE_TYPE = /* @__PURE__ */ Symbol("Sprite");
|
|
4586
5431
|
var ZylemSprite = class _ZylemSprite extends GameEntity {
|
|
4587
5432
|
static type = SPRITE_TYPE;
|
|
4588
5433
|
sprites = [];
|
|
@@ -4596,12 +5441,21 @@ var ZylemSprite = class _ZylemSprite extends GameEntity {
|
|
|
4596
5441
|
constructor(options) {
|
|
4597
5442
|
super();
|
|
4598
5443
|
this.options = { ...spriteDefaults, ...options };
|
|
4599
|
-
this.
|
|
4600
|
-
this.
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
5444
|
+
this.prependUpdate(this.spriteUpdate.bind(this));
|
|
5445
|
+
this.onDestroy(this.spriteDestroy.bind(this));
|
|
5446
|
+
}
|
|
5447
|
+
create() {
|
|
5448
|
+
this.sprites = [];
|
|
5449
|
+
this.spriteMap.clear();
|
|
5450
|
+
this.animations.clear();
|
|
5451
|
+
this.currentAnimation = null;
|
|
5452
|
+
this.currentAnimationFrame = "";
|
|
5453
|
+
this.currentAnimationIndex = 0;
|
|
5454
|
+
this.currentAnimationTime = 0;
|
|
5455
|
+
this.group = void 0;
|
|
5456
|
+
this.createSpritesFromImages(this.options?.images || []);
|
|
5457
|
+
this.createAnimations(this.options?.animations || []);
|
|
5458
|
+
return super.create();
|
|
4605
5459
|
}
|
|
4606
5460
|
createSpritesFromImages(images) {
|
|
4607
5461
|
const textureLoader = new TextureLoader3();
|
|
@@ -4671,7 +5525,7 @@ var ZylemSprite = class _ZylemSprite extends GameEntity {
|
|
|
4671
5525
|
if (_sprite.material) {
|
|
4672
5526
|
const q = this.body?.rotation();
|
|
4673
5527
|
if (q) {
|
|
4674
|
-
const quat = new
|
|
5528
|
+
const quat = new Quaternion3(q.x, q.y, q.z, q.w);
|
|
4675
5529
|
const euler = new Euler().setFromQuaternion(quat, "XYZ");
|
|
4676
5530
|
_sprite.material.rotation = euler.z;
|
|
4677
5531
|
}
|
|
@@ -4755,12 +5609,15 @@ init_game_state();
|
|
|
4755
5609
|
var Game = class {
|
|
4756
5610
|
wrappedGame = null;
|
|
4757
5611
|
options;
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
5612
|
+
// Lifecycle callback arrays
|
|
5613
|
+
setupCallbacks = [];
|
|
5614
|
+
updateCallbacks = [];
|
|
5615
|
+
destroyCallbacks = [];
|
|
5616
|
+
pendingLoadingCallbacks = [];
|
|
5617
|
+
// Game-scoped global change subscriptions
|
|
5618
|
+
globalChangeCallbacks = [];
|
|
5619
|
+
globalChangesCallbacks = [];
|
|
5620
|
+
activeGlobalSubscriptions = [];
|
|
4764
5621
|
refErrorMessage = "lost reference to game";
|
|
4765
5622
|
constructor(options) {
|
|
4766
5623
|
this.options = options;
|
|
@@ -4772,10 +5629,29 @@ var Game = class {
|
|
|
4772
5629
|
initGlobals(globals);
|
|
4773
5630
|
}
|
|
4774
5631
|
}
|
|
5632
|
+
// Fluent API for adding lifecycle callbacks
|
|
5633
|
+
onSetup(...callbacks) {
|
|
5634
|
+
this.setupCallbacks.push(...callbacks);
|
|
5635
|
+
return this;
|
|
5636
|
+
}
|
|
5637
|
+
onUpdate(...callbacks) {
|
|
5638
|
+
this.updateCallbacks.push(...callbacks);
|
|
5639
|
+
return this;
|
|
5640
|
+
}
|
|
5641
|
+
onDestroy(...callbacks) {
|
|
5642
|
+
this.destroyCallbacks.push(...callbacks);
|
|
5643
|
+
return this;
|
|
5644
|
+
}
|
|
4775
5645
|
async start() {
|
|
5646
|
+
resetGlobals();
|
|
5647
|
+
const globals = extractGlobalsFromOptions(this.options);
|
|
5648
|
+
if (globals) {
|
|
5649
|
+
initGlobals(globals);
|
|
5650
|
+
}
|
|
4776
5651
|
const game = await this.load();
|
|
4777
5652
|
this.wrappedGame = game;
|
|
4778
5653
|
this.setOverrides();
|
|
5654
|
+
this.registerGlobalSubscriptions();
|
|
4779
5655
|
game.start();
|
|
4780
5656
|
return this;
|
|
4781
5657
|
}
|
|
@@ -4786,6 +5662,9 @@ var Game = class {
|
|
|
4786
5662
|
...options,
|
|
4787
5663
|
...resolved
|
|
4788
5664
|
}, this);
|
|
5665
|
+
for (const callback of this.pendingLoadingCallbacks) {
|
|
5666
|
+
game.onLoading(callback);
|
|
5667
|
+
}
|
|
4789
5668
|
await game.loadStage(options.stages[0]);
|
|
4790
5669
|
return game;
|
|
4791
5670
|
}
|
|
@@ -4794,9 +5673,59 @@ var Game = class {
|
|
|
4794
5673
|
console.error(this.refErrorMessage);
|
|
4795
5674
|
return;
|
|
4796
5675
|
}
|
|
4797
|
-
this.wrappedGame.customSetup =
|
|
4798
|
-
|
|
4799
|
-
|
|
5676
|
+
this.wrappedGame.customSetup = (params) => {
|
|
5677
|
+
this.setupCallbacks.forEach((cb) => cb(params));
|
|
5678
|
+
};
|
|
5679
|
+
this.wrappedGame.customUpdate = (params) => {
|
|
5680
|
+
this.updateCallbacks.forEach((cb) => cb(params));
|
|
5681
|
+
};
|
|
5682
|
+
this.wrappedGame.customDestroy = (params) => {
|
|
5683
|
+
this.destroyCallbacks.forEach((cb) => cb(params));
|
|
5684
|
+
};
|
|
5685
|
+
}
|
|
5686
|
+
/**
|
|
5687
|
+
* Subscribe to changes on a global value. Subscriptions are registered
|
|
5688
|
+
* when the game starts and cleaned up when disposed.
|
|
5689
|
+
* The callback receives the value and the current stage.
|
|
5690
|
+
* @example game.onGlobalChange('score', (val, stage) => console.log(val));
|
|
5691
|
+
*/
|
|
5692
|
+
onGlobalChange(path, callback) {
|
|
5693
|
+
this.globalChangeCallbacks.push({ path, callback });
|
|
5694
|
+
return this;
|
|
5695
|
+
}
|
|
5696
|
+
/**
|
|
5697
|
+
* Subscribe to changes on multiple global paths. Subscriptions are registered
|
|
5698
|
+
* when the game starts and cleaned up when disposed.
|
|
5699
|
+
* The callback receives the values and the current stage.
|
|
5700
|
+
* @example game.onGlobalChanges(['score', 'lives'], ([score, lives], stage) => console.log(score, lives));
|
|
5701
|
+
*/
|
|
5702
|
+
onGlobalChanges(paths, callback) {
|
|
5703
|
+
this.globalChangesCallbacks.push({ paths, callback });
|
|
5704
|
+
return this;
|
|
5705
|
+
}
|
|
5706
|
+
/**
|
|
5707
|
+
* Register all stored global change callbacks.
|
|
5708
|
+
* Called internally during start().
|
|
5709
|
+
*/
|
|
5710
|
+
registerGlobalSubscriptions() {
|
|
5711
|
+
for (const { path, callback } of this.globalChangeCallbacks) {
|
|
5712
|
+
const unsub = onGlobalChange(path, (value) => {
|
|
5713
|
+
callback(value, this.getCurrentStage());
|
|
5714
|
+
});
|
|
5715
|
+
this.activeGlobalSubscriptions.push(unsub);
|
|
5716
|
+
}
|
|
5717
|
+
for (const { paths, callback } of this.globalChangesCallbacks) {
|
|
5718
|
+
const unsub = onGlobalChanges(paths, (values) => {
|
|
5719
|
+
callback(values, this.getCurrentStage());
|
|
5720
|
+
});
|
|
5721
|
+
this.activeGlobalSubscriptions.push(unsub);
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
/**
|
|
5725
|
+
* Get the current stage wrapper.
|
|
5726
|
+
*/
|
|
5727
|
+
getCurrentStage() {
|
|
5728
|
+
return this.wrappedGame?.currentStage() ?? null;
|
|
4800
5729
|
}
|
|
4801
5730
|
async pause() {
|
|
4802
5731
|
setPaused(true);
|
|
@@ -4815,19 +5744,19 @@ var Game = class {
|
|
|
4815
5744
|
}
|
|
4816
5745
|
await this.wrappedGame.loadStage(this.wrappedGame.stages[0]);
|
|
4817
5746
|
}
|
|
4818
|
-
|
|
5747
|
+
previousStage() {
|
|
4819
5748
|
if (!this.wrappedGame) {
|
|
4820
5749
|
console.error(this.refErrorMessage);
|
|
4821
5750
|
return;
|
|
4822
5751
|
}
|
|
4823
5752
|
const currentStageId = this.wrappedGame.currentStageId;
|
|
4824
|
-
const currentIndex = this.wrappedGame.stages.findIndex((s) => s.wrappedStage
|
|
5753
|
+
const currentIndex = this.wrappedGame.stages.findIndex((s) => s.wrappedStage?.uuid === currentStageId);
|
|
4825
5754
|
const previousStage = this.wrappedGame.stages[currentIndex - 1];
|
|
4826
5755
|
if (!previousStage) {
|
|
4827
5756
|
console.error("previous stage called on first stage");
|
|
4828
5757
|
return;
|
|
4829
5758
|
}
|
|
4830
|
-
|
|
5759
|
+
this.wrappedGame.loadStage(previousStage);
|
|
4831
5760
|
}
|
|
4832
5761
|
async loadStageFromId(stageId) {
|
|
4833
5762
|
if (!this.wrappedGame) {
|
|
@@ -4843,39 +5772,61 @@ var Game = class {
|
|
|
4843
5772
|
console.error(`Failed to load stage ${stageId}`, e);
|
|
4844
5773
|
}
|
|
4845
5774
|
}
|
|
4846
|
-
|
|
5775
|
+
nextStage() {
|
|
4847
5776
|
if (!this.wrappedGame) {
|
|
4848
5777
|
console.error(this.refErrorMessage);
|
|
4849
5778
|
return;
|
|
4850
5779
|
}
|
|
4851
5780
|
if (stageState2.next) {
|
|
4852
5781
|
const nextId = stageState2.next.id;
|
|
4853
|
-
|
|
5782
|
+
StageManager.transitionForward(nextId);
|
|
4854
5783
|
if (stageState2.current) {
|
|
4855
|
-
|
|
4856
|
-
|
|
5784
|
+
StageFactory.createFromBlueprint(stageState2.current).then((stage) => {
|
|
5785
|
+
this.wrappedGame?.loadStage(stage);
|
|
5786
|
+
});
|
|
4857
5787
|
return;
|
|
4858
5788
|
}
|
|
4859
5789
|
}
|
|
4860
5790
|
const currentStageId = this.wrappedGame.currentStageId;
|
|
4861
|
-
const currentIndex = this.wrappedGame.stages.findIndex((s) => s.wrappedStage
|
|
5791
|
+
const currentIndex = this.wrappedGame.stages.findIndex((s) => s.wrappedStage?.uuid === currentStageId);
|
|
4862
5792
|
const nextStage = this.wrappedGame.stages[currentIndex + 1];
|
|
4863
5793
|
if (!nextStage) {
|
|
4864
5794
|
console.error("next stage called on last stage");
|
|
4865
5795
|
return;
|
|
4866
5796
|
}
|
|
4867
|
-
|
|
5797
|
+
this.wrappedGame.loadStage(nextStage);
|
|
4868
5798
|
}
|
|
4869
5799
|
async goToStage() {
|
|
4870
5800
|
}
|
|
4871
5801
|
async end() {
|
|
4872
5802
|
}
|
|
4873
5803
|
dispose() {
|
|
5804
|
+
for (const unsub of this.activeGlobalSubscriptions) {
|
|
5805
|
+
unsub();
|
|
5806
|
+
}
|
|
5807
|
+
this.activeGlobalSubscriptions = [];
|
|
4874
5808
|
if (this.wrappedGame) {
|
|
4875
5809
|
this.wrappedGame.dispose();
|
|
4876
5810
|
}
|
|
5811
|
+
clearGlobalSubscriptions();
|
|
5812
|
+
resetGlobals();
|
|
4877
5813
|
}
|
|
5814
|
+
/**
|
|
5815
|
+
* Subscribe to loading events from the game.
|
|
5816
|
+
* Events include stage context (stageName, stageIndex).
|
|
5817
|
+
* @param callback Invoked for each loading event
|
|
5818
|
+
* @returns Unsubscribe function
|
|
5819
|
+
*/
|
|
4878
5820
|
onLoading(callback) {
|
|
5821
|
+
if (this.wrappedGame) {
|
|
5822
|
+
return this.wrappedGame.onLoading(callback);
|
|
5823
|
+
}
|
|
5824
|
+
this.pendingLoadingCallbacks.push(callback);
|
|
5825
|
+
return () => {
|
|
5826
|
+
this.pendingLoadingCallbacks = this.pendingLoadingCallbacks.filter((c) => c !== callback);
|
|
5827
|
+
if (this.wrappedGame) {
|
|
5828
|
+
}
|
|
5829
|
+
};
|
|
4879
5830
|
}
|
|
4880
5831
|
};
|
|
4881
5832
|
function createGame(...options) {
|
|
@@ -4886,7 +5837,7 @@ function createGame(...options) {
|
|
|
4886
5837
|
init_stage();
|
|
4887
5838
|
|
|
4888
5839
|
// src/lib/stage/entity-spawner.ts
|
|
4889
|
-
import { Euler as Euler2, Quaternion as
|
|
5840
|
+
import { Euler as Euler2, Quaternion as Quaternion4, Vector2 as Vector29 } from "three";
|
|
4890
5841
|
function entitySpawner(factory) {
|
|
4891
5842
|
return {
|
|
4892
5843
|
spawn: async (stage, x, y) => {
|
|
@@ -4894,7 +5845,7 @@ function entitySpawner(factory) {
|
|
|
4894
5845
|
stage.add(instance);
|
|
4895
5846
|
return instance;
|
|
4896
5847
|
},
|
|
4897
|
-
spawnRelative: async (source, stage, offset = new
|
|
5848
|
+
spawnRelative: async (source, stage, offset = new Vector29(0, 1)) => {
|
|
4898
5849
|
if (!source.body) {
|
|
4899
5850
|
console.warn("body missing for entity during spawnRelative");
|
|
4900
5851
|
return void 0;
|
|
@@ -4903,7 +5854,7 @@ function entitySpawner(factory) {
|
|
|
4903
5854
|
let rz = source._rotation2DAngle ?? 0;
|
|
4904
5855
|
try {
|
|
4905
5856
|
const r = source.body.rotation();
|
|
4906
|
-
const q = new
|
|
5857
|
+
const q = new Quaternion4(r.x, r.y, r.z, r.w);
|
|
4907
5858
|
const e = new Euler2().setFromQuaternion(q, "XYZ");
|
|
4908
5859
|
rz = e.z;
|
|
4909
5860
|
} catch {
|
|
@@ -4919,7 +5870,7 @@ function entitySpawner(factory) {
|
|
|
4919
5870
|
|
|
4920
5871
|
// src/lib/core/vessel.ts
|
|
4921
5872
|
init_base_node();
|
|
4922
|
-
var VESSEL_TYPE = Symbol("vessel");
|
|
5873
|
+
var VESSEL_TYPE = /* @__PURE__ */ Symbol("vessel");
|
|
4923
5874
|
var Vessel = class extends BaseNode {
|
|
4924
5875
|
static type = VESSEL_TYPE;
|
|
4925
5876
|
_setup(_params) {
|
|
@@ -4952,23 +5903,23 @@ init_builder();
|
|
|
4952
5903
|
init_builder();
|
|
4953
5904
|
init_builder();
|
|
4954
5905
|
import { ColliderDesc as ColliderDesc4 } from "@dimforge/rapier3d-compat";
|
|
4955
|
-
import { BoxGeometry as BoxGeometry2, Color as
|
|
4956
|
-
import { Vector3 as
|
|
5906
|
+
import { BoxGeometry as BoxGeometry2, Color as Color12 } from "three";
|
|
5907
|
+
import { Vector3 as Vector317 } from "three";
|
|
4957
5908
|
init_create();
|
|
4958
5909
|
var boxDefaults = {
|
|
4959
|
-
size: new
|
|
4960
|
-
position: new
|
|
5910
|
+
size: new Vector317(1, 1, 1),
|
|
5911
|
+
position: new Vector317(0, 0, 0),
|
|
4961
5912
|
collision: {
|
|
4962
5913
|
static: false
|
|
4963
5914
|
},
|
|
4964
5915
|
material: {
|
|
4965
|
-
color: new
|
|
5916
|
+
color: new Color12("#ffffff"),
|
|
4966
5917
|
shader: "standard"
|
|
4967
5918
|
}
|
|
4968
5919
|
};
|
|
4969
5920
|
var BoxCollisionBuilder = class extends EntityCollisionBuilder {
|
|
4970
5921
|
collider(options) {
|
|
4971
|
-
const size = options.size || new
|
|
5922
|
+
const size = options.size || new Vector317(1, 1, 1);
|
|
4972
5923
|
const half = { x: size.x / 2, y: size.y / 2, z: size.z / 2 };
|
|
4973
5924
|
let colliderDesc = ColliderDesc4.cuboid(half.x, half.y, half.z);
|
|
4974
5925
|
return colliderDesc;
|
|
@@ -4976,7 +5927,7 @@ var BoxCollisionBuilder = class extends EntityCollisionBuilder {
|
|
|
4976
5927
|
};
|
|
4977
5928
|
var BoxMeshBuilder = class extends EntityMeshBuilder {
|
|
4978
5929
|
build(options) {
|
|
4979
|
-
const size = options.size ?? new
|
|
5930
|
+
const size = options.size ?? new Vector317(1, 1, 1);
|
|
4980
5931
|
return new BoxGeometry2(size.x, size.y, size.z);
|
|
4981
5932
|
}
|
|
4982
5933
|
};
|
|
@@ -4985,7 +5936,7 @@ var BoxBuilder = class extends EntityBuilder {
|
|
|
4985
5936
|
return new ZylemBox(options);
|
|
4986
5937
|
}
|
|
4987
5938
|
};
|
|
4988
|
-
var BOX_TYPE = Symbol("Box");
|
|
5939
|
+
var BOX_TYPE = /* @__PURE__ */ Symbol("Box");
|
|
4989
5940
|
var ZylemBox = class _ZylemBox extends GameEntity {
|
|
4990
5941
|
static type = BOX_TYPE;
|
|
4991
5942
|
constructor(options) {
|
|
@@ -5021,17 +5972,17 @@ init_builder();
|
|
|
5021
5972
|
init_builder();
|
|
5022
5973
|
init_builder();
|
|
5023
5974
|
import { ColliderDesc as ColliderDesc5 } from "@dimforge/rapier3d-compat";
|
|
5024
|
-
import { Color as
|
|
5025
|
-
import { Vector3 as
|
|
5975
|
+
import { Color as Color13, SphereGeometry } from "three";
|
|
5976
|
+
import { Vector3 as Vector318 } from "three";
|
|
5026
5977
|
init_create();
|
|
5027
5978
|
var sphereDefaults = {
|
|
5028
5979
|
radius: 1,
|
|
5029
|
-
position: new
|
|
5980
|
+
position: new Vector318(0, 0, 0),
|
|
5030
5981
|
collision: {
|
|
5031
5982
|
static: false
|
|
5032
5983
|
},
|
|
5033
5984
|
material: {
|
|
5034
|
-
color: new
|
|
5985
|
+
color: new Color13("#ffffff"),
|
|
5035
5986
|
shader: "standard"
|
|
5036
5987
|
}
|
|
5037
5988
|
};
|
|
@@ -5053,7 +6004,7 @@ var SphereBuilder = class extends EntityBuilder {
|
|
|
5053
6004
|
return new ZylemSphere(options);
|
|
5054
6005
|
}
|
|
5055
6006
|
};
|
|
5056
|
-
var SPHERE_TYPE = Symbol("Sphere");
|
|
6007
|
+
var SPHERE_TYPE = /* @__PURE__ */ Symbol("Sphere");
|
|
5057
6008
|
var ZylemSphere = class _ZylemSphere extends GameEntity {
|
|
5058
6009
|
static type = SPHERE_TYPE;
|
|
5059
6010
|
constructor(options) {
|
|
@@ -5089,7 +6040,7 @@ init_builder();
|
|
|
5089
6040
|
init_builder();
|
|
5090
6041
|
init_builder();
|
|
5091
6042
|
import { ColliderDesc as ColliderDesc6 } from "@dimforge/rapier3d-compat";
|
|
5092
|
-
import { Color as
|
|
6043
|
+
import { Color as Color14, PlaneGeometry, Vector2 as Vector210, Vector3 as Vector319 } from "three";
|
|
5093
6044
|
|
|
5094
6045
|
// src/lib/graphics/geometries/XZPlaneGeometry.ts
|
|
5095
6046
|
import { BufferGeometry as BufferGeometry5, Float32BufferAttribute } from "three";
|
|
@@ -5154,25 +6105,25 @@ var XZPlaneGeometry = class _XZPlaneGeometry extends BufferGeometry5 {
|
|
|
5154
6105
|
init_create();
|
|
5155
6106
|
var DEFAULT_SUBDIVISIONS = 4;
|
|
5156
6107
|
var planeDefaults = {
|
|
5157
|
-
tile: new
|
|
5158
|
-
repeat: new
|
|
5159
|
-
position: new
|
|
6108
|
+
tile: new Vector210(10, 10),
|
|
6109
|
+
repeat: new Vector210(1, 1),
|
|
6110
|
+
position: new Vector319(0, 0, 0),
|
|
5160
6111
|
collision: {
|
|
5161
6112
|
static: true
|
|
5162
6113
|
},
|
|
5163
6114
|
material: {
|
|
5164
|
-
color: new
|
|
6115
|
+
color: new Color14("#ffffff"),
|
|
5165
6116
|
shader: "standard"
|
|
5166
6117
|
},
|
|
5167
6118
|
subdivisions: DEFAULT_SUBDIVISIONS
|
|
5168
6119
|
};
|
|
5169
6120
|
var PlaneCollisionBuilder = class extends EntityCollisionBuilder {
|
|
5170
6121
|
collider(options) {
|
|
5171
|
-
const tile = options.tile ?? new
|
|
6122
|
+
const tile = options.tile ?? new Vector210(1, 1);
|
|
5172
6123
|
const subdivisions = options.subdivisions ?? DEFAULT_SUBDIVISIONS;
|
|
5173
|
-
const size = new
|
|
6124
|
+
const size = new Vector319(tile.x, 1, tile.y);
|
|
5174
6125
|
const heightData = options._builders?.meshBuilder?.heightData;
|
|
5175
|
-
const scale2 = new
|
|
6126
|
+
const scale2 = new Vector319(size.x, 1, size.z);
|
|
5176
6127
|
let colliderDesc = ColliderDesc6.heightfield(
|
|
5177
6128
|
subdivisions,
|
|
5178
6129
|
subdivisions,
|
|
@@ -5186,9 +6137,9 @@ var PlaneMeshBuilder = class extends EntityMeshBuilder {
|
|
|
5186
6137
|
heightData = new Float32Array();
|
|
5187
6138
|
columnsRows = /* @__PURE__ */ new Map();
|
|
5188
6139
|
build(options) {
|
|
5189
|
-
const tile = options.tile ?? new
|
|
6140
|
+
const tile = options.tile ?? new Vector210(1, 1);
|
|
5190
6141
|
const subdivisions = options.subdivisions ?? DEFAULT_SUBDIVISIONS;
|
|
5191
|
-
const size = new
|
|
6142
|
+
const size = new Vector319(tile.x, 1, tile.y);
|
|
5192
6143
|
const geometry = new XZPlaneGeometry(size.x, size.z, subdivisions, subdivisions);
|
|
5193
6144
|
const vertexGeometry = new PlaneGeometry(size.x, size.z, subdivisions, subdivisions);
|
|
5194
6145
|
const dx = size.x / subdivisions;
|
|
@@ -5230,7 +6181,7 @@ var PlaneBuilder = class extends EntityBuilder {
|
|
|
5230
6181
|
return new ZylemPlane(options);
|
|
5231
6182
|
}
|
|
5232
6183
|
};
|
|
5233
|
-
var PLANE_TYPE = Symbol("Plane");
|
|
6184
|
+
var PLANE_TYPE = /* @__PURE__ */ Symbol("Plane");
|
|
5234
6185
|
var ZylemPlane = class extends GameEntity {
|
|
5235
6186
|
static type = PLANE_TYPE;
|
|
5236
6187
|
constructor(options) {
|
|
@@ -5257,10 +6208,10 @@ init_builder();
|
|
|
5257
6208
|
init_create();
|
|
5258
6209
|
init_game_state();
|
|
5259
6210
|
import { ActiveCollisionTypes as ActiveCollisionTypes3, ColliderDesc as ColliderDesc7 } from "@dimforge/rapier3d-compat";
|
|
5260
|
-
import { Vector3 as
|
|
6211
|
+
import { Vector3 as Vector320 } from "three";
|
|
5261
6212
|
var zoneDefaults = {
|
|
5262
|
-
size: new
|
|
5263
|
-
position: new
|
|
6213
|
+
size: new Vector320(1, 1, 1),
|
|
6214
|
+
position: new Vector320(0, 0, 0),
|
|
5264
6215
|
collision: {
|
|
5265
6216
|
static: true
|
|
5266
6217
|
},
|
|
@@ -5270,7 +6221,7 @@ var zoneDefaults = {
|
|
|
5270
6221
|
};
|
|
5271
6222
|
var ZoneCollisionBuilder = class extends EntityCollisionBuilder {
|
|
5272
6223
|
collider(options) {
|
|
5273
|
-
const size = options.size || new
|
|
6224
|
+
const size = options.size || new Vector320(1, 1, 1);
|
|
5274
6225
|
const half = { x: size.x / 2, y: size.y / 2, z: size.z / 2 };
|
|
5275
6226
|
let colliderDesc = ColliderDesc7.cuboid(half.x, half.y, half.z);
|
|
5276
6227
|
colliderDesc.setSensor(true);
|
|
@@ -5283,7 +6234,7 @@ var ZoneBuilder = class extends EntityBuilder {
|
|
|
5283
6234
|
return new ZylemZone(options);
|
|
5284
6235
|
}
|
|
5285
6236
|
};
|
|
5286
|
-
var ZONE_TYPE = Symbol("Zone");
|
|
6237
|
+
var ZONE_TYPE = /* @__PURE__ */ Symbol("Zone");
|
|
5287
6238
|
var ZylemZone = class extends GameEntity {
|
|
5288
6239
|
static type = ZONE_TYPE;
|
|
5289
6240
|
_enteredZone = /* @__PURE__ */ new Map();
|
|
@@ -5380,7 +6331,7 @@ init_actor();
|
|
|
5380
6331
|
init_entity();
|
|
5381
6332
|
init_builder();
|
|
5382
6333
|
init_create();
|
|
5383
|
-
import { Color as
|
|
6334
|
+
import { Color as Color15, Group as Group7, Sprite as ThreeSprite3, SpriteMaterial as SpriteMaterial3, CanvasTexture as CanvasTexture2, LinearFilter as LinearFilter2, Vector2 as Vector211, ClampToEdgeWrapping as ClampToEdgeWrapping2, ShaderMaterial as ShaderMaterial4, Mesh as Mesh5, PlaneGeometry as PlaneGeometry2, Vector3 as Vector321 } from "three";
|
|
5384
6335
|
var rectDefaults = {
|
|
5385
6336
|
position: void 0,
|
|
5386
6337
|
width: 120,
|
|
@@ -5391,16 +6342,16 @@ var rectDefaults = {
|
|
|
5391
6342
|
radius: 0,
|
|
5392
6343
|
padding: 0,
|
|
5393
6344
|
stickToViewport: true,
|
|
5394
|
-
screenPosition: new
|
|
6345
|
+
screenPosition: new Vector211(24, 24),
|
|
5395
6346
|
zDistance: 1,
|
|
5396
|
-
anchor: new
|
|
6347
|
+
anchor: new Vector211(0, 0)
|
|
5397
6348
|
};
|
|
5398
6349
|
var RectBuilder = class extends EntityBuilder {
|
|
5399
6350
|
createEntity(options) {
|
|
5400
6351
|
return new ZylemRect(options);
|
|
5401
6352
|
}
|
|
5402
6353
|
};
|
|
5403
|
-
var RECT_TYPE = Symbol("Rect");
|
|
6354
|
+
var RECT_TYPE = /* @__PURE__ */ Symbol("Rect");
|
|
5404
6355
|
var ZylemRect = class _ZylemRect extends GameEntity {
|
|
5405
6356
|
static type = RECT_TYPE;
|
|
5406
6357
|
_sprite = null;
|
|
@@ -5416,10 +6367,8 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5416
6367
|
this.options = { ...rectDefaults, ...options };
|
|
5417
6368
|
this.group = new Group7();
|
|
5418
6369
|
this.createSprite();
|
|
5419
|
-
this.
|
|
5420
|
-
|
|
5421
|
-
update: [this.rectUpdate.bind(this)]
|
|
5422
|
-
};
|
|
6370
|
+
this.prependSetup(this.rectSetup.bind(this));
|
|
6371
|
+
this.prependUpdate(this.rectUpdate.bind(this));
|
|
5423
6372
|
}
|
|
5424
6373
|
createSprite() {
|
|
5425
6374
|
this._canvas = document.createElement("canvas");
|
|
@@ -5510,7 +6459,7 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5510
6459
|
}
|
|
5511
6460
|
toCssColor(color) {
|
|
5512
6461
|
if (typeof color === "string") return color;
|
|
5513
|
-
const c = color instanceof
|
|
6462
|
+
const c = color instanceof Color15 ? color : new Color15(color);
|
|
5514
6463
|
return `#${c.getHexString()}`;
|
|
5515
6464
|
}
|
|
5516
6465
|
rectSetup(params) {
|
|
@@ -5544,10 +6493,10 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5544
6493
|
const desiredW = Math.max(2, Math.floor(width));
|
|
5545
6494
|
const desiredH = Math.max(2, Math.floor(height));
|
|
5546
6495
|
const changed = desiredW !== (this.options.width ?? 0) || desiredH !== (this.options.height ?? 0);
|
|
5547
|
-
this.options.screenPosition = new
|
|
6496
|
+
this.options.screenPosition = new Vector211(Math.floor(x), Math.floor(y));
|
|
5548
6497
|
this.options.width = desiredW;
|
|
5549
6498
|
this.options.height = desiredH;
|
|
5550
|
-
this.options.anchor = new
|
|
6499
|
+
this.options.anchor = new Vector211(0, 0);
|
|
5551
6500
|
if (changed) {
|
|
5552
6501
|
this.redrawRect();
|
|
5553
6502
|
}
|
|
@@ -5563,8 +6512,8 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5563
6512
|
const dom = this._cameraRef.renderer.domElement;
|
|
5564
6513
|
const width = dom.clientWidth;
|
|
5565
6514
|
const height = dom.clientHeight;
|
|
5566
|
-
const px = (this.options.screenPosition ?? new
|
|
5567
|
-
const py = (this.options.screenPosition ?? new
|
|
6515
|
+
const px = (this.options.screenPosition ?? new Vector211(24, 24)).x;
|
|
6516
|
+
const py = (this.options.screenPosition ?? new Vector211(24, 24)).y;
|
|
5568
6517
|
const zDist = Math.max(1e-3, this.options.zDistance ?? 1);
|
|
5569
6518
|
let worldHalfW = 1;
|
|
5570
6519
|
let worldHalfH = 1;
|
|
@@ -5595,7 +6544,7 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5595
6544
|
this._sprite.scale.set(scaleX, scaleY, 1);
|
|
5596
6545
|
if (this._mesh) this._mesh.scale.set(scaleX, scaleY, 1);
|
|
5597
6546
|
}
|
|
5598
|
-
const anchor = this.options.anchor ?? new
|
|
6547
|
+
const anchor = this.options.anchor ?? new Vector211(0, 0);
|
|
5599
6548
|
const ax = Math.min(100, Math.max(0, anchor.x)) / 100;
|
|
5600
6549
|
const ay = Math.min(100, Math.max(0, anchor.y)) / 100;
|
|
5601
6550
|
const offsetX = (0.5 - ax) * scaleX;
|
|
@@ -5619,8 +6568,8 @@ var ZylemRect = class _ZylemRect extends GameEntity {
|
|
|
5619
6568
|
}
|
|
5620
6569
|
if (bounds.world) {
|
|
5621
6570
|
const { left, right, top, bottom, z = 0 } = bounds.world;
|
|
5622
|
-
const tl = this.worldToScreen(new
|
|
5623
|
-
const br = this.worldToScreen(new
|
|
6571
|
+
const tl = this.worldToScreen(new Vector321(left, top, z));
|
|
6572
|
+
const br = this.worldToScreen(new Vector321(right, bottom, z));
|
|
5624
6573
|
const x = Math.min(tl.x, br.x);
|
|
5625
6574
|
const y = Math.min(tl.y, br.y);
|
|
5626
6575
|
const width = Math.abs(br.x - tl.x);
|
|
@@ -6089,41 +7038,41 @@ function movementSequence2D(opts, onStep) {
|
|
|
6089
7038
|
}
|
|
6090
7039
|
|
|
6091
7040
|
// src/lib/actions/capabilities/moveable.ts
|
|
6092
|
-
import { Vector3 as
|
|
7041
|
+
import { Vector3 as Vector322 } from "three";
|
|
6093
7042
|
function moveX(entity, delta) {
|
|
6094
7043
|
if (!entity.body) return;
|
|
6095
7044
|
const currentVelocity = entity.body.linvel();
|
|
6096
|
-
const newVelocity = new
|
|
7045
|
+
const newVelocity = new Vector322(delta, currentVelocity.y, currentVelocity.z);
|
|
6097
7046
|
entity.body.setLinvel(newVelocity, true);
|
|
6098
7047
|
}
|
|
6099
7048
|
function moveY(entity, delta) {
|
|
6100
7049
|
if (!entity.body) return;
|
|
6101
7050
|
const currentVelocity = entity.body.linvel();
|
|
6102
|
-
const newVelocity = new
|
|
7051
|
+
const newVelocity = new Vector322(currentVelocity.x, delta, currentVelocity.z);
|
|
6103
7052
|
entity.body.setLinvel(newVelocity, true);
|
|
6104
7053
|
}
|
|
6105
7054
|
function moveZ(entity, delta) {
|
|
6106
7055
|
if (!entity.body) return;
|
|
6107
7056
|
const currentVelocity = entity.body.linvel();
|
|
6108
|
-
const newVelocity = new
|
|
7057
|
+
const newVelocity = new Vector322(currentVelocity.x, currentVelocity.y, delta);
|
|
6109
7058
|
entity.body.setLinvel(newVelocity, true);
|
|
6110
7059
|
}
|
|
6111
7060
|
function moveXY(entity, deltaX, deltaY) {
|
|
6112
7061
|
if (!entity.body) return;
|
|
6113
7062
|
const currentVelocity = entity.body.linvel();
|
|
6114
|
-
const newVelocity = new
|
|
7063
|
+
const newVelocity = new Vector322(deltaX, deltaY, currentVelocity.z);
|
|
6115
7064
|
entity.body.setLinvel(newVelocity, true);
|
|
6116
7065
|
}
|
|
6117
7066
|
function moveXZ(entity, deltaX, deltaZ) {
|
|
6118
7067
|
if (!entity.body) return;
|
|
6119
7068
|
const currentVelocity = entity.body.linvel();
|
|
6120
|
-
const newVelocity = new
|
|
7069
|
+
const newVelocity = new Vector322(deltaX, currentVelocity.y, deltaZ);
|
|
6121
7070
|
entity.body.setLinvel(newVelocity, true);
|
|
6122
7071
|
}
|
|
6123
7072
|
function move(entity, vector) {
|
|
6124
7073
|
if (!entity.body) return;
|
|
6125
7074
|
const currentVelocity = entity.body.linvel();
|
|
6126
|
-
const newVelocity = new
|
|
7075
|
+
const newVelocity = new Vector322(
|
|
6127
7076
|
currentVelocity.x + vector.x,
|
|
6128
7077
|
currentVelocity.y + vector.y,
|
|
6129
7078
|
currentVelocity.z + vector.z
|
|
@@ -6132,7 +7081,7 @@ function move(entity, vector) {
|
|
|
6132
7081
|
}
|
|
6133
7082
|
function resetVelocity(entity) {
|
|
6134
7083
|
if (!entity.body) return;
|
|
6135
|
-
entity.body.setLinvel(new
|
|
7084
|
+
entity.body.setLinvel(new Vector322(0, 0, 0), true);
|
|
6136
7085
|
entity.body.setLinearDamping(5);
|
|
6137
7086
|
}
|
|
6138
7087
|
function moveForwardXY(entity, delta, rotation2DAngle) {
|
|
@@ -6262,14 +7211,14 @@ function makeMoveable(entity) {
|
|
|
6262
7211
|
}
|
|
6263
7212
|
|
|
6264
7213
|
// src/lib/actions/capabilities/rotatable.ts
|
|
6265
|
-
import { Euler as Euler3, Vector3 as
|
|
7214
|
+
import { Euler as Euler3, Vector3 as Vector323, MathUtils, Quaternion as Quaternion5 } from "three";
|
|
6266
7215
|
function rotateInDirection(entity, moveVector) {
|
|
6267
7216
|
if (!entity.body) return;
|
|
6268
7217
|
const rotate = Math.atan2(-moveVector.x, moveVector.z);
|
|
6269
7218
|
rotateYEuler(entity, rotate);
|
|
6270
7219
|
}
|
|
6271
7220
|
function rotateYEuler(entity, amount) {
|
|
6272
|
-
rotateEuler(entity, new
|
|
7221
|
+
rotateEuler(entity, new Vector323(0, -amount, 0));
|
|
6273
7222
|
}
|
|
6274
7223
|
function rotateEuler(entity, rotation2) {
|
|
6275
7224
|
if (!entity.group) return;
|
|
@@ -6317,7 +7266,7 @@ function setRotationDegreesZ(entity, z) {
|
|
|
6317
7266
|
}
|
|
6318
7267
|
function setRotation(entity, x, y, z) {
|
|
6319
7268
|
if (!entity.body) return;
|
|
6320
|
-
const quat = new
|
|
7269
|
+
const quat = new Quaternion5().setFromEuler(new Euler3(x, y, z));
|
|
6321
7270
|
entity.body.setRotation({ w: quat.w, x: quat.x, y: quat.y, z: quat.z }, true);
|
|
6322
7271
|
}
|
|
6323
7272
|
function setRotationDegrees(entity, x, y, z) {
|
|
@@ -6515,10 +7464,13 @@ function variableChanges(keys, callback) {
|
|
|
6515
7464
|
// src/api/main.ts
|
|
6516
7465
|
init_game_state();
|
|
6517
7466
|
init_stage_state();
|
|
7467
|
+
init_debug_state();
|
|
6518
7468
|
|
|
6519
7469
|
// src/web-components/zylem-game.ts
|
|
7470
|
+
init_debug_state();
|
|
6520
7471
|
var ZylemGameElement = class extends HTMLElement {
|
|
6521
7472
|
_game = null;
|
|
7473
|
+
_state = {};
|
|
6522
7474
|
container;
|
|
6523
7475
|
constructor() {
|
|
6524
7476
|
super();
|
|
@@ -6530,6 +7482,9 @@ var ZylemGameElement = class extends HTMLElement {
|
|
|
6530
7482
|
this.shadowRoot.appendChild(this.container);
|
|
6531
7483
|
}
|
|
6532
7484
|
set game(game) {
|
|
7485
|
+
if (this._game) {
|
|
7486
|
+
this._game.dispose();
|
|
7487
|
+
}
|
|
6533
7488
|
this._game = game;
|
|
6534
7489
|
game.options.push({ container: this.container });
|
|
6535
7490
|
game.start();
|
|
@@ -6537,6 +7492,35 @@ var ZylemGameElement = class extends HTMLElement {
|
|
|
6537
7492
|
get game() {
|
|
6538
7493
|
return this._game;
|
|
6539
7494
|
}
|
|
7495
|
+
set state(value) {
|
|
7496
|
+
this._state = value;
|
|
7497
|
+
this.syncDebugState();
|
|
7498
|
+
this.syncToolbarState();
|
|
7499
|
+
}
|
|
7500
|
+
get state() {
|
|
7501
|
+
return this._state;
|
|
7502
|
+
}
|
|
7503
|
+
/**
|
|
7504
|
+
* Sync the web component's state with the game-lib's internal debug state
|
|
7505
|
+
*/
|
|
7506
|
+
syncDebugState() {
|
|
7507
|
+
const debugFlag = this._state.gameState?.debugFlag;
|
|
7508
|
+
if (debugFlag !== void 0) {
|
|
7509
|
+
debugState.enabled = debugFlag;
|
|
7510
|
+
}
|
|
7511
|
+
}
|
|
7512
|
+
/**
|
|
7513
|
+
* Sync toolbar state with game-lib's debug state
|
|
7514
|
+
*/
|
|
7515
|
+
syncToolbarState() {
|
|
7516
|
+
const { tool, paused } = this._state.toolbarState ?? {};
|
|
7517
|
+
if (tool !== void 0) {
|
|
7518
|
+
setDebugTool(tool);
|
|
7519
|
+
}
|
|
7520
|
+
if (paused !== void 0) {
|
|
7521
|
+
setPaused(paused);
|
|
7522
|
+
}
|
|
7523
|
+
}
|
|
6540
7524
|
disconnectedCallback() {
|
|
6541
7525
|
if (this._game) {
|
|
6542
7526
|
this._game.dispose();
|
|
@@ -6545,22 +7529,36 @@ var ZylemGameElement = class extends HTMLElement {
|
|
|
6545
7529
|
}
|
|
6546
7530
|
};
|
|
6547
7531
|
customElements.define("zylem-game", ZylemGameElement);
|
|
7532
|
+
|
|
7533
|
+
// src/lib/types/entity-type-map.ts
|
|
7534
|
+
init_actor();
|
|
6548
7535
|
export {
|
|
7536
|
+
ACTOR_TYPE,
|
|
7537
|
+
BOX_TYPE,
|
|
6549
7538
|
Game,
|
|
6550
7539
|
Howl,
|
|
7540
|
+
PLANE_TYPE,
|
|
6551
7541
|
Perspectives,
|
|
6552
7542
|
RAPIER2 as RAPIER,
|
|
7543
|
+
RECT_TYPE,
|
|
7544
|
+
SPHERE_TYPE,
|
|
7545
|
+
SPRITE_TYPE,
|
|
7546
|
+
StageManager,
|
|
7547
|
+
TEXT_TYPE,
|
|
6553
7548
|
THREE2 as THREE,
|
|
7549
|
+
ZONE_TYPE,
|
|
6554
7550
|
ZylemBox,
|
|
6555
7551
|
ZylemGameElement,
|
|
6556
7552
|
actor,
|
|
6557
7553
|
boundary2d,
|
|
6558
7554
|
box,
|
|
6559
7555
|
camera,
|
|
7556
|
+
clearGlobalSubscriptions,
|
|
6560
7557
|
createGame,
|
|
6561
7558
|
createGlobal,
|
|
6562
7559
|
createStage,
|
|
6563
7560
|
createVariable,
|
|
7561
|
+
debugState,
|
|
6564
7562
|
destroy,
|
|
6565
7563
|
entitySpawner,
|
|
6566
7564
|
gameConfig,
|
|
@@ -6588,10 +7586,13 @@ export {
|
|
|
6588
7586
|
ricochetSound,
|
|
6589
7587
|
rotatable,
|
|
6590
7588
|
rotateInDirection,
|
|
7589
|
+
setDebugTool,
|
|
6591
7590
|
setGlobal,
|
|
7591
|
+
setPaused,
|
|
6592
7592
|
setVariable,
|
|
6593
7593
|
sphere,
|
|
6594
7594
|
sprite,
|
|
7595
|
+
stageState2 as stageState,
|
|
6595
7596
|
text,
|
|
6596
7597
|
variableChange,
|
|
6597
7598
|
variableChanges,
|