@guinetik/gcanvas 1.0.1 → 1.0.2

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.
Files changed (42) hide show
  1. package/demos/coordinates.html +698 -0
  2. package/demos/cube3d.html +23 -0
  3. package/demos/demos.css +17 -3
  4. package/demos/dino.html +42 -0
  5. package/demos/gameobjects.html +626 -0
  6. package/demos/index.html +17 -7
  7. package/demos/js/coordinates.js +840 -0
  8. package/demos/js/cube3d.js +789 -0
  9. package/demos/js/dino.js +1420 -0
  10. package/demos/js/gameobjects.js +176 -0
  11. package/demos/js/plane3d.js +256 -0
  12. package/demos/js/platformer.js +1579 -0
  13. package/demos/js/sphere3d.js +229 -0
  14. package/demos/js/sprite.js +473 -0
  15. package/demos/js/tde/accretiondisk.js +3 -3
  16. package/demos/js/tde/tidalstream.js +2 -2
  17. package/demos/plane3d.html +24 -0
  18. package/demos/platformer.html +43 -0
  19. package/demos/sphere3d.html +24 -0
  20. package/demos/sprite.html +18 -0
  21. package/docs/concepts/coordinate-system.md +384 -0
  22. package/docs/concepts/shapes-vs-gameobjects.md +187 -0
  23. package/docs/fluid-dynamics.md +99 -97
  24. package/package.json +1 -1
  25. package/src/game/game.js +11 -5
  26. package/src/game/objects/index.js +3 -0
  27. package/src/game/objects/platformer-scene.js +411 -0
  28. package/src/game/objects/scene.js +14 -0
  29. package/src/game/objects/sprite.js +529 -0
  30. package/src/game/pipeline.js +20 -16
  31. package/src/game/ui/theme.js +123 -121
  32. package/src/io/input.js +75 -45
  33. package/src/io/mouse.js +44 -19
  34. package/src/io/touch.js +35 -12
  35. package/src/shapes/cube3d.js +599 -0
  36. package/src/shapes/index.js +2 -0
  37. package/src/shapes/plane3d.js +687 -0
  38. package/src/shapes/sphere3d.js +75 -6
  39. package/src/util/camera2d.js +315 -0
  40. package/src/util/index.js +1 -0
  41. package/src/webgl/shaders/plane-shaders.js +332 -0
  42. package/src/webgl/shaders/sphere-shaders.js +4 -2
