@energy8platform/game-engine 0.1.0 → 0.2.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/dist/core.cjs.js +149 -0
- package/dist/core.cjs.js.map +1 -1
- package/dist/core.d.ts +86 -0
- package/dist/core.esm.js +149 -0
- package/dist/core.esm.js.map +1 -1
- package/dist/index.cjs.js +149 -144
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +86 -84
- package/dist/index.esm.js +149 -144
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/core/GameApplication.ts +8 -0
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) */
|
|
@@ -1789,6 +1935,7 @@ class GameApplication extends EventEmitter {
|
|
|
1789
1935
|
this._destroyed = true;
|
|
1790
1936
|
this._running = false;
|
|
1791
1937
|
this.scenes?.destroy();
|
|
1938
|
+
this.input?.destroy();
|
|
1792
1939
|
this.audio?.destroy();
|
|
1793
1940
|
this.viewport?.destroy();
|
|
1794
1941
|
this.sdk?.destroy();
|
|
@@ -1856,6 +2003,8 @@ class GameApplication extends EventEmitter {
|
|
|
1856
2003
|
this.assets = new AssetManager(basePath, this.config.manifest);
|
|
1857
2004
|
// Audio Manager
|
|
1858
2005
|
this.audio = new AudioManager(this.config.audio);
|
|
2006
|
+
// Input Manager
|
|
2007
|
+
this.input = new InputManager(this.app.canvas);
|
|
1859
2008
|
// Viewport Manager
|
|
1860
2009
|
this.viewport = new ViewportManager(this.app, this._container, {
|
|
1861
2010
|
designWidth: this.config.designWidth,
|
|
@@ -2339,150 +2488,6 @@ class SpineHelper {
|
|
|
2339
2488
|
}
|
|
2340
2489
|
}
|
|
2341
2490
|
|
|
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
2491
|
const DEFAULT_COLORS = {
|
|
2487
2492
|
normal: 0xffd700,
|
|
2488
2493
|
hover: 0xffe44d,
|