like2d 2.3.0 → 2.5.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/engine.js CHANGED
@@ -1,3 +1,10 @@
1
+ import { Audio } from './core/audio';
2
+ import { Input } from './core/input';
3
+ import { Timer } from './core/timer';
4
+ import { Keyboard } from './core/keyboard';
5
+ import { Mouse } from './core/mouse';
6
+ import { Gamepad } from './core/gamepad';
7
+ import { newState, bindGraphics } from './core/graphics';
1
8
  import { CanvasManager } from './core/canvas-manager';
2
9
  export class Engine {
3
10
  constructor(container) {
@@ -13,12 +20,6 @@ export class Engine {
13
20
  writable: true,
14
21
  value: void 0
15
22
  });
16
- Object.defineProperty(this, "deps", {
17
- enumerable: true,
18
- configurable: true,
19
- writable: true,
20
- value: null
21
- });
22
23
  Object.defineProperty(this, "isRunning", {
23
24
  enumerable: true,
24
25
  configurable: true,
@@ -49,6 +50,13 @@ export class Engine {
49
50
  writable: true,
50
51
  value: null
51
52
  });
53
+ // Public Like object with all systems - initialized in constructor
54
+ Object.defineProperty(this, "like", {
55
+ enumerable: true,
56
+ configurable: true,
57
+ writable: true,
58
+ value: void 0
59
+ });
52
60
  this.canvas = document.createElement('canvas');
53
61
  this.canvas.style.border = '1px solid #ccc';
54
62
  this.canvas.style.display = 'block';
@@ -58,66 +66,95 @@ export class Engine {
58
66
  this.ctx = ctx;
59
67
  this.container = container;
60
68
  this.container.appendChild(this.canvas);
61
- this.canvasManager = new CanvasManager(this.canvas, this.container, this.ctx, { mode: 'native' });
62
- // Internal listener to forward to onEvent
69
+ this.canvasManager = new CanvasManager(this.canvas, this.container, this.ctx, { pixelResolution: null, fullscreen: false });
70
+ // Create graphics state and bind it
71
+ const gfxState = newState(this.ctx);
72
+ const gfx = bindGraphics(gfxState);
73
+ // Create all subsystems
74
+ const audio = new Audio();
75
+ const timer = new Timer();
76
+ const keyboard = new Keyboard();
77
+ const mouse = new Mouse((cssX, cssY) => this.canvasManager.transformMousePosition(cssX, cssY));
78
+ const gamepad = new Gamepad();
79
+ const input = new Input({ keyboard, mouse, gamepad });
80
+ // Create the Like object with all systems
81
+ this.like = {
82
+ audio,
83
+ timer,
84
+ input,
85
+ keyboard,
86
+ mouse,
87
+ gamepad,
88
+ gfx,
89
+ setMode: (m) => this.setMode(m),
90
+ getMode: () => this.canvasManager.getMode(),
91
+ getCanvasSize: () => [this.canvas.width, this.canvas.height],
92
+ };
93
+ // Set up input event handlers
94
+ keyboard.onKeyEvent = (scancode, keycode, type) => {
95
+ this.dispatchEvent(type === 'keydown' ? 'keypressed' : 'keyreleased', [scancode, keycode]);
96
+ };
97
+ mouse.onMouseEvent = (clientX, clientY, button, type) => {
98
+ const [x, y] = this.canvasManager.transformMousePosition(clientX, clientY);
99
+ const b = (button ?? 0) + 1;
100
+ this.dispatchEvent(type === 'mousedown' ? 'mousepressed' : 'mousereleased', [x, y, b]);
101
+ };
102
+ gamepad.onButtonEvent = (gpIndex, buttonIndex, buttonName, pressed) => {
103
+ this.dispatchEvent(pressed ? 'gamepadpressed' : 'gamepadreleased', [gpIndex, buttonIndex, buttonName]);
104
+ };
105
+ // Internal listener to forward resize events
63
106
  this.canvasManager.onResize = (size, pixelSize, fullscreen) => {
64
107
  this.dispatchEvent('resize', [size, pixelSize, fullscreen]);
65
108
  };
109
+ // Listen for fullscreen changes to update mode
110
+ document.addEventListener('fullscreenchange', () => this.handleFullscreenChange());
66
111
  }
67
- setScaling(config) {
68
- this.canvasManager.setConfig(config);
69
- }
70
- setDeps(deps) {
71
- this.deps = deps;
112
+ handleFullscreenChange() {
113
+ const mode = this.canvasManager.getMode();
114
+ const isFullscreen = !!document.fullscreenElement;
115
+ if (mode.fullscreen !== isFullscreen) {
116
+ this.canvasManager.setMode({ ...mode, fullscreen: isFullscreen });
117
+ }
72
118
  }
73
- dispose() {
74
- this.isRunning = false;
75
- this.deps?.keyboard.dispose();
76
- this.deps?.mouse.dispose();
77
- this.deps?.gamepad.dispose();
78
- this.canvasManager.dispose();
79
- if (this.canvas.parentNode === this.container) {
80
- this.container.removeChild(this.canvas);
119
+ setMode(mode) {
120
+ const currentMode = this.canvasManager.getMode();
121
+ const mergedMode = { ...currentMode, ...mode };
122
+ const needsFullscreenChange = mode.fullscreen !== undefined && mode.fullscreen !== currentMode.fullscreen;
123
+ if (needsFullscreenChange) {
124
+ if (mergedMode.fullscreen) {
125
+ this.container.requestFullscreen().catch(console.error);
126
+ }
127
+ else {
128
+ document.exitFullscreen();
129
+ }
81
130
  }
131
+ this.canvasManager.setMode(mode);
82
132
  }
83
133
  dispatchEvent(type, args) {
84
134
  if (this.onEvent) {
85
135
  this.onEvent({ type, args, timestamp: performance.now() });
86
136
  }
87
137
  }
88
- start(onEvent) {
89
- if (!this.deps)
90
- throw new Error('Engine dependencies not set. Call setDeps() before start().');
138
+ async start(onEvent) {
91
139
  this.onEvent = onEvent;
92
140
  this.isRunning = true;
93
141
  this.lastTime = performance.now();
94
- // Listeners for raw input
95
- this.deps.keyboard.onKeyEvent = (scancode, keycode, type) => {
96
- this.dispatchEvent(type === 'keydown' ? 'keypressed' : 'keyreleased', [scancode, keycode]);
97
- };
98
- this.deps.mouse.onMouseEvent = (clientX, clientY, button, type) => {
99
- const [x, y] = this.transformMousePosition(clientX, clientY);
100
- const b = (button ?? 0) + 1;
101
- this.dispatchEvent(type === 'mousedown' ? 'mousepressed' : 'mousereleased', [x, y, b]);
102
- };
103
- this.deps.gamepad.onButtonEvent = (gpIndex, buttonIndex, buttonName, pressed) => {
104
- this.dispatchEvent(pressed ? 'gamepadpressed' : 'gamepadreleased', [gpIndex, buttonIndex, buttonName]);
105
- };
142
+ // Initialize gamepad
143
+ await this.like.gamepad.init();
106
144
  const loop = () => {
107
145
  if (!this.isRunning)
108
146
  return;
109
147
  const currentTime = performance.now();
110
148
  const dt = (currentTime - this.lastTime) / 1000;
111
149
  this.lastTime = currentTime;
112
- if (!this.deps.timer.isSleeping()) {
113
- this.deps.timer.update(dt);
114
- const inputEvents = this.deps.input.update();
150
+ if (!this.like.timer.isSleeping()) {
151
+ this.like.timer.update(dt);
152
+ const inputEvents = this.like.input.update();
115
153
  inputEvents.pressed.forEach(action => this.dispatchEvent('actionpressed', [action]));
116
154
  inputEvents.released.forEach(action => this.dispatchEvent('actionreleased', [action]));
117
155
  this.dispatchEvent('update', [dt]);
118
156
  }
119
- this.deps.graphics.clear();
120
- this.dispatchEvent('draw', [this.canvas]);
157
+ this.dispatchEvent('draw', []);
121
158
  this.canvasManager.present();
122
159
  requestAnimationFrame(loop);
123
160
  };
@@ -127,28 +164,17 @@ export class Engine {
127
164
  stop() {
128
165
  this.isRunning = false;
129
166
  }
130
- setSize(width, height) {
131
- this.canvas.width = width;
132
- this.canvas.height = height;
133
- }
134
- getTime() {
135
- return this.deps?.timer.getTime() ?? 0;
136
- }
137
- getCanvas() {
138
- return this.canvas;
139
- }
140
- getContext() {
141
- return this.ctx;
142
- }
143
- transformMousePosition(cssX, cssY) {
144
- return this.canvasManager.transformMousePosition(cssX, cssY);
145
- }
146
- toggleFullscreen() {
147
- if (!document.fullscreenElement) {
148
- this.container.requestFullscreen().catch(console.error);
149
- }
150
- else {
151
- document.exitFullscreen();
167
+ dispose() {
168
+ this.isRunning = false;
169
+ this.like.keyboard.dispose();
170
+ this.like.mouse.dispose();
171
+ this.like.gamepad.dispose();
172
+ this.canvasManager.dispose();
173
+ if (this.canvas.parentNode === this.container) {
174
+ this.container.removeChild(this.canvas);
152
175
  }
153
176
  }
177
+ getCanvasSize() {
178
+ return [this.canvas.width, this.canvas.height];
179
+ }
154
180
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Main API interface containing all core systems.
3
+ * Passed as first argument to all callbacks.
4
+ */
5
+ export type { Like } from './core/like';
1
6
  /**
2
7
  * 2D vector as a tuple: [x, y]
3
8
  */
@@ -14,7 +19,8 @@ export { Rect } from './core/rect';
14
19
  /**
15
20
  * Common event structure for all engine events.
16
21
  */
17
- export type { Like2DEvent, EventType } from './core/events';
22
+ export type { Like2DEvent, EventType, EventMap } from './core/events';
23
+ export type { CanvasMode, PartialCanvasMode } from './core/canvas-config';
18
24
  /**
19
25
  * Graphics types for drawing operations.
20
26
  */
@@ -22,7 +28,7 @@ export type { Color, Quad, ShapeProps, DrawProps, PrintProps } from './core/grap
22
28
  /**
23
29
  * Handle to an image asset that may be loading in the background.
24
30
  */
25
- export { ImageHandle } from './core/graphics';
31
+ export { ImageHandle, newImage } from './core/graphics';
26
32
  /**
27
33
  * Audio source types for sound playback.
28
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC;;GAEG;AACH,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE5D;;GAEG;AACH,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;GAEG;AACH,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1D;;GAEG;AACH,YAAY,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC;;GAEG;AACH,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC;;;GAGG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC;;GAEG;AACH,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE1E;;GAEG;AACH,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAExD;;GAEG;AACH,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1D;;GAEG;AACH,YAAY,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Like2D - Multi-adapter game framework
2
2
  // Use specific adapters for different patterns:
3
- // - import { like, graphics } from 'like2d/callback' (Love2D-style callbacks)
3
+ // - import { createLike, graphics } from 'like2d/callback' (Love2D-style callbacks)
4
4
  // - import { SceneRunner, Scene } from 'like2d/scene' (Class-based scenes)
5
5
  /**
6
6
  * 2D vector math and utility functions
@@ -14,11 +14,11 @@ export { Rect } from './core/rect';
14
14
  /**
15
15
  * Handle to an image asset that may be loading in the background.
16
16
  */
17
- export { ImageHandle } from './core/graphics';
17
+ export { ImageHandle, newImage } from './core/graphics';
18
18
  /**
19
19
  * Gamepad utility functions and types.
20
20
  */
21
21
  export { getGPName, GP } from './core/gamepad';
22
22
  // Note: For actual usage, import from specific adapters:
23
- // import { like, graphics } from 'like2d/callback';
23
+ // import { createLike, graphics } from 'like2d/callback';
24
24
  // import { SceneRunner, Scene } from 'like2d/scene';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "like2d",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "A web-native game framework inspired by Love2D",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -26,13 +26,6 @@
26
26
  "README.md",
27
27
  "LICENSE"
28
28
  ],
29
- "scripts": {
30
- "build": "tsc && cp src/gamecontrollerdb.txt dist/",
31
- "typecheck": "tsc --noEmit",
32
- "lint": "echo 'No linting configured'",
33
- "clean": "rm -rf dist",
34
- "test": "vitest run"
35
- },
36
29
  "keywords": [
37
30
  "game",
38
31
  "framework",
@@ -46,5 +39,12 @@
46
39
  "license": "MIT",
47
40
  "devDependencies": {
48
41
  "typescript": "^5.9.3"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc && cp src/gamecontrollerdb.txt dist/",
45
+ "typecheck": "tsc --noEmit",
46
+ "lint": "echo 'No linting configured'",
47
+ "clean": "rm -rf dist",
48
+ "test": "vitest run"
49
49
  }
50
- }
50
+ }