litecanvas 0.82.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 +127 -172
- package/dist/dist.js +86 -65
- package/dist/dist.min.js +1 -1
- package/package.json +6 -3
- package/src/index.js +125 -182
- 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,9 @@
|
|
|
846
796
|
* @returns {Function} a function to remove the listener
|
|
847
797
|
*/
|
|
848
798
|
listen(eventName, callback) {
|
|
849
|
-
DEV: assert(
|
|
850
|
-
|
|
851
|
-
|
|
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");
|
|
801
|
+
eventName = eventName.toLowerCase();
|
|
857
802
|
_events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
|
|
858
803
|
_events[eventName].add(callback);
|
|
859
804
|
return () => _events[eventName].delete(callback);
|
|
@@ -868,11 +813,9 @@
|
|
|
868
813
|
* @param {*} [arg4] any data to be passed over the listeners
|
|
869
814
|
*/
|
|
870
815
|
emit(eventName, arg1, arg2, arg3, arg4) {
|
|
871
|
-
DEV: assert(
|
|
872
|
-
"string" === typeof eventName,
|
|
873
|
-
"emit: 1st param must be a string"
|
|
874
|
-
);
|
|
816
|
+
DEV: assert("string" === typeof eventName, "emit: 1st param must be a string");
|
|
875
817
|
if (_initialized) {
|
|
818
|
+
eventName = eventName.toLowerCase();
|
|
876
819
|
triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
|
|
877
820
|
triggerEvent(eventName, arg1, arg2, arg3, arg4);
|
|
878
821
|
triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
|
|
@@ -897,14 +840,9 @@
|
|
|
897
840
|
* @param {*} value
|
|
898
841
|
*/
|
|
899
842
|
def(key, value) {
|
|
900
|
-
DEV: assert(
|
|
901
|
-
"string" === typeof key,
|
|
902
|
-
"def: 1st param must be a string"
|
|
903
|
-
);
|
|
843
|
+
DEV: assert("string" === typeof key, "def: 1st param must be a string");
|
|
904
844
|
DEV: if (null == value) {
|
|
905
|
-
console.warn(
|
|
906
|
-
`def: key "${key}" was defined as ${value} but now is null`
|
|
907
|
-
);
|
|
845
|
+
console.warn(`def: key "${key}" was defined as ${value} but now is null`);
|
|
908
846
|
}
|
|
909
847
|
instance[key] = value;
|
|
910
848
|
if (settings.global) {
|
|
@@ -944,10 +882,7 @@
|
|
|
944
882
|
* @returns {any}
|
|
945
883
|
*/
|
|
946
884
|
stat(n) {
|
|
947
|
-
DEV: assert(
|
|
948
|
-
isNumber(n) && n >= 0,
|
|
949
|
-
"stat: 1st param must be a positive number"
|
|
950
|
-
);
|
|
885
|
+
DEV: assert(isNumber(n) && n >= 0, "stat: 1st param must be a positive number");
|
|
951
886
|
const list = [
|
|
952
887
|
// 0
|
|
953
888
|
settings,
|
|
@@ -974,7 +909,9 @@
|
|
|
974
909
|
// 11
|
|
975
910
|
_fontFamily
|
|
976
911
|
];
|
|
977
|
-
|
|
912
|
+
const data = { index: n, value: list[n] };
|
|
913
|
+
instance.emit("stat", data);
|
|
914
|
+
return data.value;
|
|
978
915
|
},
|
|
979
916
|
/**
|
|
980
917
|
* Stops the litecanvas instance and remove all event listeners.
|
|
@@ -1010,25 +947,50 @@
|
|
|
1010
947
|
on(root, "resize", resizeCanvas);
|
|
1011
948
|
}
|
|
1012
949
|
if (settings.tapEvents) {
|
|
1013
|
-
const _getXY = (
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
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();
|
|
1032
994
|
let _pressingMouse = false;
|
|
1033
995
|
on(
|
|
1034
996
|
_canvas,
|
|
@@ -1142,25 +1104,24 @@
|
|
|
1142
1104
|
});
|
|
1143
1105
|
}
|
|
1144
1106
|
if (settings.keyboardEvents) {
|
|
1145
|
-
const toLowerCase = (s) => s.toLowerCase();
|
|
1146
1107
|
const _keysDown = /* @__PURE__ */ new Set();
|
|
1147
1108
|
const _keysPress = /* @__PURE__ */ new Set();
|
|
1148
|
-
const keyCheck = (
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
);
|
|
1109
|
+
const keyCheck = (keySet, key = "") => {
|
|
1110
|
+
key = key.toLowerCase();
|
|
1111
|
+
return !key ? keySet.size > 0 : keySet.has("space" === key ? " " : key);
|
|
1152
1112
|
};
|
|
1153
1113
|
on(root, "keydown", (event) => {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1114
|
+
const key = event.key.toLowerCase();
|
|
1115
|
+
if (!_keysDown.has(key)) {
|
|
1116
|
+
_keysDown.add(key);
|
|
1117
|
+
_keysPress.add(key);
|
|
1157
1118
|
}
|
|
1158
1119
|
});
|
|
1159
1120
|
on(root, "keyup", (event) => {
|
|
1160
|
-
_keysDown.delete(
|
|
1121
|
+
_keysDown.delete(event.key.toLowerCase());
|
|
1161
1122
|
});
|
|
1162
1123
|
on(root, "blur", () => _keysDown.clear());
|
|
1163
|
-
instance.listen("after:
|
|
1124
|
+
instance.listen("after:update", () => _keysPress.clear());
|
|
1164
1125
|
instance.def(
|
|
1165
1126
|
"iskeydown",
|
|
1166
1127
|
/**
|
|
@@ -1234,10 +1195,7 @@
|
|
|
1234
1195
|
_canvas = document.querySelector(settings.canvas);
|
|
1235
1196
|
}
|
|
1236
1197
|
_canvas = _canvas || document.createElement("canvas");
|
|
1237
|
-
DEV: assert(
|
|
1238
|
-
_canvas && _canvas.tagName === "CANVAS",
|
|
1239
|
-
"Invalid canvas element"
|
|
1240
|
-
);
|
|
1198
|
+
DEV: assert(_canvas && _canvas.tagName === "CANVAS", "Invalid canvas element");
|
|
1241
1199
|
instance.def("CANVAS", _canvas);
|
|
1242
1200
|
_ctx = _canvas.getContext("2d");
|
|
1243
1201
|
on(_canvas, "click", () => root.focus());
|
|
@@ -1270,10 +1228,7 @@
|
|
|
1270
1228
|
_canvas.style.display = "block";
|
|
1271
1229
|
_canvas.style.margin = "auto";
|
|
1272
1230
|
}
|
|
1273
|
-
_scale = math.min(
|
|
1274
|
-
root.innerWidth / instance.W,
|
|
1275
|
-
root.innerHeight / instance.H
|
|
1276
|
-
);
|
|
1231
|
+
_scale = math.min(root.innerWidth / instance.W, root.innerHeight / instance.H);
|
|
1277
1232
|
_scale = (settings.pixelart ? ~~_scale : _scale) || 1;
|
|
1278
1233
|
_canvas.style.width = instance.W * _scale + "px";
|
|
1279
1234
|
_canvas.style.height = instance.H * _scale + "px";
|