like2d 2.8.0 → 2.10.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/README.md +44 -41
- package/dist/__benchmarks__/vector2.bench.d.ts +2 -0
- package/dist/__benchmarks__/vector2.bench.d.ts.map +1 -0
- package/dist/__benchmarks__/vector2.bench.js +74 -0
- package/dist/{core → audio}/audio.d.ts +21 -9
- package/dist/audio/audio.d.ts.map +1 -0
- package/dist/{core → audio}/audio.js +15 -4
- package/dist/audio/index.d.ts +2 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/engine.d.ts +30 -15
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +79 -160
- package/dist/events.d.ts +86 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +5 -0
- package/dist/gamecontrollerdb.txt +9 -8
- package/dist/graphics/canvas.d.ts +65 -0
- package/dist/graphics/canvas.d.ts.map +1 -0
- package/dist/graphics/canvas.js +224 -0
- package/dist/graphics/drawing.d.ts +203 -0
- package/dist/graphics/drawing.d.ts.map +1 -0
- package/dist/graphics/drawing.js +388 -0
- package/dist/graphics/index.d.ts +19 -0
- package/dist/graphics/index.d.ts.map +1 -0
- package/dist/graphics/index.js +13 -0
- package/dist/index.d.ts +18 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -15
- package/dist/input/gamepad-mapping.d.ts +134 -0
- package/dist/input/gamepad-mapping.d.ts.map +1 -0
- package/dist/input/gamepad-mapping.js +146 -0
- package/dist/input/gamepad.d.ts +74 -0
- package/dist/input/gamepad.d.ts.map +1 -0
- package/dist/input/gamepad.js +288 -0
- package/dist/input/index.d.ts +6 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +1 -0
- package/dist/input/input.d.ts +76 -0
- package/dist/input/input.d.ts.map +1 -0
- package/dist/input/input.js +164 -0
- package/dist/input/keyboard.d.ts +15 -0
- package/dist/input/keyboard.d.ts.map +1 -0
- package/dist/input/keyboard.js +53 -0
- package/dist/input/mouse.d.ts +108 -0
- package/dist/input/mouse.d.ts.map +1 -0
- package/dist/input/mouse.js +241 -0
- package/dist/like.d.ts +80 -0
- package/dist/like.d.ts.map +1 -0
- package/dist/like.js +5 -0
- package/dist/math/index.d.ts +18 -0
- package/dist/math/index.d.ts.map +1 -0
- package/dist/math/index.js +17 -0
- package/dist/math/rect.d.ts +68 -0
- package/dist/math/rect.d.ts.map +1 -0
- package/dist/{core → math}/rect.js +48 -66
- package/dist/math/vector2.d.ts +133 -0
- package/dist/math/vector2.d.ts.map +1 -0
- package/dist/math/vector2.js +111 -0
- package/dist/prefab-scenes/index.d.ts +8 -0
- package/dist/prefab-scenes/index.d.ts.map +1 -0
- package/dist/prefab-scenes/index.js +7 -0
- package/dist/prefab-scenes/mapGamepad.d.ts +28 -0
- package/dist/prefab-scenes/mapGamepad.d.ts.map +1 -0
- package/dist/prefab-scenes/mapGamepad.js +181 -0
- package/dist/prefab-scenes/startScreen.d.ts +59 -0
- package/dist/prefab-scenes/startScreen.d.ts.map +1 -0
- package/dist/{scenes/startup.js → prefab-scenes/startScreen.js} +48 -8
- package/dist/scene.d.ts +104 -6
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +28 -1
- package/dist/timer/index.d.ts +2 -0
- package/dist/timer/index.d.ts.map +1 -0
- package/dist/timer/timer.d.ts +32 -0
- package/dist/timer/timer.d.ts.map +1 -0
- package/dist/{core → timer}/timer.js +19 -14
- package/package.json +27 -2
- package/dist/core/audio.d.ts.map +0 -1
- package/dist/core/canvas-config.d.ts +0 -22
- package/dist/core/canvas-config.d.ts.map +0 -1
- package/dist/core/canvas-config.js +0 -14
- package/dist/core/canvas-manager.d.ts +0 -32
- package/dist/core/canvas-manager.d.ts.map +0 -1
- package/dist/core/canvas-manager.js +0 -179
- package/dist/core/events.d.ts +0 -31
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/gamepad-buttons.d.ts +0 -23
- package/dist/core/gamepad-buttons.d.ts.map +0 -1
- package/dist/core/gamepad-buttons.js +0 -36
- package/dist/core/gamepad-mapping.d.ts +0 -19
- package/dist/core/gamepad-mapping.d.ts.map +0 -1
- package/dist/core/gamepad-mapping.js +0 -223
- package/dist/core/gamepad.d.ts +0 -61
- package/dist/core/gamepad.d.ts.map +0 -1
- package/dist/core/gamepad.js +0 -237
- package/dist/core/graphics.d.ts +0 -93
- package/dist/core/graphics.d.ts.map +0 -1
- package/dist/core/graphics.js +0 -289
- package/dist/core/input-state.d.ts +0 -14
- package/dist/core/input-state.d.ts.map +0 -1
- package/dist/core/input-state.js +0 -50
- package/dist/core/input.d.ts +0 -33
- package/dist/core/input.d.ts.map +0 -1
- package/dist/core/input.js +0 -117
- package/dist/core/keyboard.d.ts +0 -16
- package/dist/core/keyboard.d.ts.map +0 -1
- package/dist/core/keyboard.js +0 -83
- package/dist/core/like.d.ts +0 -59
- package/dist/core/like.d.ts.map +0 -1
- package/dist/core/mouse.d.ts +0 -45
- package/dist/core/mouse.d.ts.map +0 -1
- package/dist/core/mouse.js +0 -182
- package/dist/core/rect.d.ts +0 -26
- package/dist/core/rect.d.ts.map +0 -1
- package/dist/core/timer.d.ts +0 -18
- package/dist/core/timer.d.ts.map +0 -1
- package/dist/core/vector2.d.ts +0 -26
- package/dist/core/vector2.d.ts.map +0 -1
- package/dist/core/vector2.js +0 -105
- package/dist/scenes/startup.d.ts +0 -18
- package/dist/scenes/startup.d.ts.map +0 -1
- /package/dist/{core/events.js → audio/index.js} +0 -0
- /package/dist/{core/like.js → timer/index.js} +0 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module graphics
|
|
3
|
+
* @description a reduced-state, Love2D-like wrapper around browser canvas
|
|
4
|
+
*
|
|
5
|
+
* # Graphics Module
|
|
6
|
+
*
|
|
7
|
+
* A wrapper around browser Canvas.
|
|
8
|
+
* In standard usage `like.gfx` gives a {@link BoundGraphics} object with a canvas already on it.
|
|
9
|
+
* So, you can for example call `like.gfx.rectangle('fill', 'green', [10, 10, 30, 30])`
|
|
10
|
+
*
|
|
11
|
+
* ## State Isolation
|
|
12
|
+
* Each drawing operation resets relevant canvas state before executing:
|
|
13
|
+
* - Stroke properties (`lineWidth`, `lineCap`, `lineJoin`, `miterLimit`) are always set to defaults first
|
|
14
|
+
* - No state leakage between drawing calls
|
|
15
|
+
*
|
|
16
|
+
* ## Predicable Parameter Ordering
|
|
17
|
+
* - No clunky argument overrides that could affect positionality.
|
|
18
|
+
* - **Required arguments** come first as positional parameters
|
|
19
|
+
* - **Optional arguments** are grouped in a trailing `props` object
|
|
20
|
+
* - **Mode** `'fill' | 'line'` is the first arg if relevent.
|
|
21
|
+
* - **Color** then {@link Color}, if relevant -- there is no `setColor`.
|
|
22
|
+
*
|
|
23
|
+
* ## Note: Coordinate System is unchanged from native Canvas.
|
|
24
|
+
* - Origin (0, 0) at top-left
|
|
25
|
+
* - X increases right
|
|
26
|
+
* - Y increases down
|
|
27
|
+
* - Angles in radians, 0 is right, positive is clockwise
|
|
28
|
+
*/
|
|
29
|
+
import { Vec2 } from "../math/vector2";
|
|
30
|
+
export class ImageHandle {
|
|
31
|
+
constructor(path) {
|
|
32
|
+
Object.defineProperty(this, "path", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
value: void 0
|
|
37
|
+
});
|
|
38
|
+
Object.defineProperty(this, "element", {
|
|
39
|
+
enumerable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
writable: true,
|
|
42
|
+
value: null
|
|
43
|
+
});
|
|
44
|
+
Object.defineProperty(this, "loadPromise", {
|
|
45
|
+
enumerable: true,
|
|
46
|
+
configurable: true,
|
|
47
|
+
writable: true,
|
|
48
|
+
value: void 0
|
|
49
|
+
});
|
|
50
|
+
Object.defineProperty(this, "isLoaded", {
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true,
|
|
54
|
+
value: false
|
|
55
|
+
});
|
|
56
|
+
this.path = path;
|
|
57
|
+
this.loadPromise = new Promise((resolve, reject) => {
|
|
58
|
+
const img = new Image();
|
|
59
|
+
img.onload = () => {
|
|
60
|
+
this.element = img;
|
|
61
|
+
this.isLoaded = true;
|
|
62
|
+
resolve();
|
|
63
|
+
};
|
|
64
|
+
img.onerror = () => {
|
|
65
|
+
reject(new Error(`Failed to load image: ${path}`));
|
|
66
|
+
};
|
|
67
|
+
img.src = path;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
isReady() {
|
|
71
|
+
return this.isLoaded;
|
|
72
|
+
}
|
|
73
|
+
ready() {
|
|
74
|
+
return this.loadPromise;
|
|
75
|
+
}
|
|
76
|
+
get size() {
|
|
77
|
+
return [this.element?.width ?? 0, this.element?.height ?? 0];
|
|
78
|
+
}
|
|
79
|
+
getElement() {
|
|
80
|
+
return this.element;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function parseColor(color) {
|
|
84
|
+
if (typeof color === "string")
|
|
85
|
+
return color;
|
|
86
|
+
const [r, g, b, a = 1] = color;
|
|
87
|
+
return `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`;
|
|
88
|
+
}
|
|
89
|
+
function applyColor(color) {
|
|
90
|
+
return parseColor(color ?? [1, 1, 1, 1]);
|
|
91
|
+
}
|
|
92
|
+
function setStrokeProps(ctx, props) {
|
|
93
|
+
ctx.lineWidth = props?.lineWidth ?? 1;
|
|
94
|
+
ctx.lineCap = props?.lineCap ?? "butt";
|
|
95
|
+
ctx.lineJoin = props?.lineJoin ?? "miter";
|
|
96
|
+
ctx.miterLimit = props?.miterLimit ?? 10;
|
|
97
|
+
}
|
|
98
|
+
function wrapText(ctx, text, maxWidth) {
|
|
99
|
+
const words = text.split(" ");
|
|
100
|
+
const [first, ...rest] = words;
|
|
101
|
+
const lines = [];
|
|
102
|
+
let current = first ?? "";
|
|
103
|
+
rest.forEach((word) => {
|
|
104
|
+
if (ctx.measureText(current + " " + word).width < maxWidth) {
|
|
105
|
+
current += " " + word;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
lines.push(current);
|
|
109
|
+
current = word;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
lines.push(current);
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
function getFontHeight(ctx) {
|
|
116
|
+
const match = ctx.font.match(/(\d+)px/);
|
|
117
|
+
return match ? parseInt(match[1]) : 16;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* All of these methods exist on `like.gfx`, but with `ctx`
|
|
121
|
+
* bound to the first arg.
|
|
122
|
+
*
|
|
123
|
+
* Acts as the core of the graphics system, but can be used separately.
|
|
124
|
+
*
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { draw } from "like/graphics"
|
|
127
|
+
* draw.clear(my2dContext, "red");
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
131
|
+
export const draw = {
|
|
132
|
+
/**
|
|
133
|
+
* Clears the canvas with a solid color.
|
|
134
|
+
* @param ctx Canvas context.
|
|
135
|
+
* @param color Fill color.
|
|
136
|
+
*/
|
|
137
|
+
clear(ctx, color = [0, 0, 0, 1]) {
|
|
138
|
+
ctx.fillStyle = parseColor(color);
|
|
139
|
+
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* Draws a rectangle.
|
|
143
|
+
* @param ctx Canvas context.
|
|
144
|
+
* @param mode Fill or line.
|
|
145
|
+
* @param color Fill or stroke color.
|
|
146
|
+
* @param rect Rectangle [x, y, w, h].
|
|
147
|
+
* @param props Optional stroke properties.
|
|
148
|
+
*/
|
|
149
|
+
rectangle(ctx, mode, color, rect, props) {
|
|
150
|
+
const c = applyColor(color);
|
|
151
|
+
if (mode === "fill") {
|
|
152
|
+
ctx.fillStyle = c;
|
|
153
|
+
ctx.fillRect(...rect);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
setStrokeProps(ctx, props);
|
|
157
|
+
ctx.strokeStyle = c;
|
|
158
|
+
ctx.strokeRect(...rect);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
/**
|
|
162
|
+
* Draws a circle or ellipse.
|
|
163
|
+
* @param ctx Canvas context.
|
|
164
|
+
* @param mode Fill or line.
|
|
165
|
+
* @param color Fill or stroke color.
|
|
166
|
+
* @param position Center position.
|
|
167
|
+
* @param radii Radius (number) or [rx, ry] for ellipse.
|
|
168
|
+
* @param props Optional arc, center, and stroke properties. Center is true by default.
|
|
169
|
+
*/
|
|
170
|
+
circle(ctx, mode, color, position, radii, props) {
|
|
171
|
+
const center = (props && 'center' in props) ? props.center : true;
|
|
172
|
+
const c = applyColor(color);
|
|
173
|
+
const size = typeof radii === "number" ? [radii, radii] : radii;
|
|
174
|
+
const [startAngle, endAngle] = props?.arc ?? [0, Math.PI * 2];
|
|
175
|
+
if (!center) {
|
|
176
|
+
position = Vec2.add(position, size);
|
|
177
|
+
}
|
|
178
|
+
ctx.save();
|
|
179
|
+
ctx.translate(...position);
|
|
180
|
+
ctx.scale(...size);
|
|
181
|
+
ctx.beginPath();
|
|
182
|
+
ctx.arc(0, 0, 1, startAngle, endAngle);
|
|
183
|
+
if (mode == 'fill')
|
|
184
|
+
ctx.lineTo(0, 0);
|
|
185
|
+
ctx.closePath();
|
|
186
|
+
ctx.restore();
|
|
187
|
+
if (mode === "fill") {
|
|
188
|
+
ctx.fillStyle = c;
|
|
189
|
+
ctx.fill();
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
setStrokeProps(ctx, props);
|
|
193
|
+
ctx.strokeStyle = c;
|
|
194
|
+
ctx.stroke();
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Draws connected line segments.
|
|
199
|
+
* @param ctx Canvas context.
|
|
200
|
+
* @param color Stroke color.
|
|
201
|
+
* @param points Array of [x, y] positions.
|
|
202
|
+
* @param props Optional stroke properties.
|
|
203
|
+
*/
|
|
204
|
+
line(ctx, color, points, props) {
|
|
205
|
+
if (points.length < 2)
|
|
206
|
+
return;
|
|
207
|
+
setStrokeProps(ctx, props);
|
|
208
|
+
ctx.beginPath();
|
|
209
|
+
const [[x0, y0], ...rest] = points;
|
|
210
|
+
ctx.moveTo(x0, y0);
|
|
211
|
+
rest.forEach(([x, y]) => ctx.lineTo(x, y));
|
|
212
|
+
ctx.strokeStyle = applyColor(color);
|
|
213
|
+
ctx.stroke();
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* Draws text at a position.
|
|
217
|
+
*
|
|
218
|
+
* Keep in mind: if you set `align` without `width` in your props,
|
|
219
|
+
* nothing will happen -- you'll get left-aligned text.
|
|
220
|
+
*
|
|
221
|
+
* Align works browser-style: if you align center, your text draws
|
|
222
|
+
* to the left and right of its position. If you align right, your position
|
|
223
|
+
* becomes the upper-right corner of the text.
|
|
224
|
+
*
|
|
225
|
+
* @param ctx Canvas context.
|
|
226
|
+
* @param color Fill color.
|
|
227
|
+
* @param text Text string.
|
|
228
|
+
* @param position Top-left position.
|
|
229
|
+
* @param props {@link PrintProps} Optional font, text limit, or alignment.
|
|
230
|
+
*/
|
|
231
|
+
print(ctx, color, text, position, props) {
|
|
232
|
+
const [x, y] = position;
|
|
233
|
+
const { font = "16px sans-serif" } = props ?? {};
|
|
234
|
+
ctx.fillStyle = parseColor(color);
|
|
235
|
+
ctx.font = font;
|
|
236
|
+
ctx.textAlign = props?.align ?? "left";
|
|
237
|
+
if (props && 'width' in props) {
|
|
238
|
+
const { width } = props;
|
|
239
|
+
const lines = wrapText(ctx, text, width);
|
|
240
|
+
const lineHeight = getFontHeight(ctx);
|
|
241
|
+
ctx.textBaseline = "top";
|
|
242
|
+
lines.forEach((line, i) => {
|
|
243
|
+
ctx.fillText(line, x, y + i * lineHeight, width);
|
|
244
|
+
});
|
|
245
|
+
ctx.textBaseline = "alphabetic";
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
ctx.fillText(text, x, y);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
/**
|
|
252
|
+
* Draws an image.
|
|
253
|
+
*
|
|
254
|
+
* @remarks named "draw" because it draws anything _drawable_
|
|
255
|
+
* in the long run.
|
|
256
|
+
*
|
|
257
|
+
* @param ctx Canvas context.
|
|
258
|
+
* @param handle Image handle from newImage.
|
|
259
|
+
* @param position Draw position.
|
|
260
|
+
* @param props Optional rotation, scale, origin, or quad.
|
|
261
|
+
*/
|
|
262
|
+
draw(ctx, handle, position, props) {
|
|
263
|
+
if (!handle.isReady())
|
|
264
|
+
return;
|
|
265
|
+
const element = handle.getElement();
|
|
266
|
+
if (!element)
|
|
267
|
+
return;
|
|
268
|
+
const [x, y] = position;
|
|
269
|
+
const { r = 0, scale = 1, origin = 0, quad } = props ?? {};
|
|
270
|
+
const [sx, sy] = typeof scale === "number" ? [scale, scale] : scale;
|
|
271
|
+
const [ox, oy] = typeof origin === "number" ? [origin, origin] : origin;
|
|
272
|
+
ctx.save();
|
|
273
|
+
ctx.translate(x, y);
|
|
274
|
+
ctx.rotate(r);
|
|
275
|
+
ctx.scale(sx, sy);
|
|
276
|
+
if (quad) {
|
|
277
|
+
const [qx, qy, qw, qh] = quad;
|
|
278
|
+
ctx.drawImage(element, qx, qy, qw, qh, -ox, -oy, qw, qh);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
ctx.drawImage(element, -ox, -oy);
|
|
282
|
+
}
|
|
283
|
+
ctx.restore();
|
|
284
|
+
},
|
|
285
|
+
/**
|
|
286
|
+
* Loads an image from a path.
|
|
287
|
+
* Unlike built-in loading, this pretends to be synchronous.
|
|
288
|
+
* @param ctx Canvas context.
|
|
289
|
+
* @param path Image file path.
|
|
290
|
+
* @returns ImageHandle for use with draw.
|
|
291
|
+
*/
|
|
292
|
+
newImage(_ctx, path) {
|
|
293
|
+
return new ImageHandle(path);
|
|
294
|
+
},
|
|
295
|
+
/**
|
|
296
|
+
* Sets the clipping region.
|
|
297
|
+
* @param ctx Canvas context.
|
|
298
|
+
* @param rect Clipping rectangle, or full canvas if omitted.
|
|
299
|
+
*/
|
|
300
|
+
clip(ctx, rect) {
|
|
301
|
+
ctx.beginPath();
|
|
302
|
+
if (rect) {
|
|
303
|
+
const [x, y, w, h] = rect;
|
|
304
|
+
ctx.rect(x, y, w, h);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
308
|
+
}
|
|
309
|
+
ctx.clip();
|
|
310
|
+
},
|
|
311
|
+
/**
|
|
312
|
+
* Draws a polygon.
|
|
313
|
+
* @param ctx Canvas context.
|
|
314
|
+
* @param mode Fill or line.
|
|
315
|
+
* @param color Fill or stroke color.
|
|
316
|
+
* @param points Array of [x, y] vertices.
|
|
317
|
+
* @param props Optional stroke properties.
|
|
318
|
+
*/
|
|
319
|
+
polygon(ctx, mode, color, points, props) {
|
|
320
|
+
if (points.length < 3)
|
|
321
|
+
return;
|
|
322
|
+
const c = applyColor(color);
|
|
323
|
+
ctx.beginPath();
|
|
324
|
+
const [[x0, y0], ...rest] = points;
|
|
325
|
+
ctx.moveTo(x0, y0);
|
|
326
|
+
rest.forEach(([x, y]) => ctx.lineTo(x, y));
|
|
327
|
+
ctx.closePath();
|
|
328
|
+
if (mode === "fill") {
|
|
329
|
+
ctx.fillStyle = c;
|
|
330
|
+
ctx.fill();
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
setStrokeProps(ctx, props);
|
|
334
|
+
ctx.strokeStyle = c;
|
|
335
|
+
ctx.stroke();
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
/**
|
|
339
|
+
* Draws individual pixels.
|
|
340
|
+
* @param ctx Canvas context.
|
|
341
|
+
* @param color Fill color.
|
|
342
|
+
* @param pts Array of [x, y] positions.
|
|
343
|
+
*/
|
|
344
|
+
points(ctx, color, pts) {
|
|
345
|
+
ctx.fillStyle = applyColor(color);
|
|
346
|
+
pts.forEach(([x, y]) => ctx.fillRect(x, y, 1, 1));
|
|
347
|
+
},
|
|
348
|
+
/**
|
|
349
|
+
* Saves canvas state.
|
|
350
|
+
* @param ctx Canvas context.
|
|
351
|
+
*/
|
|
352
|
+
push(ctx) {
|
|
353
|
+
ctx.save();
|
|
354
|
+
},
|
|
355
|
+
/**
|
|
356
|
+
* Restores canvas state.
|
|
357
|
+
* @param ctx Canvas context.
|
|
358
|
+
*/
|
|
359
|
+
pop(ctx) {
|
|
360
|
+
ctx.restore();
|
|
361
|
+
},
|
|
362
|
+
/**
|
|
363
|
+
* Applies a translation.
|
|
364
|
+
* @param ctx Canvas context.
|
|
365
|
+
* @param offset [x, y] offset.
|
|
366
|
+
*/
|
|
367
|
+
translate(ctx, offset) {
|
|
368
|
+
const [x, y] = offset;
|
|
369
|
+
ctx.translate(x, y);
|
|
370
|
+
},
|
|
371
|
+
/**
|
|
372
|
+
* Applies a rotation.
|
|
373
|
+
* @param ctx Canvas context.
|
|
374
|
+
* @param angle Rotation in radians.
|
|
375
|
+
*/
|
|
376
|
+
rotate(ctx, angle) {
|
|
377
|
+
ctx.rotate(angle);
|
|
378
|
+
},
|
|
379
|
+
/**
|
|
380
|
+
* Applies a scale.
|
|
381
|
+
* @param ctx Canvas context.
|
|
382
|
+
* @param factor Scale factor (number or [x, y]).
|
|
383
|
+
*/
|
|
384
|
+
scale(ctx, factor) {
|
|
385
|
+
const [sx, sy] = typeof factor === "number" ? [factor, factor] : factor;
|
|
386
|
+
ctx.scale(sx, sy);
|
|
387
|
+
},
|
|
388
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module graphics
|
|
3
|
+
* @description a reduced-state, Love2D-like wrapper around browser canvas
|
|
4
|
+
*/
|
|
5
|
+
import { draw } from "./drawing";
|
|
6
|
+
export type { Color, DrawMode, ShapeProps, DrawProps, PrintProps, ImageHandle, } from "./drawing";
|
|
7
|
+
export { draw } from "./drawing";
|
|
8
|
+
export type { CanvasModeOptions, CanvasSize, Canvas, } from "./canvas";
|
|
9
|
+
type Bind<F> = F extends (ctx: CanvasRenderingContext2D, ...args: infer A) => infer R ? (...args: A) => R : never;
|
|
10
|
+
/**
|
|
11
|
+
* A graphics object with a canvas already attatched to it.
|
|
12
|
+
* Calling its methods will draw to the render canvas.
|
|
13
|
+
* See {@link graphics} for more info.
|
|
14
|
+
*/
|
|
15
|
+
export type BoundGraphics = {
|
|
16
|
+
[K in keyof typeof draw]: Bind<(typeof draw)[K]>;
|
|
17
|
+
};
|
|
18
|
+
export declare function bindGraphics(ctx: CanvasRenderingContext2D): BoundGraphics;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graphics/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,YAAY,EACV,KAAK,EACL,QAAQ,EACR,UAAU,EACV,SAAS,EACT,UAAU,EACV,WAAW,GACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,YAAY,EACV,iBAAiB,EACjB,UAAU,EACV,MAAM,GACP,MAAM,UAAU,CAAC;AAElB,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CACvB,GAAG,EAAE,wBAAwB,EAC7B,GAAG,IAAI,EAAE,MAAM,CAAC,KACb,MAAM,CAAC,GACR,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,GACjB,KAAK,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;KACzB,CAAC,IAAI,MAAM,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF,wBAAgB,YAAY,CAAC,GAAG,EAAE,wBAAwB,GAAG,aAAa,CAMzE"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module graphics
|
|
3
|
+
* @description a reduced-state, Love2D-like wrapper around browser canvas
|
|
4
|
+
*/
|
|
5
|
+
import { draw } from "./drawing";
|
|
6
|
+
export { draw } from "./drawing";
|
|
7
|
+
export function bindGraphics(ctx) {
|
|
8
|
+
const bound = {};
|
|
9
|
+
for (const [name, fn] of Object.entries(draw)) {
|
|
10
|
+
bound[name] = (...args) => fn(ctx, ...args);
|
|
11
|
+
}
|
|
12
|
+
return bound;
|
|
13
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
export type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
export type LikeWithCallbacks = Like & Callbacks & {
|
|
21
|
-
start(): Promise<void>;
|
|
22
|
-
dispose(): void;
|
|
23
|
-
};
|
|
24
|
-
export declare function createLike(container: HTMLElement): LikeWithCallbacks;
|
|
1
|
+
/**
|
|
2
|
+
* @module like2d
|
|
3
|
+
* @description A cozy web-native 2D game framework.
|
|
4
|
+
*/
|
|
5
|
+
import type { Like } from './like';
|
|
6
|
+
export type { Like, TopLevelEventHandler } from './like';
|
|
7
|
+
export type { LikeEvent, EventType, EventMap } from './events';
|
|
8
|
+
/**
|
|
9
|
+
* Create a new Like2D game instance attached to a DOM container.
|
|
10
|
+
*
|
|
11
|
+
* This is the entry point for all Like2D games. It creates a canvas element,
|
|
12
|
+
* initializes all subsystems (graphics, audio, input), and returns an object
|
|
13
|
+
* where you can assign game callbacks.
|
|
14
|
+
*
|
|
15
|
+
* @param container - The HTML element to attach the game canvas to.
|
|
16
|
+
* @returns A {@link Like} instance ready for callback assignment
|
|
17
|
+
*/
|
|
18
|
+
export declare function createLike(container: HTMLElement): Like;
|
|
25
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,YAAY,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AACzD,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE/D;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAGvD"}
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module like2d
|
|
3
|
+
* @description A cozy web-native 2D game framework.
|
|
4
|
+
*/
|
|
1
5
|
import { Engine } from './engine';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Create a new Like2D game instance attached to a DOM container.
|
|
8
|
+
*
|
|
9
|
+
* This is the entry point for all Like2D games. It creates a canvas element,
|
|
10
|
+
* initializes all subsystems (graphics, audio, input), and returns an object
|
|
11
|
+
* where you can assign game callbacks.
|
|
12
|
+
*
|
|
13
|
+
* @param container - The HTML element to attach the game canvas to.
|
|
14
|
+
* @returns A {@link Like} instance ready for callback assignment
|
|
15
|
+
*/
|
|
7
16
|
export function createLike(container) {
|
|
8
17
|
const engine = new Engine(container);
|
|
9
|
-
|
|
10
|
-
const handleEvent = (event) => {
|
|
11
|
-
const cb = callbacks[event.type];
|
|
12
|
-
if (cb)
|
|
13
|
-
cb(...event.args);
|
|
14
|
-
};
|
|
15
|
-
return Object.assign(engine.like, callbacks, {
|
|
16
|
-
start: () => engine.start(handleEvent),
|
|
17
|
-
dispose: () => engine.dispose(),
|
|
18
|
-
});
|
|
18
|
+
return engine.like;
|
|
19
19
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GamepadMapping
|
|
3
|
+
*
|
|
4
|
+
* A database, generated on module load,
|
|
5
|
+
* which uses SDL's database to coerce
|
|
6
|
+
* browser APIs into physical gamepad button
|
|
7
|
+
* mappings.
|
|
8
|
+
*
|
|
9
|
+
* Browser API shortcomings:
|
|
10
|
+
* - No standard way of exposing vendor and product
|
|
11
|
+
* - Almost nothing is standard
|
|
12
|
+
* - Vendor and product alone doesn't suffice for GUID -- Different controllers have the same.
|
|
13
|
+
* - D-pads either get mapped to an axis (last pair of axes in Chromium) or buttons (Firefox).
|
|
14
|
+
* - Analog axes get mapped differently in Firefox and Chromium.
|
|
15
|
+
*
|
|
16
|
+
* How we overcome them:
|
|
17
|
+
* - We parse out vendor and product based on currently known formats.
|
|
18
|
+
* - We go with best-match and always fall back on manual mapping.
|
|
19
|
+
*/
|
|
20
|
+
import type { Vector2 } from "../math";
|
|
21
|
+
/**
|
|
22
|
+
* ref: https://www.w3.org/TR/gamepad/#dfn-standard-gamepad
|
|
23
|
+
* note: `num` is only the corresponding number on standard mapping above.
|
|
24
|
+
*
|
|
25
|
+
* The point of the mapping system is to apply that _or_ non-standard mappings,
|
|
26
|
+
* Which are exceedingly common.
|
|
27
|
+
*/
|
|
28
|
+
declare const buttonMap: readonly [{
|
|
29
|
+
readonly sdl: "a";
|
|
30
|
+
readonly like: "BBottom";
|
|
31
|
+
readonly num: number;
|
|
32
|
+
readonly name: "Bottom Face Button";
|
|
33
|
+
}, {
|
|
34
|
+
readonly sdl: "b";
|
|
35
|
+
readonly like: "BRight";
|
|
36
|
+
readonly num: 1;
|
|
37
|
+
readonly name: "Right Face Button";
|
|
38
|
+
}, {
|
|
39
|
+
readonly sdl: "x";
|
|
40
|
+
readonly like: "BLeft";
|
|
41
|
+
readonly num: 2;
|
|
42
|
+
readonly name: "Left Face Button";
|
|
43
|
+
}, {
|
|
44
|
+
readonly sdl: "y";
|
|
45
|
+
readonly like: "BTop";
|
|
46
|
+
readonly num: 3;
|
|
47
|
+
readonly name: "Top Face Button";
|
|
48
|
+
}, {
|
|
49
|
+
readonly sdl: "leftshoulder";
|
|
50
|
+
readonly like: "L1";
|
|
51
|
+
readonly num: 4;
|
|
52
|
+
readonly name: "Left shoulder (front)";
|
|
53
|
+
}, {
|
|
54
|
+
readonly sdl: "rightshoulder";
|
|
55
|
+
readonly like: "R1";
|
|
56
|
+
readonly num: 5;
|
|
57
|
+
readonly name: "Right shoulder (front)";
|
|
58
|
+
}, {
|
|
59
|
+
readonly sdl: "lefttrigger";
|
|
60
|
+
readonly like: "L2";
|
|
61
|
+
readonly num: 6;
|
|
62
|
+
readonly name: "Left shoulder (rear)";
|
|
63
|
+
}, {
|
|
64
|
+
readonly sdl: "righttrigger";
|
|
65
|
+
readonly like: "R2";
|
|
66
|
+
readonly num: 7;
|
|
67
|
+
readonly name: "Right shoulder (rear)";
|
|
68
|
+
}, {
|
|
69
|
+
readonly sdl: "back";
|
|
70
|
+
readonly like: "MenuLeft";
|
|
71
|
+
readonly num: 8;
|
|
72
|
+
readonly name: "Left Menu Button";
|
|
73
|
+
}, {
|
|
74
|
+
readonly sdl: "start";
|
|
75
|
+
readonly like: "MenuRight";
|
|
76
|
+
readonly num: 9;
|
|
77
|
+
readonly name: "Right Menu Button";
|
|
78
|
+
}, {
|
|
79
|
+
readonly sdl: "leftstick";
|
|
80
|
+
readonly like: "LeftStick";
|
|
81
|
+
readonly num: 10;
|
|
82
|
+
readonly name: "Left Stick Button";
|
|
83
|
+
}, {
|
|
84
|
+
readonly sdl: "rightstick";
|
|
85
|
+
readonly like: "RightStick";
|
|
86
|
+
readonly num: 11;
|
|
87
|
+
readonly name: "Right Stick Button";
|
|
88
|
+
}, {
|
|
89
|
+
readonly sdl: "dpup";
|
|
90
|
+
readonly like: "Up";
|
|
91
|
+
readonly num: 12;
|
|
92
|
+
readonly name: "D-Pad Up";
|
|
93
|
+
}, {
|
|
94
|
+
readonly sdl: "dpdown";
|
|
95
|
+
readonly like: "Down";
|
|
96
|
+
readonly num: 13;
|
|
97
|
+
readonly name: "D-Pad Down";
|
|
98
|
+
}, {
|
|
99
|
+
readonly sdl: "dpleft";
|
|
100
|
+
readonly like: "Left";
|
|
101
|
+
readonly num: 14;
|
|
102
|
+
readonly name: "D-Pad Left";
|
|
103
|
+
}, {
|
|
104
|
+
readonly sdl: "dpright";
|
|
105
|
+
readonly like: "Right";
|
|
106
|
+
readonly num: 15;
|
|
107
|
+
readonly name: "D-Pad right";
|
|
108
|
+
}];
|
|
109
|
+
export type LikeButton = (typeof buttonMap)[number]["like"] | `Button${number}` | `Axis${number}+` | `Axis${number}-`;
|
|
110
|
+
export type GamepadMapping = {
|
|
111
|
+
buttons: ButtonMapping;
|
|
112
|
+
sticks: StickMapping[];
|
|
113
|
+
};
|
|
114
|
+
export type ButtonMapping = Record<number, LikeButton>;
|
|
115
|
+
export type StickMapping = [StickAxisMapping, StickAxisMapping];
|
|
116
|
+
export type StickAxisMapping = {
|
|
117
|
+
index: number;
|
|
118
|
+
invert: boolean;
|
|
119
|
+
};
|
|
120
|
+
export declare const defaultMapping: (stickCount: number) => GamepadMapping;
|
|
121
|
+
export declare const standardButtonMapping: () => ButtonMapping;
|
|
122
|
+
export declare const allButtons: Set<string>;
|
|
123
|
+
export declare const fullButtonName: Map<"BBottom" | "BRight" | "BLeft" | "BTop" | "L1" | "R1" | "L2" | "R2" | "MenuLeft" | "MenuRight" | "LeftStick" | "RightStick" | "Up" | "Down" | "Left" | "Right", "Bottom Face Button" | "Right Face Button" | "Left Face Button" | "Top Face Button" | "Left shoulder (front)" | "Right shoulder (front)" | "Left shoulder (rear)" | "Right shoulder (rear)" | "Left Menu Button" | "Right Menu Button" | "Left Stick Button" | "Right Stick Button" | "D-Pad Up" | "D-Pad Down" | "D-Pad Left" | "D-Pad right">;
|
|
124
|
+
export declare const mapStick: (gp: Gamepad, mapping: StickMapping) => Vector2;
|
|
125
|
+
type SdlMapping = {
|
|
126
|
+
vendor: number;
|
|
127
|
+
product: number;
|
|
128
|
+
name: string;
|
|
129
|
+
sdlName: string;
|
|
130
|
+
mapping: Record<number, LikeButton>;
|
|
131
|
+
};
|
|
132
|
+
export declare function getSdlMapping(gamepad: Gamepad): SdlMapping | undefined;
|
|
133
|
+
export {};
|
|
134
|
+
//# sourceMappingURL=gamepad-mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gamepad-mapping.d.ts","sourceRoot":"","sources":["../../src/input/gamepad-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;GAMG;AACH,QAAA,MAAM,SAAS;;;kBAC0B,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBrC,CAAC;AAEX,MAAM,MAAM,UAAU,GAClB,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAClC,SAAS,MAAM,EAAE,GACjB,OAAO,MAAM,GAAG,GAChB,OAAO,MAAM,GAAG,CAAC;AAIrB,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,YAAY,EAAE,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACvD,MAAM,MAAM,YAAY,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;AAChE,MAAM,MAAM,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAElE,eAAO,MAAM,cAAc,GAAI,YAAY,MAAM,KAAG,cAQlD,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAAO,aAC0B,CAAC;AACpE,eAAO,MAAM,UAAU,aAAqD,CAAC;AAC7E,eAAO,MAAM,cAAc,qfAE1B,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,IAAI,OAAO,EAAE,SAAS,YAAY,KAAG,OAK7D,CAAC;AAsEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACrC,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CA0BtE"}
|