@energy8platform/game-engine 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -21
- package/dist/core.cjs.js +155 -1
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +86 -0
- package/dist/core.esm.js +155 -1
- package/dist/core.esm.js.map +1 -1
- package/dist/index.cjs.js +155 -145
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +86 -84
- package/dist/index.esm.js +155 -145
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/GameApplication.ts +16 -1
package/dist/index.esm.js
CHANGED
|
@@ -991,6 +991,150 @@ class AudioManager {
|
|
|
991
991
|
}
|
|
992
992
|
}
|
|
993
993
|
|
|
994
|
+
/**
|
|
995
|
+
* Unified input manager for touch, mouse, and keyboard.
|
|
996
|
+
*
|
|
997
|
+
* Features:
|
|
998
|
+
* - Unified pointer events (works with touch + mouse)
|
|
999
|
+
* - Swipe gesture detection
|
|
1000
|
+
* - Keyboard input with isKeyDown state
|
|
1001
|
+
* - Input locking (block input during animations)
|
|
1002
|
+
*
|
|
1003
|
+
* @example
|
|
1004
|
+
* ```ts
|
|
1005
|
+
* const input = new InputManager(app.canvas);
|
|
1006
|
+
*
|
|
1007
|
+
* input.on('tap', ({ x, y }) => console.log('Tapped at', x, y));
|
|
1008
|
+
* input.on('swipe', ({ direction }) => console.log('Swiped', direction));
|
|
1009
|
+
* input.on('keydown', ({ key }) => {
|
|
1010
|
+
* if (key === ' ') spin();
|
|
1011
|
+
* });
|
|
1012
|
+
*
|
|
1013
|
+
* // Block input during animations
|
|
1014
|
+
* input.lock();
|
|
1015
|
+
* await playAnimation();
|
|
1016
|
+
* input.unlock();
|
|
1017
|
+
* ```
|
|
1018
|
+
*/
|
|
1019
|
+
class InputManager extends EventEmitter {
|
|
1020
|
+
_canvas;
|
|
1021
|
+
_locked = false;
|
|
1022
|
+
_keysDown = new Set();
|
|
1023
|
+
_destroyed = false;
|
|
1024
|
+
// Gesture tracking
|
|
1025
|
+
_pointerStart = null;
|
|
1026
|
+
_swipeThreshold = 50; // minimum distance in px
|
|
1027
|
+
_swipeMaxTime = 300; // max ms for swipe gesture
|
|
1028
|
+
constructor(canvas) {
|
|
1029
|
+
super();
|
|
1030
|
+
this._canvas = canvas;
|
|
1031
|
+
this.setupPointerEvents();
|
|
1032
|
+
this.setupKeyboardEvents();
|
|
1033
|
+
}
|
|
1034
|
+
/** Whether input is currently locked */
|
|
1035
|
+
get locked() {
|
|
1036
|
+
return this._locked;
|
|
1037
|
+
}
|
|
1038
|
+
/** Lock all input (e.g., during animations) */
|
|
1039
|
+
lock() {
|
|
1040
|
+
this._locked = true;
|
|
1041
|
+
}
|
|
1042
|
+
/** Unlock input */
|
|
1043
|
+
unlock() {
|
|
1044
|
+
this._locked = false;
|
|
1045
|
+
}
|
|
1046
|
+
/** Check if a key is currently pressed */
|
|
1047
|
+
isKeyDown(key) {
|
|
1048
|
+
return this._keysDown.has(key.toLowerCase());
|
|
1049
|
+
}
|
|
1050
|
+
/** Destroy the input manager */
|
|
1051
|
+
destroy() {
|
|
1052
|
+
this._destroyed = true;
|
|
1053
|
+
this._canvas.removeEventListener('pointerdown', this.onPointerDown);
|
|
1054
|
+
this._canvas.removeEventListener('pointerup', this.onPointerUp);
|
|
1055
|
+
this._canvas.removeEventListener('pointermove', this.onPointerMove);
|
|
1056
|
+
document.removeEventListener('keydown', this.onKeyDown);
|
|
1057
|
+
document.removeEventListener('keyup', this.onKeyUp);
|
|
1058
|
+
this._keysDown.clear();
|
|
1059
|
+
this.removeAllListeners();
|
|
1060
|
+
}
|
|
1061
|
+
// ─── Private: Pointer ──────────────────────────────────
|
|
1062
|
+
setupPointerEvents() {
|
|
1063
|
+
this._canvas.addEventListener('pointerdown', this.onPointerDown);
|
|
1064
|
+
this._canvas.addEventListener('pointerup', this.onPointerUp);
|
|
1065
|
+
this._canvas.addEventListener('pointermove', this.onPointerMove);
|
|
1066
|
+
}
|
|
1067
|
+
onPointerDown = (e) => {
|
|
1068
|
+
if (this._locked || this._destroyed)
|
|
1069
|
+
return;
|
|
1070
|
+
const pos = this.getCanvasPosition(e);
|
|
1071
|
+
this._pointerStart = { ...pos, time: Date.now() };
|
|
1072
|
+
this.emit('press', pos);
|
|
1073
|
+
};
|
|
1074
|
+
onPointerUp = (e) => {
|
|
1075
|
+
if (this._locked || this._destroyed)
|
|
1076
|
+
return;
|
|
1077
|
+
const pos = this.getCanvasPosition(e);
|
|
1078
|
+
this.emit('release', pos);
|
|
1079
|
+
// Check for tap vs swipe
|
|
1080
|
+
if (this._pointerStart) {
|
|
1081
|
+
const dx = pos.x - this._pointerStart.x;
|
|
1082
|
+
const dy = pos.y - this._pointerStart.y;
|
|
1083
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
1084
|
+
const elapsed = Date.now() - this._pointerStart.time;
|
|
1085
|
+
if (dist > this._swipeThreshold && elapsed < this._swipeMaxTime) {
|
|
1086
|
+
// Swipe detected
|
|
1087
|
+
const absDx = Math.abs(dx);
|
|
1088
|
+
const absDy = Math.abs(dy);
|
|
1089
|
+
let direction;
|
|
1090
|
+
if (absDx > absDy) {
|
|
1091
|
+
direction = dx > 0 ? 'right' : 'left';
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
direction = dy > 0 ? 'down' : 'up';
|
|
1095
|
+
}
|
|
1096
|
+
this.emit('swipe', { direction, velocity: dist / elapsed });
|
|
1097
|
+
}
|
|
1098
|
+
else if (dist < 10) {
|
|
1099
|
+
// Tap (minimal movement)
|
|
1100
|
+
this.emit('tap', pos);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
this._pointerStart = null;
|
|
1104
|
+
};
|
|
1105
|
+
onPointerMove = (e) => {
|
|
1106
|
+
if (this._locked || this._destroyed)
|
|
1107
|
+
return;
|
|
1108
|
+
this.emit('move', this.getCanvasPosition(e));
|
|
1109
|
+
};
|
|
1110
|
+
getCanvasPosition(e) {
|
|
1111
|
+
const rect = this._canvas.getBoundingClientRect();
|
|
1112
|
+
return {
|
|
1113
|
+
x: e.clientX - rect.left,
|
|
1114
|
+
y: e.clientY - rect.top,
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
// ─── Private: Keyboard ─────────────────────────────────
|
|
1118
|
+
setupKeyboardEvents() {
|
|
1119
|
+
document.addEventListener('keydown', this.onKeyDown);
|
|
1120
|
+
document.addEventListener('keyup', this.onKeyUp);
|
|
1121
|
+
}
|
|
1122
|
+
onKeyDown = (e) => {
|
|
1123
|
+
if (this._locked || this._destroyed)
|
|
1124
|
+
return;
|
|
1125
|
+
this._keysDown.add(e.key.toLowerCase());
|
|
1126
|
+
this.emit('keydown', { key: e.key, code: e.code });
|
|
1127
|
+
};
|
|
1128
|
+
onKeyUp = (e) => {
|
|
1129
|
+
if (this._destroyed)
|
|
1130
|
+
return;
|
|
1131
|
+
this._keysDown.delete(e.key.toLowerCase());
|
|
1132
|
+
if (this._locked)
|
|
1133
|
+
return;
|
|
1134
|
+
this.emit('keyup', { key: e.key, code: e.code });
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
|
|
994
1138
|
/**
|
|
995
1139
|
* Manages responsive scaling of the game canvas to fit its container.
|
|
996
1140
|
*
|
|
@@ -1694,6 +1838,8 @@ class GameApplication extends EventEmitter {
|
|
|
1694
1838
|
assets;
|
|
1695
1839
|
/** Audio manager */
|
|
1696
1840
|
audio;
|
|
1841
|
+
/** Input manager */
|
|
1842
|
+
input;
|
|
1697
1843
|
/** Viewport manager */
|
|
1698
1844
|
viewport;
|
|
1699
1845
|
/** SDK instance (null in offline mode) */
|
|
@@ -1770,6 +1916,7 @@ class GameApplication extends EventEmitter {
|
|
|
1770
1916
|
removeCSSPreloader(this._container);
|
|
1771
1917
|
// 8. Load assets with loading screen
|
|
1772
1918
|
await this.loadAssets(firstScene, sceneData);
|
|
1919
|
+
this.emit('loaded', undefined);
|
|
1773
1920
|
// 9. Start the game loop
|
|
1774
1921
|
this._running = true;
|
|
1775
1922
|
this.emit('started', undefined);
|
|
@@ -1789,12 +1936,13 @@ class GameApplication extends EventEmitter {
|
|
|
1789
1936
|
this._destroyed = true;
|
|
1790
1937
|
this._running = false;
|
|
1791
1938
|
this.scenes?.destroy();
|
|
1939
|
+
this.input?.destroy();
|
|
1792
1940
|
this.audio?.destroy();
|
|
1793
1941
|
this.viewport?.destroy();
|
|
1794
1942
|
this.sdk?.destroy();
|
|
1795
1943
|
this.app?.destroy(true, { children: true, texture: true });
|
|
1796
|
-
this.removeAllListeners();
|
|
1797
1944
|
this.emit('destroyed', undefined);
|
|
1945
|
+
this.removeAllListeners();
|
|
1798
1946
|
}
|
|
1799
1947
|
// ─── Private initialization steps ──────────────────────
|
|
1800
1948
|
resolveContainer() {
|
|
@@ -1856,6 +2004,8 @@ class GameApplication extends EventEmitter {
|
|
|
1856
2004
|
this.assets = new AssetManager(basePath, this.config.manifest);
|
|
1857
2005
|
// Audio Manager
|
|
1858
2006
|
this.audio = new AudioManager(this.config.audio);
|
|
2007
|
+
// Input Manager
|
|
2008
|
+
this.input = new InputManager(this.app.canvas);
|
|
1859
2009
|
// Viewport Manager
|
|
1860
2010
|
this.viewport = new ViewportManager(this.app, this._container, {
|
|
1861
2011
|
designWidth: this.config.designWidth,
|
|
@@ -1873,6 +2023,10 @@ class GameApplication extends EventEmitter {
|
|
|
1873
2023
|
this.viewport.on('orientationChange', (orientation) => {
|
|
1874
2024
|
this.emit('orientationChange', orientation);
|
|
1875
2025
|
});
|
|
2026
|
+
// Wire scene changes → engine event
|
|
2027
|
+
this.scenes.on('change', ({ from, to }) => {
|
|
2028
|
+
this.emit('sceneChange', { from, to });
|
|
2029
|
+
});
|
|
1876
2030
|
// Connect ticker → scene updates
|
|
1877
2031
|
this.app.ticker.add((ticker) => {
|
|
1878
2032
|
// Always update scenes (loading screen needs onUpdate before _running=true)
|
|
@@ -2339,150 +2493,6 @@ class SpineHelper {
|
|
|
2339
2493
|
}
|
|
2340
2494
|
}
|
|
2341
2495
|
|
|
2342
|
-
/**
|
|
2343
|
-
* Unified input manager for touch, mouse, and keyboard.
|
|
2344
|
-
*
|
|
2345
|
-
* Features:
|
|
2346
|
-
* - Unified pointer events (works with touch + mouse)
|
|
2347
|
-
* - Swipe gesture detection
|
|
2348
|
-
* - Keyboard input with isKeyDown state
|
|
2349
|
-
* - Input locking (block input during animations)
|
|
2350
|
-
*
|
|
2351
|
-
* @example
|
|
2352
|
-
* ```ts
|
|
2353
|
-
* const input = new InputManager(app.canvas);
|
|
2354
|
-
*
|
|
2355
|
-
* input.on('tap', ({ x, y }) => console.log('Tapped at', x, y));
|
|
2356
|
-
* input.on('swipe', ({ direction }) => console.log('Swiped', direction));
|
|
2357
|
-
* input.on('keydown', ({ key }) => {
|
|
2358
|
-
* if (key === ' ') spin();
|
|
2359
|
-
* });
|
|
2360
|
-
*
|
|
2361
|
-
* // Block input during animations
|
|
2362
|
-
* input.lock();
|
|
2363
|
-
* await playAnimation();
|
|
2364
|
-
* input.unlock();
|
|
2365
|
-
* ```
|
|
2366
|
-
*/
|
|
2367
|
-
class InputManager extends EventEmitter {
|
|
2368
|
-
_canvas;
|
|
2369
|
-
_locked = false;
|
|
2370
|
-
_keysDown = new Set();
|
|
2371
|
-
_destroyed = false;
|
|
2372
|
-
// Gesture tracking
|
|
2373
|
-
_pointerStart = null;
|
|
2374
|
-
_swipeThreshold = 50; // minimum distance in px
|
|
2375
|
-
_swipeMaxTime = 300; // max ms for swipe gesture
|
|
2376
|
-
constructor(canvas) {
|
|
2377
|
-
super();
|
|
2378
|
-
this._canvas = canvas;
|
|
2379
|
-
this.setupPointerEvents();
|
|
2380
|
-
this.setupKeyboardEvents();
|
|
2381
|
-
}
|
|
2382
|
-
/** Whether input is currently locked */
|
|
2383
|
-
get locked() {
|
|
2384
|
-
return this._locked;
|
|
2385
|
-
}
|
|
2386
|
-
/** Lock all input (e.g., during animations) */
|
|
2387
|
-
lock() {
|
|
2388
|
-
this._locked = true;
|
|
2389
|
-
}
|
|
2390
|
-
/** Unlock input */
|
|
2391
|
-
unlock() {
|
|
2392
|
-
this._locked = false;
|
|
2393
|
-
}
|
|
2394
|
-
/** Check if a key is currently pressed */
|
|
2395
|
-
isKeyDown(key) {
|
|
2396
|
-
return this._keysDown.has(key.toLowerCase());
|
|
2397
|
-
}
|
|
2398
|
-
/** Destroy the input manager */
|
|
2399
|
-
destroy() {
|
|
2400
|
-
this._destroyed = true;
|
|
2401
|
-
this._canvas.removeEventListener('pointerdown', this.onPointerDown);
|
|
2402
|
-
this._canvas.removeEventListener('pointerup', this.onPointerUp);
|
|
2403
|
-
this._canvas.removeEventListener('pointermove', this.onPointerMove);
|
|
2404
|
-
document.removeEventListener('keydown', this.onKeyDown);
|
|
2405
|
-
document.removeEventListener('keyup', this.onKeyUp);
|
|
2406
|
-
this._keysDown.clear();
|
|
2407
|
-
this.removeAllListeners();
|
|
2408
|
-
}
|
|
2409
|
-
// ─── Private: Pointer ──────────────────────────────────
|
|
2410
|
-
setupPointerEvents() {
|
|
2411
|
-
this._canvas.addEventListener('pointerdown', this.onPointerDown);
|
|
2412
|
-
this._canvas.addEventListener('pointerup', this.onPointerUp);
|
|
2413
|
-
this._canvas.addEventListener('pointermove', this.onPointerMove);
|
|
2414
|
-
}
|
|
2415
|
-
onPointerDown = (e) => {
|
|
2416
|
-
if (this._locked || this._destroyed)
|
|
2417
|
-
return;
|
|
2418
|
-
const pos = this.getCanvasPosition(e);
|
|
2419
|
-
this._pointerStart = { ...pos, time: Date.now() };
|
|
2420
|
-
this.emit('press', pos);
|
|
2421
|
-
};
|
|
2422
|
-
onPointerUp = (e) => {
|
|
2423
|
-
if (this._locked || this._destroyed)
|
|
2424
|
-
return;
|
|
2425
|
-
const pos = this.getCanvasPosition(e);
|
|
2426
|
-
this.emit('release', pos);
|
|
2427
|
-
// Check for tap vs swipe
|
|
2428
|
-
if (this._pointerStart) {
|
|
2429
|
-
const dx = pos.x - this._pointerStart.x;
|
|
2430
|
-
const dy = pos.y - this._pointerStart.y;
|
|
2431
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
2432
|
-
const elapsed = Date.now() - this._pointerStart.time;
|
|
2433
|
-
if (dist > this._swipeThreshold && elapsed < this._swipeMaxTime) {
|
|
2434
|
-
// Swipe detected
|
|
2435
|
-
const absDx = Math.abs(dx);
|
|
2436
|
-
const absDy = Math.abs(dy);
|
|
2437
|
-
let direction;
|
|
2438
|
-
if (absDx > absDy) {
|
|
2439
|
-
direction = dx > 0 ? 'right' : 'left';
|
|
2440
|
-
}
|
|
2441
|
-
else {
|
|
2442
|
-
direction = dy > 0 ? 'down' : 'up';
|
|
2443
|
-
}
|
|
2444
|
-
this.emit('swipe', { direction, velocity: dist / elapsed });
|
|
2445
|
-
}
|
|
2446
|
-
else if (dist < 10) {
|
|
2447
|
-
// Tap (minimal movement)
|
|
2448
|
-
this.emit('tap', pos);
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
this._pointerStart = null;
|
|
2452
|
-
};
|
|
2453
|
-
onPointerMove = (e) => {
|
|
2454
|
-
if (this._locked || this._destroyed)
|
|
2455
|
-
return;
|
|
2456
|
-
this.emit('move', this.getCanvasPosition(e));
|
|
2457
|
-
};
|
|
2458
|
-
getCanvasPosition(e) {
|
|
2459
|
-
const rect = this._canvas.getBoundingClientRect();
|
|
2460
|
-
return {
|
|
2461
|
-
x: e.clientX - rect.left,
|
|
2462
|
-
y: e.clientY - rect.top,
|
|
2463
|
-
};
|
|
2464
|
-
}
|
|
2465
|
-
// ─── Private: Keyboard ─────────────────────────────────
|
|
2466
|
-
setupKeyboardEvents() {
|
|
2467
|
-
document.addEventListener('keydown', this.onKeyDown);
|
|
2468
|
-
document.addEventListener('keyup', this.onKeyUp);
|
|
2469
|
-
}
|
|
2470
|
-
onKeyDown = (e) => {
|
|
2471
|
-
if (this._locked || this._destroyed)
|
|
2472
|
-
return;
|
|
2473
|
-
this._keysDown.add(e.key.toLowerCase());
|
|
2474
|
-
this.emit('keydown', { key: e.key, code: e.code });
|
|
2475
|
-
};
|
|
2476
|
-
onKeyUp = (e) => {
|
|
2477
|
-
if (this._destroyed)
|
|
2478
|
-
return;
|
|
2479
|
-
this._keysDown.delete(e.key.toLowerCase());
|
|
2480
|
-
if (this._locked)
|
|
2481
|
-
return;
|
|
2482
|
-
this.emit('keyup', { key: e.key, code: e.code });
|
|
2483
|
-
};
|
|
2484
|
-
}
|
|
2485
|
-
|
|
2486
2496
|
const DEFAULT_COLORS = {
|
|
2487
2497
|
normal: 0xffd700,
|
|
2488
2498
|
hover: 0xffe44d,
|