litecanvas 0.83.0 → 0.83.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 +25 -19
- package/dist/dist.dev.js +113 -161
- package/dist/dist.js +72 -54
- package/dist/dist.min.js +1 -1
- package/package.json +6 -3
- package/src/index.js +105 -170
- package/types/index.d.ts +12 -43
- package/types/types.d.ts +7 -22
package/README.md
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
# Litecanvas
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/litecanvas/)
|
|
6
|
+
|
|
5
7
|
Litecanvas is a lightweight HTML5 canvas 2D engine suitable for small web games, prototypes, game jams, animations, creative coding, learning game programming and game design, etc.
|
|
6
8
|
|
|
7
9
|
:warning: **This project is still under development. All feedback is appreciated!** :warning:
|
|
8
10
|
|
|
9
|
-
[](https://bills.itch.io/litecanvas)
|
|
12
|
+
[](https://discord.com/invite/r2c3rGsvH3)
|
|
13
|
+
[](https://litecanvas.js.org/)
|
|
11
14
|
|
|
12
15
|
### Features
|
|
13
16
|
|
|
@@ -38,8 +41,10 @@ If you prefer, you can manually install via [NPM](https://www.npmjs.com/package/
|
|
|
38
41
|
npm install litecanvas
|
|
39
42
|
```
|
|
40
43
|
|
|
44
|
+
### Show me the code!
|
|
45
|
+
|
|
41
46
|
```js
|
|
42
|
-
// import the package or put
|
|
47
|
+
// import the package or put a script tag in your HTML
|
|
43
48
|
// CDN: https://unpkg.com/litecanvas/dist/dist.dev.js
|
|
44
49
|
import litecanvas from 'litecanvas'
|
|
45
50
|
|
|
@@ -49,43 +54,44 @@ litecanvas({
|
|
|
49
54
|
loop: { init, update, draw, tapped },
|
|
50
55
|
})
|
|
51
56
|
|
|
57
|
+
// this function runs once at the beginning
|
|
52
58
|
function init() {
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
posx = CX // center X or (canvas width / 2)
|
|
59
|
-
posy = CY // center Y or (canvas width / 2)
|
|
59
|
+
bg = 0 // the color #0 (black)
|
|
60
|
+
color = 3 // the color #3 (white)
|
|
61
|
+
radius = W / 10 // the canvas width/10
|
|
62
|
+
posx = CX // center X (or canvas width/2)
|
|
63
|
+
posy = CY // center Y (or canvas width/2)
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
// this function detect
|
|
63
|
-
// and changes the circle position
|
|
66
|
+
// this function detect clicks/touches
|
|
64
67
|
function tapped(x, y) {
|
|
68
|
+
// changes the circle position
|
|
69
|
+
// based on the position of the tap
|
|
65
70
|
posx = x
|
|
66
71
|
posy = y
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
//
|
|
74
|
+
// put the game logic in this function
|
|
70
75
|
function update(dt) {
|
|
71
76
|
// make the circle falls 100 pixels per second
|
|
72
|
-
posy +=
|
|
77
|
+
posy += 200 * dt
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
//
|
|
80
|
+
// put the game rendering in this function
|
|
76
81
|
function draw() {
|
|
77
82
|
cls(bg) // clear the screen
|
|
78
83
|
circfill(posx, posy, radius, color) // draw a circle
|
|
84
|
+
text(10, 10, 'Tap anywhere') // draw a text
|
|
79
85
|
}
|
|
80
86
|
```
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
[Play with this code in the playground](https://litecanvas.js.org?c=eJx9k91u4yAQhe%2F9FCP1ovauFZL2LlKu9hFaadtLDBNDQwDBeOOoyrsv4KR2V9FasuSfjzNnDgNj8EI8EHArISINHkghoO21xYoxMMiDhaMLuAVF5OOWMaMJBbd%2FeFx9xJULPeOdG2il6Ggekghp28dqpurPCtJlnPNb%2BARtNbUweMkJW5CBn1og7j1KuLTVpalyXVI6wn6wgrSzEAYbwVmBwKkY7DAZtKlO9cVk2bqBqVbXww7WUIQQhDMuwMMa6s5wcWgKMn3cwfM%2F1DPUJ5W8T1TgUg8xYb%2BBwWZWLI3BSUtSbLMuqHdxTOCvtwwJtIQB3qBOmt%2Fop%2BZGnzP9vqDf79KXO4FITOESCKPFITJyg1AY5yymOOuxhfMtkVxFcdtjnBrQQRjMLnRecUM6HtM2ZAU1%2FwS3L%2B9JddnouOzjfLXph2mDen7EtOO9FmljvpufbU4zUEtamDzyAy4d7rkxMSW%2FBq9HTI8%2BBRVROCvn%2Bj938JSIHyDpno%2BAVmJI0%2FIfL3kOv8ZHmFh3fVNCyyegSEUREKeksre9NqbOUbTFQ3sdlXaao7I2awK%2FdlIWEo5Ub9Yt5Pvxlft08M4nhQEflysyVl3%2BAgslJEg%3D)
|
|
83
89
|
|
|
84
|
-
|
|
90
|
+
https://github.com/user-attachments/assets/854ac6bd-724f-4da8-bb3c-bc04dba5d8c8
|
|
85
91
|
|
|
86
|
-
##
|
|
92
|
+
## Demos
|
|
87
93
|
|
|
88
|
-
Try some demos in
|
|
94
|
+
Try some demos in the playground:
|
|
89
95
|
|
|
90
96
|
- [Pong](https://litecanvas.js.org?c=eJy1Vlly20YQ%2FccpOl8ATBACuEiWYslFM5DlKkdMkUwkJpVKwcCQnAoEoIChpdiWr%2BAT%2BC%2BHyHlygVwh3TODTZYU%2F0QsDdELenm9DBMmIA%2FjCzgGf%2BA5BuAf0mdEj2vykkivEa%2BQHg01HbNSkALpKc6bMElaj6vmccHfsZZpYk3STUK8yhovpLeaWjVUmTMWIzmoQimjrGi9m%2FA1K5EcKlKwG0EOta4ICyFfX4dJyQwj4YJFYfo2LK33UuOax2J7BMMKhy3jm604gtFTZNzahrG3B9NdKbIr%2BPnd6SWU2S6NS1hnBYgtL2ETXjHSyQsmBGdFn29SjM%2BIsrQU8GL24%2Fk0QPe%2FOOCAz4b05XpDOgbIcGBAHAcOR54WVB8XJe6%2B0t%2F%2F9duHfSyWk%2FmSXHju2EFUYIxIyddGeAzbXsYHnvYsD%2B3IGz1m%2FsXk9evfZqeni%2Bk8CM7Jj%2B8OfZnOGB14rkdeyQ8eB9KbpPqH7iGe%2B3TSx3N9v3oayPfkOZKnTxka610aCZ6lwFMuLBveN42FfqfB%2BTKYXzYdVvNW0Iez4NXLsyXswajTBqhz8eq75RkK%2FIFx2%2FIhwjxnsXXjwB%2BVJ74G6xvdMhWv20Wi2LGGvb6xJPh2zUIEd0UqydvOnHz8aN1glHLq9mBgd0LZ5XEomBWL%2BwNRRgErJLjAsSmjgrH0ea2pJ%2BAYR6KtTJ0J2VtWPDekKrKukMS2ZRRHnLD2pCesyC05zSpmVVm7fjXOUlOglmi9j2SoDaqY6pCk0WcUjzbvSRHDGWzkPQXHiapQrarqpbAyaouq4r1moZzokrcLVbWKv%2B91eNQqBw2rWhnquw9%2Bp6Tdhrd1MSscVK2kVcizklMBW23aO1bL7IneW08gFq2OVeJVV6zWGCL7BndL1N5W2qfiK5%2FYLnew1o7byCgIP3zQQT2rZW2wVJzH0G%2FSbwKoG%2F22KZpK4UFjcmc%2FaqpOKNqy6HeVT5QlCS9pCq652LYbk1yitGCRUDk6%2BmKpA2g%2Fqdala0qeF7iI7HsCbCWr7pEeXXJfEbUEQElt1SZytXcHOS7C63pvRUlpefaji4W2VJjgurXMiKWCFaYD5hUnCEy7o1Vikla11LoiSy9Gp9qGaGM5%2BQGWM3U1oM2hfbeWqvVPaEKbcAjqNU8S60sw6edBbUdmx4tI6j5Ummp3PJDBfRhIhAiCbZhueLq5g4Hl4%2B1F%2F%2Bbfn%2F%2F8569PYLoFy1koVDa2A6P77bI0fsRqtW8q65Zp4jTJ7rBdzHtBUVl4E3v2XST%2F70piVAO8Xc2Xk%2B8DmP0UzM1ODb4wh%2FvEc5%2BO%2F8tqT6G4mM7mwREl%2B1UpY6f%2FC73Is6Q%3D)
|
|
91
97
|
- [Bouncing Ball](https://litecanvas.js.org?c=eJxtUstugzAQvPMVewTiBCdtpVYpPVStSu6ReraMiSy5gIyhRUn%2BvQZvg0NzsGTveGdmH0oYqKtGGlmVkEIneLimlNgTkQDsW1Vcmn64HzTr8KpZLtvG%2Fr9%2FDAIljeCs7FgTRkFQtCUfyWQpTRjB0WNBgc%2Fd2z6LNyR7331k%2B2QTbSd2%2FEIRtNDZ42zrnBkR5sbx%2Fhlf%2FcAivajYVwy58fH%2BCu8d7hlzBGhhyvcyPHhKTxJ4raw3AVVRgMgPorFRWUA4OVtgr15gLBtOJ8%2F2EsFnoK6iK0txCsv19kaUrp4exrDXgBS4Yl%2B1p0xwTMQpo1ZkE89zl7Y%2BuPjEzs%2F99KOf%2F9LDyFwKKowC%2FtRyzb5xE7hqQjrOm0vNC6mUb3jiJGj9brYAw27YwnrHpoVpdQnHIWIlfwGU6d0i)
|
package/dist/dist.dev.js
CHANGED
|
@@ -32,9 +32,7 @@
|
|
|
32
32
|
function litecanvas(settings = {}) {
|
|
33
33
|
const root = globalThis, math = Math, TWO_PI = math.PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
|
|
34
34
|
elem.addEventListener(evt, callback, false);
|
|
35
|
-
_browserEventListeners.push(
|
|
36
|
-
() => elem.removeEventListener(evt, callback, false)
|
|
37
|
-
);
|
|
35
|
+
_browserEventListeners.push(() => elem.removeEventListener(evt, callback, false));
|
|
38
36
|
}, isNumber = Number.isFinite, defaults = {
|
|
39
37
|
width: null,
|
|
40
38
|
height: null,
|
|
@@ -93,7 +91,7 @@
|
|
|
93
91
|
*
|
|
94
92
|
* @type {number}
|
|
95
93
|
*/
|
|
96
|
-
HALF_PI:
|
|
94
|
+
HALF_PI: TWO_PI / 4,
|
|
97
95
|
/**
|
|
98
96
|
* Calculates a linear (interpolation) value over t%.
|
|
99
97
|
*
|
|
@@ -158,16 +156,13 @@
|
|
|
158
156
|
* @param {number} max
|
|
159
157
|
* @returns {number}
|
|
160
158
|
*/
|
|
161
|
-
clamp: (value,
|
|
159
|
+
clamp: (value, min2, max2) => {
|
|
162
160
|
DEV: assert(isNumber(value), "clamp: 1st param must be a number");
|
|
163
|
-
DEV: assert(isNumber(
|
|
164
|
-
DEV: assert(isNumber(
|
|
165
|
-
DEV: assert(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
169
|
-
if (value < min) return min;
|
|
170
|
-
if (value > max) return max;
|
|
161
|
+
DEV: assert(isNumber(min2), "clamp: 2nd param must be a number");
|
|
162
|
+
DEV: assert(isNumber(max2), "clamp: 3rd param must be a number");
|
|
163
|
+
DEV: assert(max2 > min2, "clamp: the 2nd param must be less than the 3rd param");
|
|
164
|
+
if (value < min2) return min2;
|
|
165
|
+
if (value > max2) return max2;
|
|
171
166
|
return value;
|
|
172
167
|
},
|
|
173
168
|
/**
|
|
@@ -178,19 +173,12 @@
|
|
|
178
173
|
* @param {number} max
|
|
179
174
|
* @returns {number}
|
|
180
175
|
*/
|
|
181
|
-
wrap: (value,
|
|
176
|
+
wrap: (value, min2, max2) => {
|
|
182
177
|
DEV: assert(isNumber(value), "wrap: 1st param must be a number");
|
|
183
|
-
DEV: assert(isNumber(
|
|
184
|
-
DEV: assert(isNumber(
|
|
185
|
-
DEV: assert(
|
|
186
|
-
|
|
187
|
-
"randi: the 2nd param must be less than the 3rd param"
|
|
188
|
-
);
|
|
189
|
-
DEV: assert(
|
|
190
|
-
max !== min,
|
|
191
|
-
"randi: the 2nd param must be not equal to the 3rd param"
|
|
192
|
-
);
|
|
193
|
-
return value - (max - min) * math.floor((value - min) / (max - min));
|
|
178
|
+
DEV: assert(isNumber(min2), "wrap: 2nd param must be a number");
|
|
179
|
+
DEV: assert(isNumber(max2), "wrap: 3rd param must be a number");
|
|
180
|
+
DEV: assert(max2 > min2, "wrap: the 2nd param must be less than the 3rd param");
|
|
181
|
+
return value - (max2 - min2) * math.floor((value - min2) / (max2 - min2));
|
|
194
182
|
},
|
|
195
183
|
/**
|
|
196
184
|
* Re-maps a number from one range to another.
|
|
@@ -209,6 +197,7 @@
|
|
|
209
197
|
DEV: assert(isNumber(stop1), "map: 3rd param must be a number");
|
|
210
198
|
DEV: assert(isNumber(start2), "map: 4th param must be a number");
|
|
211
199
|
DEV: assert(isNumber(stop2), "map: 5th param must be a number");
|
|
200
|
+
DEV: assert(max !== min, "map: the 3rd param must be different than the 2nd param");
|
|
212
201
|
const result = (value - start1) / (stop1 - start1) * (stop2 - start2) + start2;
|
|
213
202
|
return withinBounds ? instance.clamp(result, start2, stop2) : result;
|
|
214
203
|
},
|
|
@@ -233,10 +222,19 @@
|
|
|
233
222
|
*
|
|
234
223
|
* @param {number} from - the lower bound
|
|
235
224
|
* @param {number} to - the higher bound
|
|
236
|
-
* @param {number} t - the
|
|
237
|
-
* @param {(n: number) => number} fn - the periodic function (which default to `Math.sin`)
|
|
225
|
+
* @param {number} t - value passed to the periodic function
|
|
226
|
+
* @param {(n: number) => number} [fn] - the periodic function (which default to `Math.sin`)
|
|
238
227
|
*/
|
|
239
|
-
wave: (from, to, t, fn = Math.sin) =>
|
|
228
|
+
wave: (from, to, t, fn = Math.sin) => {
|
|
229
|
+
DEV: assert(isNumber(from), "wave: 1st param must be a number");
|
|
230
|
+
DEV: assert(isNumber(to), "wave: 2nd param must be a number");
|
|
231
|
+
DEV: assert(isNumber(t), "wave: 3rd param must be a number");
|
|
232
|
+
DEV: assert(
|
|
233
|
+
"function" === typeof fn,
|
|
234
|
+
"wave: 4rd param must be a function (n: number) => number"
|
|
235
|
+
);
|
|
236
|
+
return from + (fn(t) + 1) / 2 * (to - from);
|
|
237
|
+
},
|
|
240
238
|
/** RNG API */
|
|
241
239
|
/**
|
|
242
240
|
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
@@ -246,18 +244,15 @@
|
|
|
246
244
|
* @param {number} [max=1.0]
|
|
247
245
|
* @returns {number} the random number
|
|
248
246
|
*/
|
|
249
|
-
rand: (
|
|
250
|
-
DEV: assert(isNumber(
|
|
251
|
-
DEV: assert(isNumber(
|
|
252
|
-
DEV: assert(
|
|
253
|
-
max > min,
|
|
254
|
-
"rand: the 1st param must be less than the 2nd param"
|
|
255
|
-
);
|
|
247
|
+
rand: (min2 = 0, max2 = 1) => {
|
|
248
|
+
DEV: assert(isNumber(min2), "rand: 1st param must be a number");
|
|
249
|
+
DEV: assert(isNumber(max2), "rand: 2nd param must be a number");
|
|
250
|
+
DEV: assert(max2 > min2, "rand: the 1st param must be less than the 2nd param");
|
|
256
251
|
const a = 1664525;
|
|
257
252
|
const c = 1013904223;
|
|
258
253
|
const m = 4294967296;
|
|
259
254
|
_rngSeed = (a * _rngSeed + c) % m;
|
|
260
|
-
return _rngSeed / m * (
|
|
255
|
+
return _rngSeed / m * (max2 - min2) + min2;
|
|
261
256
|
},
|
|
262
257
|
/**
|
|
263
258
|
* Generates a pseudorandom integer between min (inclusive) and max (inclusive)
|
|
@@ -266,14 +261,11 @@
|
|
|
266
261
|
* @param {number} [max=1]
|
|
267
262
|
* @returns {number} the random number
|
|
268
263
|
*/
|
|
269
|
-
randi: (
|
|
270
|
-
DEV: assert(isNumber(
|
|
271
|
-
DEV: assert(isNumber(
|
|
272
|
-
DEV: assert(
|
|
273
|
-
|
|
274
|
-
"randi: the 1st param must be less than the 2nd param"
|
|
275
|
-
);
|
|
276
|
-
return math.floor(instance.rand(min, max + 1));
|
|
264
|
+
randi: (min2 = 0, max2 = 1) => {
|
|
265
|
+
DEV: assert(isNumber(min2), "randi: 1st param must be a number");
|
|
266
|
+
DEV: assert(isNumber(max2), "randi: 2nd param must be a number");
|
|
267
|
+
DEV: assert(max2 > min2, "randi: the 1st param must be less than the 2nd param");
|
|
268
|
+
return math.floor(instance.rand(min2, max2 + 1));
|
|
277
269
|
},
|
|
278
270
|
/**
|
|
279
271
|
* Initializes the random number generator with an explicit seed value.
|
|
@@ -303,13 +295,7 @@
|
|
|
303
295
|
if (null == color) {
|
|
304
296
|
_ctx.clearRect(0, 0, _ctx.canvas.width, _ctx.canvas.height);
|
|
305
297
|
} else {
|
|
306
|
-
instance.rectfill(
|
|
307
|
-
0,
|
|
308
|
-
0,
|
|
309
|
-
_ctx.canvas.width,
|
|
310
|
-
_ctx.canvas.height,
|
|
311
|
-
color
|
|
312
|
-
);
|
|
298
|
+
instance.rectfill(0, 0, _ctx.canvas.width, _ctx.canvas.height, color);
|
|
313
299
|
}
|
|
314
300
|
},
|
|
315
301
|
/**
|
|
@@ -321,14 +307,13 @@
|
|
|
321
307
|
* @param {number} height
|
|
322
308
|
* @param {number} [color=0] the color index
|
|
323
309
|
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
310
|
+
*
|
|
311
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect
|
|
324
312
|
*/
|
|
325
313
|
rect(x, y, width, height, color, radii) {
|
|
326
314
|
DEV: assert(isNumber(x), "rect: 1st param must be a number");
|
|
327
315
|
DEV: assert(isNumber(y), "rect: 2nd param must be a number");
|
|
328
|
-
DEV: assert(
|
|
329
|
-
isNumber(width) && width > 0,
|
|
330
|
-
"rect: 3rd param must be a positive number"
|
|
331
|
-
);
|
|
316
|
+
DEV: assert(isNumber(width) && width > 0, "rect: 3rd param must be a positive number");
|
|
332
317
|
DEV: assert(
|
|
333
318
|
isNumber(height) && height >= 0,
|
|
334
319
|
"rect: 4th param must be a positive number or zero"
|
|
@@ -381,13 +366,7 @@
|
|
|
381
366
|
"rectfill: 6th param must be a number or array of at least 2 numbers"
|
|
382
367
|
);
|
|
383
368
|
_ctx.beginPath();
|
|
384
|
-
_ctx[radii ? "roundRect" : "rect"](
|
|
385
|
-
~~x,
|
|
386
|
-
~~y,
|
|
387
|
-
~~width,
|
|
388
|
-
~~height,
|
|
389
|
-
radii
|
|
390
|
-
);
|
|
369
|
+
_ctx[radii ? "roundRect" : "rect"](~~x, ~~y, ~~width, ~~height, radii);
|
|
391
370
|
instance.fill(color);
|
|
392
371
|
},
|
|
393
372
|
/**
|
|
@@ -448,14 +427,8 @@
|
|
|
448
427
|
line(x1, y1, x2, y2, color) {
|
|
449
428
|
DEV: assert(isNumber(x1), "line: 1st param must be a number");
|
|
450
429
|
DEV: assert(isNumber(y1), "line: 2nd param must be a number");
|
|
451
|
-
DEV: assert(
|
|
452
|
-
|
|
453
|
-
"line: 3rd param must be a positive number or zero"
|
|
454
|
-
);
|
|
455
|
-
DEV: assert(
|
|
456
|
-
isNumber(y2),
|
|
457
|
-
"line: 4th param must be a positive number or zero"
|
|
458
|
-
);
|
|
430
|
+
DEV: assert(isNumber(x2), "line: 3rd param must be a positive number or zero");
|
|
431
|
+
DEV: assert(isNumber(y2), "line: 4th param must be a positive number or zero");
|
|
459
432
|
DEV: assert(
|
|
460
433
|
null == color || isNumber(color) && color >= 0,
|
|
461
434
|
"line: 5th param must be a positive number or zero"
|
|
@@ -494,10 +467,7 @@
|
|
|
494
467
|
Array.isArray(segments) && segments.length > 0,
|
|
495
468
|
"linedash: 1st param must be an array of numbers"
|
|
496
469
|
);
|
|
497
|
-
DEV: assert(
|
|
498
|
-
isNumber(offset),
|
|
499
|
-
"linedash: 2nd param must be a number"
|
|
500
|
-
);
|
|
470
|
+
DEV: assert(isNumber(offset), "linedash: 2nd param must be a number");
|
|
501
471
|
_ctx.setLineDash(segments);
|
|
502
472
|
_ctx.lineDashOffset = offset;
|
|
503
473
|
},
|
|
@@ -518,10 +488,7 @@
|
|
|
518
488
|
null == color || isNumber(color) && color >= 0,
|
|
519
489
|
"text: 4th param must be a positive number or zero"
|
|
520
490
|
);
|
|
521
|
-
DEV: assert(
|
|
522
|
-
"string" === typeof fontStyle,
|
|
523
|
-
"text: 5th param must be a string"
|
|
524
|
-
);
|
|
491
|
+
DEV: assert("string" === typeof fontStyle, "text: 5th param must be a string");
|
|
525
492
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
|
|
526
493
|
_ctx.fillStyle = _colors[~~color % _colors.length];
|
|
527
494
|
_ctx.fillText(message, ~~x, ~~y);
|
|
@@ -532,10 +499,7 @@
|
|
|
532
499
|
* @param {string} family
|
|
533
500
|
*/
|
|
534
501
|
textfont(family) {
|
|
535
|
-
DEV: assert(
|
|
536
|
-
"string" === typeof family,
|
|
537
|
-
"textfont: 1st param must be a string"
|
|
538
|
-
);
|
|
502
|
+
DEV: assert("string" === typeof family, "textfont: 1st param must be a string");
|
|
539
503
|
_fontFamily = family;
|
|
540
504
|
},
|
|
541
505
|
/**
|
|
@@ -561,14 +525,9 @@
|
|
|
561
525
|
"textalign: 1st param must be null or one of the following strings: center, left, right, start or end."
|
|
562
526
|
);
|
|
563
527
|
DEV: assert(
|
|
564
|
-
null == baseline || [
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
"middle",
|
|
568
|
-
"hanging",
|
|
569
|
-
"alphabetic",
|
|
570
|
-
"ideographic"
|
|
571
|
-
].includes(baseline),
|
|
528
|
+
null == baseline || ["top", "bottom", "middle", "hanging", "alphabetic", "ideographic"].includes(
|
|
529
|
+
baseline
|
|
530
|
+
),
|
|
572
531
|
"textalign: 2nd param must be null or one of the following strings: middle, top, bottom, hanging, alphabetic or ideographic."
|
|
573
532
|
);
|
|
574
533
|
if (align) _ctx.textAlign = align;
|
|
@@ -679,10 +638,7 @@
|
|
|
679
638
|
*/
|
|
680
639
|
scale: (x, y) => {
|
|
681
640
|
DEV: assert(isNumber(x), "scale: 1st param must be a number");
|
|
682
|
-
DEV: assert(
|
|
683
|
-
null == y || isNumber(y),
|
|
684
|
-
"scale: 2nd param must be a number"
|
|
685
|
-
);
|
|
641
|
+
DEV: assert(null == y || isNumber(y), "scale: 2nd param must be a number");
|
|
686
642
|
return _ctx.scale(x, y || x);
|
|
687
643
|
},
|
|
688
644
|
/**
|
|
@@ -767,14 +723,13 @@
|
|
|
767
723
|
/**
|
|
768
724
|
* Turn given path into a clipping region.
|
|
769
725
|
*
|
|
726
|
+
* Note: always call `push()` before and `pop()` after.
|
|
727
|
+
*
|
|
770
728
|
* @param {Path2D} path
|
|
771
729
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
|
|
772
730
|
*/
|
|
773
731
|
clip(path) {
|
|
774
|
-
DEV: assert(
|
|
775
|
-
path instanceof Path2D,
|
|
776
|
-
"clip: 1st param must be a Path2D instance"
|
|
777
|
-
);
|
|
732
|
+
DEV: assert(path instanceof Path2D, "clip: 1st param must be a Path2D instance");
|
|
778
733
|
_ctx.clip(path);
|
|
779
734
|
},
|
|
780
735
|
/** SOUND API */
|
|
@@ -795,10 +750,7 @@
|
|
|
795
750
|
"sfx: 1st param must be an array"
|
|
796
751
|
);
|
|
797
752
|
DEV: assert(isNumber(pitchSlide), "sfx: 2nd param must be a number");
|
|
798
|
-
DEV: assert(
|
|
799
|
-
isNumber(volumeFactor),
|
|
800
|
-
"sfx: 3rd param must be a number"
|
|
801
|
-
);
|
|
753
|
+
DEV: assert(isNumber(volumeFactor), "sfx: 3rd param must be a number");
|
|
802
754
|
if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
|
|
803
755
|
return false;
|
|
804
756
|
}
|
|
@@ -828,15 +780,13 @@
|
|
|
828
780
|
* @param {pluginCallback} callback
|
|
829
781
|
*/
|
|
830
782
|
use(callback, config = {}) {
|
|
831
|
-
DEV: assert(
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
);
|
|
839
|
-
_initialized ? loadPlugin(callback, config) : _plugins.push([callback, config]);
|
|
783
|
+
DEV: assert("function" === typeof callback, "use: 1st param must be a function");
|
|
784
|
+
DEV: assert("object" === typeof config, "use: 2nd param must be an object");
|
|
785
|
+
if (_initialized) {
|
|
786
|
+
loadPlugin(callback, config);
|
|
787
|
+
} else {
|
|
788
|
+
_plugins.push([callback, config]);
|
|
789
|
+
}
|
|
840
790
|
},
|
|
841
791
|
/**
|
|
842
792
|
* Add a game event listener
|
|
@@ -846,14 +796,8 @@
|
|
|
846
796
|
* @returns {Function} a function to remove the listener
|
|
847
797
|
*/
|
|
848
798
|
listen(eventName, callback) {
|
|
849
|
-
DEV: assert(
|
|
850
|
-
|
|
851
|
-
"listen: 1st param must be a string"
|
|
852
|
-
);
|
|
853
|
-
DEV: assert(
|
|
854
|
-
"function" === typeof callback,
|
|
855
|
-
"listen: 2nd param must be a function"
|
|
856
|
-
);
|
|
799
|
+
DEV: assert("string" === typeof eventName, "listen: 1st param must be a string");
|
|
800
|
+
DEV: assert("function" === typeof callback, "listen: 2nd param must be a function");
|
|
857
801
|
eventName = eventName.toLowerCase();
|
|
858
802
|
_events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
|
|
859
803
|
_events[eventName].add(callback);
|
|
@@ -869,10 +813,7 @@
|
|
|
869
813
|
* @param {*} [arg4] any data to be passed over the listeners
|
|
870
814
|
*/
|
|
871
815
|
emit(eventName, arg1, arg2, arg3, arg4) {
|
|
872
|
-
DEV: assert(
|
|
873
|
-
"string" === typeof eventName,
|
|
874
|
-
"emit: 1st param must be a string"
|
|
875
|
-
);
|
|
816
|
+
DEV: assert("string" === typeof eventName, "emit: 1st param must be a string");
|
|
876
817
|
if (_initialized) {
|
|
877
818
|
eventName = eventName.toLowerCase();
|
|
878
819
|
triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
|
|
@@ -899,14 +840,9 @@
|
|
|
899
840
|
* @param {*} value
|
|
900
841
|
*/
|
|
901
842
|
def(key, value) {
|
|
902
|
-
DEV: assert(
|
|
903
|
-
"string" === typeof key,
|
|
904
|
-
"def: 1st param must be a string"
|
|
905
|
-
);
|
|
843
|
+
DEV: assert("string" === typeof key, "def: 1st param must be a string");
|
|
906
844
|
DEV: if (null == value) {
|
|
907
|
-
console.warn(
|
|
908
|
-
`def: key "${key}" was defined as ${value} but now is null`
|
|
909
|
-
);
|
|
845
|
+
console.warn(`def: key "${key}" was defined as ${value} but now is null`);
|
|
910
846
|
}
|
|
911
847
|
instance[key] = value;
|
|
912
848
|
if (settings.global) {
|
|
@@ -946,10 +882,7 @@
|
|
|
946
882
|
* @returns {any}
|
|
947
883
|
*/
|
|
948
884
|
stat(n) {
|
|
949
|
-
DEV: assert(
|
|
950
|
-
isNumber(n) && n >= 0,
|
|
951
|
-
"stat: 1st param must be a positive number"
|
|
952
|
-
);
|
|
885
|
+
DEV: assert(isNumber(n) && n >= 0, "stat: 1st param must be a positive number");
|
|
953
886
|
const list = [
|
|
954
887
|
// 0
|
|
955
888
|
settings,
|
|
@@ -1014,25 +947,50 @@
|
|
|
1014
947
|
on(root, "resize", resizeCanvas);
|
|
1015
948
|
}
|
|
1016
949
|
if (settings.tapEvents) {
|
|
1017
|
-
const _getXY = (
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
950
|
+
const _getXY = (
|
|
951
|
+
/**
|
|
952
|
+
* @param {number} pageX
|
|
953
|
+
* @param {number} pageY
|
|
954
|
+
*/
|
|
955
|
+
(pageX, pageY) => [
|
|
956
|
+
(pageX - _canvas.offsetLeft) / _scale,
|
|
957
|
+
(pageY - _canvas.offsetTop) / _scale
|
|
958
|
+
]
|
|
959
|
+
), _taps = /* @__PURE__ */ new Map(), _registerTap = (
|
|
960
|
+
/**
|
|
961
|
+
* @param {number} id
|
|
962
|
+
* @param {number} [x]
|
|
963
|
+
* @param {number} [y]
|
|
964
|
+
*/
|
|
965
|
+
(id, x, y) => {
|
|
966
|
+
const tap = {
|
|
967
|
+
x,
|
|
968
|
+
y,
|
|
969
|
+
startX: x,
|
|
970
|
+
startY: y,
|
|
971
|
+
// timestamp
|
|
972
|
+
ts: performance.now()
|
|
973
|
+
};
|
|
974
|
+
_taps.set(id, tap);
|
|
975
|
+
return tap;
|
|
976
|
+
}
|
|
977
|
+
), _updateTap = (
|
|
978
|
+
/**
|
|
979
|
+
* @param {number} id
|
|
980
|
+
* @param {number} x
|
|
981
|
+
* @param {number} y
|
|
982
|
+
*/
|
|
983
|
+
(id, x, y) => {
|
|
984
|
+
const tap = _taps.get(id) || _registerTap(id);
|
|
985
|
+
tap.x = x;
|
|
986
|
+
tap.y = y;
|
|
987
|
+
}
|
|
988
|
+
), _checkTapped = (
|
|
989
|
+
/**
|
|
990
|
+
* @param {{ts: number}} tap
|
|
991
|
+
*/
|
|
992
|
+
(tap) => tap && performance.now() - tap.ts <= 300
|
|
993
|
+
), preventDefault = (ev) => ev.preventDefault();
|
|
1036
994
|
let _pressingMouse = false;
|
|
1037
995
|
on(
|
|
1038
996
|
_canvas,
|
|
@@ -1237,10 +1195,7 @@
|
|
|
1237
1195
|
_canvas = document.querySelector(settings.canvas);
|
|
1238
1196
|
}
|
|
1239
1197
|
_canvas = _canvas || document.createElement("canvas");
|
|
1240
|
-
DEV: assert(
|
|
1241
|
-
_canvas && _canvas.tagName === "CANVAS",
|
|
1242
|
-
"Invalid canvas element"
|
|
1243
|
-
);
|
|
1198
|
+
DEV: assert(_canvas && _canvas.tagName === "CANVAS", "Invalid canvas element");
|
|
1244
1199
|
instance.def("CANVAS", _canvas);
|
|
1245
1200
|
_ctx = _canvas.getContext("2d");
|
|
1246
1201
|
on(_canvas, "click", () => root.focus());
|
|
@@ -1273,10 +1228,7 @@
|
|
|
1273
1228
|
_canvas.style.display = "block";
|
|
1274
1229
|
_canvas.style.margin = "auto";
|
|
1275
1230
|
}
|
|
1276
|
-
_scale = math.min(
|
|
1277
|
-
root.innerWidth / instance.W,
|
|
1278
|
-
root.innerHeight / instance.H
|
|
1279
|
-
);
|
|
1231
|
+
_scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H);
|
|
1280
1232
|
_scale = (settings.pixelart ? ~~_scale : _scale) || 1;
|
|
1281
1233
|
_canvas.style.width = instance.W * _scale + "px";
|
|
1282
1234
|
_canvas.style.height = instance.H * _scale + "px";
|