@@ -1,121 +1,123 @@
1
- /***************************************************************
2
- * theme.js
3
- *
4
- * Terminal × Vercel design system for GCanvas UI components.
5
- *
6
- * Aesthetic principles:
7
- * - Dark translucent backgrounds (depth, layering)
8
- * - Neon green (#0f0) as primary accent
9
- * - Monospace typography throughout
10
- * - Inverted colors on hover for clear feedback
11
- * - Minimal, clean lines inspired by terminal UIs
12
- ***************************************************************/
13
-
14
- /**
15
- * Core theme colors and values for UI components.
16
- * Import this for consistent styling across custom UI elements.
17
- *
18
- * @example
19
- * ```js
20
- * import { UI_THEME } from "gcanvas";
21
- *
22
- * const myButton = new Button(game, {
23
- * colorDefaultBg: UI_THEME.colors.darkBg,
24
- * colorDefaultStroke: UI_THEME.colors.neonGreen,
25
- * colorDefaultText: UI_THEME.colors.neonGreen,
26
- * });
27
- * ```
28
- *
29
- * @constant {Object}
30
- */
31
- export const UI_THEME = {
32
- /**
33
- * Color palette
34
- */
35
- colors: {
36
- // Primary accent - terminal green
37
- neonGreen: "#0f0",
38
- terminalGreen: "#16F529",
39
-
40
- // Secondary accent - cyan
41
- cyanAccent: "#0ff",
42
-
43
- // Backgrounds
44
- darkBg: "rgba(0, 0, 0, 0.85)",
45
- darkerBg: "rgba(0, 0, 0, 0.92)",
46
- hoverBg: "#0f0",
47
- pressedBg: "#0c0",
48
- activeBg: "rgba(0, 255, 0, 0.15)",
49
-
50
- // Text
51
- lightText: "#0f0",
52
- darkText: "#000",
53
- dimText: "rgba(0, 255, 0, 0.7)",
54
-
55
- // Borders
56
- subtleBorder: "rgba(0, 255, 0, 0.4)",
57
- activeBorder: "#0f0",
58
- glowBorder: "rgba(0, 255, 0, 0.5)",
59
- },
60
-
61
- /**
62
- * Typography
63
- */
64
- fonts: {
65
- primary: "monospace",
66
- small: "11px monospace",
67
- medium: "14px monospace",
68
- large: "18px monospace",
69
- heading: "bold 24px monospace",
70
- },
71
-
72
- /**
73
- * Spacing values
74
- */
75
- spacing: {
76
- xs: 4,
77
- sm: 8,
78
- md: 12,
79
- lg: 16,
80
- xl: 24,
81
- },
82
-
83
- /**
84
- * Pre-configured button color schemes
85
- */
86
- button: {
87
- default: {
88
- bg: "rgba(0, 0, 0, 0.85)",
89
- stroke: "rgba(0, 255, 0, 0.4)",
90
- text: "#0f0",
91
- },
92
- hover: {
93
- bg: "#0f0",
94
- stroke: "#0f0",
95
- text: "#000",
96
- },
97
- pressed: {
98
- bg: "#0c0",
99
- stroke: "#0f0",
100
- text: "#000",
101
- },
102
- active: {
103
- bg: "rgba(0, 255, 0, 0.15)",
104
- stroke: "#0f0",
105
- text: "#0f0",
106
- },
107
- },
108
-
109
- /**
110
- * Pre-configured tooltip styles
111
- */
112
- tooltip: {
113
- bg: "rgba(0, 0, 0, 0.92)",
114
- border: "rgba(0, 255, 0, 0.5)",
115
- text: "#0f0",
116
- },
117
- };
118
-
119
- export default UI_THEME;
120
-
121
-
1
+ /***************************************************************
2
+ * theme.js
3
+ *
4
+ * Terminal × Vercel design system for GCanvas UI components.
5
+ *
6
+ * Aesthetic principles:
7
+ * - Dark translucent backgrounds (depth, layering)
8
+ * - Neon green (#0f0) as primary accent
9
+ * - Monospace typography throughout
10
+ * - Inverted colors on hover for clear feedback
11
+ * - Minimal, clean lines inspired by terminal UIs
12
+ ***************************************************************/
13
+
14
+ /**
15
+ * Core theme colors and values for UI components.
16
+ * Import this for consistent styling across custom UI elements.
17
+ *
18
+ * @example
19
+ * ```js
20
+ * import { UI_THEME } from "gcanvas";
21
+ *
22
+ * const myButton = new Button(game, {
23
+ * colorDefaultBg: UI_THEME.colors.darkBg,
24
+ * colorDefaultStroke: UI_THEME.colors.neonGreen,
25
+ * colorDefaultText: UI_THEME.colors.neonGreen,
26
+ * });
27
+ * ```
28
+ *
29
+ * @constant {Object}
30
+ */
31
+ export const UI_THEME = {
32
+ /**
33
+ * Color palette
34
+ */
35
+ colors: {
36
+ // Primary accent - terminal green
37
+ neonGreen: "#0f0",
38
+ terminalGreen: "#16F529",
39
+
40
+ // Secondary accent - cyan
41
+ cyanAccent: "#0ff",
42
+
43
+ // Backgrounds
44
+ darkBg: "rgba(0, 0, 0, 0.85)",
45
+ darkerBg: "rgba(0, 0, 0, 0.92)",
46
+ hoverBg: "#0f0",
47
+ pressedBg: "#0c0",
48
+ activeBg: "rgba(0, 255, 0, 0.15)",
49
+
50
+ // Text
51
+ lightText: "#0f0",
52
+ darkText: "#000",
53
+ dimText: "rgba(0, 255, 0, 0.7)",
54
+
55
+ // Borders
56
+ subtleBorder: "rgba(0, 255, 0, 0.4)",
57
+ activeBorder: "#0f0",
58
+ glowBorder: "rgba(0, 255, 0, 0.5)",
59
+ },
60
+
61
+ /**
62
+ * Typography
63
+ */
64
+ fonts: {
65
+ primary: "monospace",
66
+ small: "11px monospace",
67
+ medium: "14px monospace",
68
+ large: "18px monospace",
69
+ heading: "bold 24px monospace",
70
+ },
71
+
72
+ /**
73
+ * Spacing values
74
+ */
75
+ spacing: {
76
+ xs: 4,
77
+ sm: 8,
78
+ md: 12,
79
+ lg: 16,
80
+ xl: 24,
81
+ },
82
+
83
+ /**
84
+ * Pre-configured button color schemes
85
+ */
86
+ button: {
87
+ default: {
88
+ bg: "rgba(0, 0, 0, 0.85)",
89
+ stroke: "rgba(0, 255, 0, 0.4)",
90
+ text: "#0f0",
91
+ },
92
+ hover: {
93
+ bg: "#0f0",
94
+ stroke: "#0f0",
95
+ text: "#000",
96
+ },
97
+ pressed: {
98
+ bg: "#0c0",
99
+ stroke: "#0f0",
100
+ text: "#000",
101
+ },
102
+ active: {
103
+ bg: "rgba(0, 255, 0, 0.15)",
104
+ stroke: "#0f0",
105
+ text: "#0f0",
106
+ },
107
+ },
108
+
109
+ /**
110
+ * Pre-configured tooltip styles
111
+ */
112
+ tooltip: {
113
+ bg: "rgba(0, 0, 0, 0.92)",
114
+ border: "rgba(0, 255, 0, 0.5)",
115
+ text: "#0f0",
116
+ },
117
+ };
118
+
119
+ export default UI_THEME;
120
+
121
+
122
+
123
+
package/src/io/input.js CHANGED
@@ -1,15 +1,38 @@
1
1
  export class Input {
2
2
  static init(game) {
3
+ // Set defaults for last initialized game (backwards compatibility)
3
4
  Input.game = game;
4
5
  Input.x = 0;
5
6
  Input.y = 0;
6
7
  Input.down = false;
7
- game.events.on("mousedown", Input._onDown);
8
- game.events.on("mouseup", Input._onUp);
9
- game.events.on("mousemove", Input._onMove);
10
- game.events.on("touchstart", Input._onTouchStart);
11
- game.events.on("touchend", Input._onTouchEnd);
12
- game.events.on("touchmove", Input._onTouchMove);
8
+
9
+ // Create bound handlers that know which game they belong to
10
+ game.events.on("mousedown", (e) => Input._onDown(e, game));
11
+ game.events.on("mouseup", (e) => Input._onUp(e, game));
12
+ game.events.on("mousemove", (e) => Input._onMove(e, game));
13
+ game.events.on("touchstart", (e) => Input._onTouchStart(e, game));
14
+ game.events.on("touchend", (e) => Input._onTouchEnd(e, game));
15
+ game.events.on("touchmove", (e) => Input._onTouchMove(e, game));
16
+ }
17
+
18
+ /**
19
+ * Scales CSS pixel coordinates to canvas internal coordinates.
20
+ * This handles the case where the canvas is CSS-scaled (display size differs from resolution).
21
+ * @param {Object} game - The game instance
22
+ * @param {number} cssX - X coordinate in CSS pixels
23
+ * @param {number} cssY - Y coordinate in CSS pixels
24
+ * @returns {{x: number, y: number}} Scaled coordinates in canvas pixels
25
+ */
26
+ static _scaleToCanvas(game, cssX, cssY) {
27
+ const canvas = game.canvas;
28
+ const rect = canvas.getBoundingClientRect();
29
+ // Scale from CSS pixels to canvas internal pixels
30
+ const scaleX = canvas.width / rect.width;
31
+ const scaleY = canvas.height / rect.height;
32
+ return {
33
+ x: cssX * scaleX,
34
+ y: cssY * scaleY
35
+ };
13
36
  }
14
37
 
15
38
  static _setPosition(x, y) {
@@ -17,54 +40,61 @@ export class Input {
17
40
  Input.y = y;
18
41
  }
19
42
 
20
- static _onDown = (e) => {
43
+ static _onDown(e, game) {
21
44
  Input.down = true;
22
- Input._setPosition(e.offsetX, e.offsetY);
23
- Object.defineProperty(e, "x", { value: e.offsetX, configurable: true });
24
- Object.defineProperty(e, "y", { value: e.offsetY, configurable: true });
25
- Input.game.events.emit("inputdown", e);
26
- };
45
+ const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
46
+ Input._setPosition(scaled.x, scaled.y);
47
+ Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
48
+ Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
49
+ game.events.emit("inputdown", e);
50
+ }
27
51
 
28
- static _onUp = (e) => {
52
+ static _onUp(e, game) {
29
53
  Input.down = false;
30
- Input._setPosition(e.offsetX, e.offsetY);
31
- Object.defineProperty(e, "x", { value: e.offsetX, configurable: true });
32
- Object.defineProperty(e, "y", { value: e.offsetY, configurable: true });
33
- Input.game.events.emit("inputup", e);
34
- };
54
+ const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
55
+ Input._setPosition(scaled.x, scaled.y);
56
+ Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
57
+ Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
58
+ game.events.emit("inputup", e);
59
+ }
35
60
 
36
- static _onMove = (e) => {
37
- Input._setPosition(e.offsetX, e.offsetY);
38
- Object.defineProperty(e, "x", { value: e.offsetX, configurable: true });
39
- Object.defineProperty(e, "y", { value: e.offsetY, configurable: true });
40
- Input.game.events.emit("inputmove", e);
41
- };
61
+ static _onMove(e, game) {
62
+ const scaled = Input._scaleToCanvas(game, e.offsetX, e.offsetY);
63
+ Input._setPosition(scaled.x, scaled.y);
64
+ Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
65
+ Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
66
+ game.events.emit("inputmove", e);
67
+ }
42
68
 
43
- static _onTouchStart = (e) => {
69
+ static _onTouchStart(e, game) {
44
70
  const touch = e.touches[0];
45
- const rect = Input.game.canvas.getBoundingClientRect();
71
+ const rect = game.canvas.getBoundingClientRect();
46
72
  Input.down = true;
47
- const x = touch.clientX - rect.left;
48
- const y = touch.clientY - rect.top;
49
- Input._setPosition(x, y);
50
- Object.defineProperty(e, "x", { value: x, configurable: true });
51
- Object.defineProperty(e, "y", { value: y, configurable: true });
52
- Input.game.events.emit("inputdown", e);
53
- };
73
+ // Calculate CSS-relative position, then scale to canvas coordinates
74
+ const cssX = touch.clientX - rect.left;
75
+ const cssY = touch.clientY - rect.top;
76
+ const scaled = Input._scaleToCanvas(game, cssX, cssY);
77
+ Input._setPosition(scaled.x, scaled.y);
78
+ Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
79
+ Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
80
+ game.events.emit("inputdown", e);
81
+ }
54
82
 
55
- static _onTouchEnd = (e) => {
83
+ static _onTouchEnd(e, game) {
56
84
  Input.down = false;
57
- Input.game.events.emit("inputup", e);
58
- };
85
+ game.events.emit("inputup", e);
86
+ }
59
87
 
60
- static _onTouchMove = (e) => {
88
+ static _onTouchMove(e, game) {
61
89
  const touch = e.touches[0];
62
- const rect = Input.game.canvas.getBoundingClientRect();
63
- const x = touch.clientX - rect.left;
64
- const y = touch.clientY - rect.top;
65
- Input._setPosition(x, y);
66
- Object.defineProperty(e, "x", { value: x, configurable: true });
67
- Object.defineProperty(e, "y", { value: y, configurable: true });
68
- Input.game.events.emit("inputmove", e);
69
- };
90
+ const rect = game.canvas.getBoundingClientRect();
91
+ // Calculate CSS-relative position, then scale to canvas coordinates
92
+ const cssX = touch.clientX - rect.left;
93
+ const cssY = touch.clientY - rect.top;
94
+ const scaled = Input._scaleToCanvas(game, cssX, cssY);
95
+ Input._setPosition(scaled.x, scaled.y);
96
+ Object.defineProperty(e, "x", { value: scaled.x, configurable: true });
97
+ Object.defineProperty(e, "y", { value: scaled.y, configurable: true });
98
+ game.events.emit("inputmove", e);
99
+ }
70
100
  }
package/src/io/mouse.js CHANGED
@@ -1,5 +1,12 @@
1
1
  export class Mouse {
2
+ // Map of canvas -> game for multi-game support
3
+ static _gameMap = new Map();
4
+
2
5
  static init(game) {
6
+ // Store mapping from canvas to game
7
+ Mouse._gameMap.set(game.canvas, game);
8
+
9
+ // Set defaults for last initialized game (backwards compatibility)
3
10
  Mouse.game = game;
4
11
  Mouse.canvas = game.canvas;
5
12
  Mouse.x = 0;
@@ -8,42 +15,59 @@ export class Mouse {
8
15
  Mouse.middleDown = false;
9
16
  Mouse.rightDown = false;
10
17
 
11
- Mouse.canvas.addEventListener("mousemove", Mouse._onMove);
12
- Mouse.canvas.addEventListener("mousedown", Mouse._onDown);
13
- Mouse.canvas.addEventListener("mouseup", Mouse._onUp);
14
- Mouse.canvas.addEventListener("click", Mouse._onClick);
15
- Mouse.canvas.addEventListener("wheel", Mouse._onWheel);
18
+ game.canvas.addEventListener("mousemove", Mouse._onMove);
19
+ game.canvas.addEventListener("mousedown", Mouse._onDown);
20
+ game.canvas.addEventListener("mouseup", Mouse._onUp);
21
+ game.canvas.addEventListener("click", Mouse._onClick);
22
+ game.canvas.addEventListener("wheel", Mouse._onWheel);
23
+ }
24
+
25
+ // Get the game instance for a given event's target canvas
26
+ static _getGameForEvent(e) {
27
+ const canvas = e.currentTarget;
28
+ return Mouse._gameMap.get(canvas) || Mouse.game;
16
29
  }
17
30
 
18
- static _updatePosition(e) {
19
- const rect = Mouse.canvas.getBoundingClientRect();
20
- Mouse.x = e.clientX - rect.left;
21
- Mouse.y = e.clientY - rect.top;
31
+ static _updatePosition(e, game) {
32
+ const canvas = game.canvas;
33
+ const rect = canvas.getBoundingClientRect();
34
+ // Calculate CSS-relative position
35
+ const cssX = e.clientX - rect.left;
36
+ const cssY = e.clientY - rect.top;
37
+ // Scale to canvas internal coordinates (handles CSS scaling)
38
+ const scaleX = canvas.width / rect.width;
39
+ const scaleY = canvas.height / rect.height;
40
+ Mouse.x = cssX * scaleX;
41
+ Mouse.y = cssY * scaleY;
22
42
  }
23
43
 
24
44
  static _onMove = (e) => {
25
- Mouse._updatePosition(e);
26
- Mouse.game.events.emit("mousemove", e);
45
+ const game = Mouse._getGameForEvent(e);
46
+ Mouse._updatePosition(e, game);
47
+ game.events.emit("mousemove", e);
27
48
  };
28
49
 
29
50
  static _onDown = (e) => {
30
- Mouse._updatePosition(e);
51
+ const game = Mouse._getGameForEvent(e);
52
+ Mouse._updatePosition(e, game);
31
53
  if (e.button === 0) Mouse.leftDown = true;
32
54
  if (e.button === 1) Mouse.middleDown = true;
33
55
  if (e.button === 2) Mouse.rightDown = true;
34
- Mouse.game.events.emit("mousedown", e);
56
+ game.events.emit("mousedown", e);
35
57
  };
36
58
 
37
59
  static _onUp = (e) => {
38
- Mouse._updatePosition(e);
60
+ const game = Mouse._getGameForEvent(e);
61
+ Mouse._updatePosition(e, game);
39
62
  if (e.button === 0) Mouse.leftDown = false;
40
63
  if (e.button === 1) Mouse.middleDown = false;
41
64
  if (e.button === 2) Mouse.rightDown = false;
42
- Mouse.game.events.emit("mouseup", e);
65
+ game.events.emit("mouseup", e);
43
66
  };
44
67
 
45
68
  static _onClick = (e) => {
46
- Mouse._updatePosition(e);
69
+ const game = Mouse._getGameForEvent(e);
70
+ Mouse._updatePosition(e, game);
47
71
  // Emit enhanced event with canvas-relative coordinates
48
72
  // Note: e is a MouseEvent, add canvas-relative x/y directly
49
73
  e.canvasX = Mouse.x;
@@ -51,11 +75,12 @@ export class Mouse {
51
75
  // Also set x/y for convenience (matches expected fluent API)
52
76
  Object.defineProperty(e, 'x', { value: Mouse.x, writable: false });
53
77
  Object.defineProperty(e, 'y', { value: Mouse.y, writable: false });
54
- Mouse.game.events.emit("click", e);
78
+ game.events.emit("click", e);
55
79
  };
56
80
 
57
81
  static _onWheel = (e) => {
58
- Mouse._updatePosition(e);
59
- Mouse.game.events.emit("wheel", e);
82
+ const game = Mouse._getGameForEvent(e);
83
+ Mouse._updatePosition(e, game);
84
+ game.events.emit("wheel", e);
60
85
  };
61
86
  }
package/src/io/touch.js CHANGED
@@ -1,39 +1,62 @@
1
1
  export class Touch {
2
+ // Map of canvas -> game for multi-game support
3
+ static _gameMap = new Map();
4
+
2
5
  static init(game) {
6
+ // Store mapping from canvas to game
7
+ Touch._gameMap.set(game.canvas, game);
8
+
9
+ // Set defaults for last initialized game (backwards compatibility)
3
10
  Touch.game = game;
4
11
  Touch.canvas = game.canvas;
5
12
  Touch.x = 0;
6
13
  Touch.y = 0;
7
14
  Touch.active = false;
8
15
 
9
- Touch.canvas.addEventListener("touchstart", Touch._onStart);
10
- Touch.canvas.addEventListener("touchend", Touch._onEnd);
11
- Touch.canvas.addEventListener("touchmove", Touch._onMove);
16
+ game.canvas.addEventListener("touchstart", Touch._onStart);
17
+ game.canvas.addEventListener("touchend", Touch._onEnd);
18
+ game.canvas.addEventListener("touchmove", Touch._onMove);
19
+ }
20
+
21
+ // Get the game instance for a given event's target canvas
22
+ static _getGameForEvent(e) {
23
+ const canvas = e.currentTarget;
24
+ return Touch._gameMap.get(canvas) || Touch.game;
12
25
  }
13
26
 
14
- static _updatePosition(touch) {
15
- const rect = Touch.canvas.getBoundingClientRect();
16
- Touch.x = touch.clientX - rect.left;
17
- Touch.y = touch.clientY - rect.top;
27
+ static _updatePosition(touch, game) {
28
+ const canvas = game.canvas;
29
+ const rect = canvas.getBoundingClientRect();
30
+ // Calculate CSS-relative position
31
+ const cssX = touch.clientX - rect.left;
32
+ const cssY = touch.clientY - rect.top;
33
+ // Scale to canvas internal coordinates (handles CSS scaling)
34
+ const scaleX = canvas.width / rect.width;
35
+ const scaleY = canvas.height / rect.height;
36
+ Touch.x = cssX * scaleX;
37
+ Touch.y = cssY * scaleY;
18
38
  }
19
39
 
20
40
  static _onStart = (e) => {
21
41
  if (e.touches.length > 0) {
42
+ const game = Touch._getGameForEvent(e);
22
43
  Touch.active = true;
23
- Touch._updatePosition(e.touches[0]);
24
- Touch.game.events.emit("touchstart", e);
44
+ Touch._updatePosition(e.touches[0], game);
45
+ game.events.emit("touchstart", e);
25
46
  }
26
47
  };
27
48
 
28
49
  static _onEnd = (e) => {
50
+ const game = Touch._getGameForEvent(e);
29
51
  Touch.active = false;
30
- Touch.game.events.emit("touchend", e);
52
+ game.events.emit("touchend", e);
31
53
  };
32
54
 
33
55
  static _onMove = (e) => {
34
56
  if (e.touches.length > 0) {
35
- Touch._updatePosition(e.touches[0]);
36
- Touch.game.events.emit("touchmove", e);
57
+ const game = Touch._getGameForEvent(e);
58
+ Touch._updatePosition(e.touches[0], game);
59
+ game.events.emit("touchmove", e);
37
60
  }
38
61
  };
39
62
  }