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