litecanvas 0.40.0 → 0.41.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 +20 -16
- package/dist/dist.js +168 -160
- package/dist/dist.min.js +1 -1
- package/dist/dist.min.js.map +3 -3
- package/package.json +2 -2
- package/src/index.js +197 -218
- package/src/palette.js +1 -1
- package/src/sounds.js +1 -1
- package/src/types.js +4 -11
- package/src/zzfx.js +7 -7
- package/types/index.d.ts +29 -71
- package/types/types.d.ts +25 -90
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Lightweight HTML5 canvas engine suitable for small games and animations for peop
|
|
|
17
17
|
- **Extensible**: Use or create [plugins](https://www.npmjs.com/search?q=keywords:litecanvas) to add functionalities or change the engine.
|
|
18
18
|
- **Offline Playground**: Install the [playground](https://litecanvas.js.org/) webapp and use anywhere at any time.
|
|
19
19
|
|
|
20
|
-
[Learn more](https://litecanvas.js.org/about.html)
|
|
20
|
+
[Learn more...](https://litecanvas.js.org/about.html)
|
|
21
21
|
|
|
22
22
|
## Getting Started
|
|
23
23
|
|
|
@@ -43,31 +43,36 @@ import litecanvas from 'litecanvas'
|
|
|
43
43
|
// you can setup other configurations here
|
|
44
44
|
// learn more in the cheatsheet
|
|
45
45
|
litecanvas({
|
|
46
|
-
loop: { init, update, draw },
|
|
46
|
+
loop: { init, update, draw, tapped },
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
// run once before the game starts
|
|
50
49
|
function init() {
|
|
50
|
+
// this function run once
|
|
51
|
+
// before the game starts
|
|
51
52
|
bg = 0
|
|
52
53
|
color = 3
|
|
54
|
+
radius = 32
|
|
53
55
|
posx = CENTERX
|
|
54
56
|
posy = CENTERY
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
+
// this function detect taps/clicks
|
|
60
|
+
// and changes the circle position
|
|
61
|
+
function tapped(x, y) {
|
|
62
|
+
posx = x
|
|
63
|
+
posy = y
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// this function controls the game logic
|
|
59
67
|
function update(dt) {
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
posx = TAPX
|
|
63
|
-
posy = TAPY
|
|
64
|
-
}
|
|
68
|
+
// make the circle falls 100 pixels per second
|
|
69
|
+
posy += 100 * dt
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
//
|
|
72
|
+
// this function render the game scene
|
|
68
73
|
function draw() {
|
|
69
|
-
|
|
70
|
-
circfill(posx, posy,
|
|
74
|
+
cls(bg) // clear the screen
|
|
75
|
+
circfill(posx, posy, radius, color) // draw a circle
|
|
71
76
|
}
|
|
72
77
|
```
|
|
73
78
|
|
|
@@ -79,11 +84,10 @@ Check out our [Cheatsheet](https://litecanvas.js.org/about.html).
|
|
|
79
84
|
|
|
80
85
|
Try some demos in our playground:
|
|
81
86
|
|
|
82
|
-
- [Pong](https://litecanvas.js.org?c=
|
|
87
|
+
- [Pong](https://litecanvas.js.org?c=eJy1VVFu20gM%2Ffcp2C9JsRLLTtwGQZzCSL1JgN1mkRhN%2FTmRRvZg5ZExGidpm%2FYKe4L96yF6nr3AXmHJ4UiW07TYnwUcezjkkHzkI1MoK1Oh70QVfuoA3KvMLo5gf5DEKC2kmi%2FsERwcJp3PUaeTr3VqValBaWXDCOjFSmQ3MIL%2BIGHhnIQhn9%2FTOfGKGQoH%2ByRksrKkIgsUb0VRkHg6eTudXNU3s%2BZmBrtwPrk4O59CDw68%2Blp9lHUkksd6XtCF86%2BMi8zHmT9WKykzPA9cQlVamtq%2BULms8LyPZysfrPd9c%2FFmeo4hD8ncCmPd81wUlezgVa8HRSkyEJCuK1suIS%2B1JW94%2BQsew2BZ6nJuxDKIIeiRturVV3vW5ngdGllFMDpxlQRQub%2BhLPJtH5GzkBgc7MKU9xCcCg26tJwFWQdogm363GqUFauVzMKHGD5wuyjEC48m8mHb8KxZS39ppF0bTT5bPfvyJXzAfriu92CwHW29yoSVYWafi8XuqGxWWexVlRop9Wtv53swwo60TediKaG8k%2Ba1L%2FkSBSyApAyyQvrXjmsv8LFLs8blGVhIs3IWMatjSPaSYeSAsdOs1AHWUdqWZxSFD8WZtkMdU5bePTHItaXRdrk8J8ygxpD5xLXreG%2FM9O6G0iee6jWGejj6L5NGJka%2FYrGmLv%2FuOqJjO%2FOHcL8NkBvjHsOqrBR1q5m87ognZsePyA5kthlCVs62lez0tsS%2Be6fY%2FK0qec9tXAz%2F8dFHPW50NVROYgS7GxD9yNNvU6tn39UzvvWKs0wXMv2Dk0zLolAVEfVe2cU2g1BnZGo58ZjBx02o9omZRAvNfd%2FE0I%2BepFIjcDumSzuwyS3h3NpTkxlx75dpiqQzZOOz%2BvVy%2FObi7Vk9EfX10wGmdSEKNddhkEptpaGNs1QEz%2B8Nsqgw%2FbDeb5vr0O%2FduF63%2BHY6%2Fh2ml3A9HV9N0RdzacNyZtsJDQEnQKXLVVGE3xeH%2FiV4D4hPmdTZ%2FajMQwf9mXx52TwB68pAWBdCz5Wet8CG%2FQQbg3%2FB3399%2FefbnxDsGbmSwnLyUQwHrVDen9TZ895%2BVLp6pCkQfsIgQM67tkd7CPya8gtfoi7aLuL%2F0TZMYzBEB2fj3yZw%2BW5yFTRl%2F76aO7gDD4c%2F89bl6l2fXl5NjgjWfwCHtP4XpMdclw%3D%3D)
|
|
83
88
|
- [Bouncing ball](https://litecanvas.js.org?c=eJxtUj1vgzAQ3fkVNxpCAklbqRWlQ9WqZI%2FU2TImsuQCAkOLkvz3GvsKDs3gwff8Pu7OUijOaNnTlvieJ7mCumqFElUJKfSckW0ch%2Fr4Buu5rJhQQ2Jux4b206WhuehaTbp%2F9LyiK5nREKVQxIeTBxMXdT%2F3b4cs2IXZ%2B%2F4jO0Q7P9FvUBGfxAhq6OJodnVOFSe5srp%2FeTc%2FsEonF30LIFcuPlzhg8WdYFYAI8x8h%2BHAMz2K4LXS2ThURQE8P%2FJWV0UBZE62wum8gGkbzmcn9hrBZ4htR1eRghTW2%2BRGNd48PZiyM4AUmKRfteMc4mJC64xeviZelil1fzDlxMkv8wwmz3%2FrcWWWgg7GwN1a3tBv%2FAlMtiQ2%2B2aiYYWQ0g08a4YY%2FW7xAca%2FoRsbrFrDVdeUcBor2vIXzlHggw%3D%3D)
|
|
84
|
-
- [Scroller](https://litecanvas.js.org?c=
|
|
89
|
+
- [Scroller](https://litecanvas.js.org?c=eJxVUMFOwzAMvfcrzAEtacNIxwZDsAPSJoG0AxJIO0w7hDZdI6XN1HhQgfbvOOs22CGJ7ff8nh1rUGeq%2FlSe8SgqtnWGxtVgaoPAOPxEAJX2Xq01TKC30DZzlQZ0YE%2BNFz0itQQvXqbvzxRvlKVsORQjcSvuxFjci1SKNF1Fu38W202uUAPLsbNB6pnNn17fZlPKvPnWR8nrwwR9q%2Bs1loSWBI3k3vZqAjdSQgw5nsnnjfo6bpBZzySnoHANMKsRDAnIB3oe4VycaknSdQEEJoa5MGGyn8aGn8p0UDcEHdv99sNjw4yA9I%2BVOesCiX5kWVjnGoYYjy4pPdjx1Z6LusWwMQsXP5VYpVrWChhInpg4YLHsjwWUyUAm3tRBbcjjUhzGEZ1hENjRZ%2FwCV%2F6J0w%3D%3D)
|
|
85
90
|
- [3D Projection](https://litecanvas.js.org?c=eJyNVU2P2jAQvfMrpodqnWI%2By6kt7WW3hVulrtTuRjk4JCyG4CDHFJYV%2F73jj5CYDUslROx579njGc844yqdMfGXFSRoteZbMVM8F8AFVySAlxZAxkW644lakGGA04IfUhjD7%2Bnt%2FQS%2BwuRu%2BmNyD9%2FKQQ9G8MmhOEbBRubL1K46hhANAOGAQh9%2FEbVTHA%2F8qbaYaaRXyLlQRaXuaB8o1D8RhV4Pwj2FZwqHyPKaaHWkAehcQ2oEf7GLwGt7pxGIqliliT6sNjDxlOlw91vHWna2m4SplCTKZsiS2sjq9gctNMxzCSRLFXAt%2FYyfLy6I3SwVT2qBpnbbigFmuSgU4jrChjVcMyX5nnS7XasKeRQYql5T5opZD5G23mbEGNCtP8Q4ElC9luVf5D6cuI5yhf%2FYzHeul1Eb3lbK6tqdaU5sPJU%2BcSVG%2BOjFOZFs56pglhWkH5gUYUSIvaLff%2F6iMAp0yDfbYkE0riQTRabTUxbBkFbFYUqoKT2j85QIdIpwCoRDGwYBvIcRrZwNfBpSECU1bmBNlwQUeAPhaIptg%2BeoR6EUMQoxdfeoag3EXREWhX39KxnaMPAM8TkjPjE%2B%2Bju6FOoNXfRNntksz%2FQlZahxF7nCZL4z2DkQO1HcIIqdKC4BRPgciN3o3XhsGQGoBX4B%2ByDcSZlLcjPFjpnxBGylpMWNuQR2VZkWZfk2Zdp46mUbBfYuhrZxnVRLq1qiyhwDh5XKVmOxXZv2YC0n5coqV3o%2Fq1zVlWB0bR1KHoWrCD5gfFZRuIwc4ei%2B1jW043ooaZXYUR9XpmorheZ42av6gWQJx2qw%2Bzr2xRdglhcngWmnojatE33El%2FVdK23y5%2BEtf86W8Xe58E6d%2B%2Bg784Ynj%2F%2FvyaU4XA%2FCq4e07onX592r6TsT7rEuw2f9d4i0%2BB%2FEGGLo)
|
|
86
|
-
- [Clip](https://litecanvas.js.org?c=eJx1UE1LxDAUvPdXvNsmNEi2blnw4yCo215kwYJK6aG2qRssaUlTbZX9774mtbgHIR9vhuS9mamlEUWuPvKOUM%2BrelUY2SiQShpC4dsDGOAa1pxjNWK1DT2sXptBdIjSDEHVaCC1MCCR4Zd4XUHIp8L3XYv5w1nbdweS6lyVknAGT%2FFtElEGCxHdxbsoWZgNgy3NKDY44u7kl5ikBKF3%2FKO0b8vcCFIaN0pWQJKb%2FT5%2B2P3Ongwg9WzB6MDL3PSkVanzz9l0UXeET5OtZGoZ2RZSF2RgMDKrhs4Pz%2Bk%2FKTjXtVBv5nAShxaFqWRdE%2FsilVnKMwYLWCMIQrcXMrBJYA5GN%2B%2FCqZsstE1rBRoxmClEXKv7%2FePFyseTwYaixx%2BHoYO9)
|
|
87
91
|
|
|
88
92
|
_See other demos in [samples](samples) folder_
|
|
89
93
|
|
package/dist/dist.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
// src/palette.js
|
|
29
|
-
var
|
|
29
|
+
var colors = [
|
|
30
30
|
"#18161c",
|
|
31
31
|
"#6a7799",
|
|
32
32
|
"#aec2c2",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
];
|
|
43
43
|
|
|
44
44
|
// src/sounds.js
|
|
45
|
-
var
|
|
45
|
+
var sounds = [
|
|
46
46
|
// 0 - pickup
|
|
47
47
|
[0.8, 0, 2e3, 0.01, 0.05, , 1, 2, , , -600, 0.05, , , , , , 0.5, 0.05],
|
|
48
48
|
// 1 - hit
|
|
@@ -56,31 +56,33 @@
|
|
|
56
56
|
// src/index.js
|
|
57
57
|
var root = globalThis;
|
|
58
58
|
function litecanvas(settings = {}) {
|
|
59
|
-
const
|
|
59
|
+
const PI = Math.PI, TWO_PI = PI * 2, on = (elem, evt, callback) => elem.addEventListener(evt, callback), defaults = {
|
|
60
60
|
fps: 60,
|
|
61
61
|
fullscreen: true,
|
|
62
|
-
width:
|
|
63
|
-
height:
|
|
62
|
+
width: null,
|
|
63
|
+
height: null,
|
|
64
64
|
autoscale: true,
|
|
65
65
|
pixelart: false,
|
|
66
66
|
antialias: true,
|
|
67
|
-
|
|
68
|
-
canvas: NULL,
|
|
67
|
+
canvas: null,
|
|
69
68
|
global: true,
|
|
70
69
|
tapEvents: true,
|
|
71
|
-
|
|
72
|
-
loop: NULL
|
|
70
|
+
loop: null
|
|
73
71
|
};
|
|
74
72
|
settings = Object.assign(defaults, settings);
|
|
75
|
-
let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale,
|
|
73
|
+
let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _scale = 1, _mouseX, _mouseY, _ctx, _lastFrame, _step = 1 / settings.fps, _stepMs = _step * 1e3, _accumulated = 0, _rafid, _drawCount = 0, _drawTime = 0, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _textAlign = "start", _textBaseline = "top", _events = {
|
|
76
74
|
init: [],
|
|
77
75
|
update: [],
|
|
78
76
|
draw: [],
|
|
79
|
-
resized: []
|
|
77
|
+
resized: [],
|
|
78
|
+
tap: [],
|
|
79
|
+
untap: [],
|
|
80
|
+
tapping: [],
|
|
81
|
+
tapped: []
|
|
80
82
|
}, _helpers = {
|
|
81
83
|
settings: Object.assign({}, settings),
|
|
82
|
-
colors
|
|
83
|
-
sounds
|
|
84
|
+
colors,
|
|
85
|
+
sounds
|
|
84
86
|
};
|
|
85
87
|
const instance = {
|
|
86
88
|
/** @type {number} */
|
|
@@ -88,25 +90,15 @@
|
|
|
88
90
|
/** @type {number} */
|
|
89
91
|
HEIGHT: settings.height || settings.width,
|
|
90
92
|
/** @type {HTMLCanvasElement} */
|
|
91
|
-
CANVAS:
|
|
92
|
-
/** @type {boolean} */
|
|
93
|
-
TAPPED: NULL,
|
|
94
|
-
/** @type {boolean} */
|
|
95
|
-
TAPPING: NULL,
|
|
96
|
-
/** @type {number} */
|
|
97
|
-
TAPX: NULL,
|
|
98
|
-
/** @type {number} */
|
|
99
|
-
TAPY: NULL,
|
|
93
|
+
CANVAS: null,
|
|
100
94
|
/** @type {number} */
|
|
101
95
|
ELAPSED: 0,
|
|
102
96
|
/** @type {number} */
|
|
103
97
|
FPS: settings.fps,
|
|
104
98
|
/** @type {number} */
|
|
105
|
-
|
|
106
|
-
/** @type {number} */
|
|
107
|
-
CENTERX: NULL,
|
|
99
|
+
CENTERX: null,
|
|
108
100
|
/** @type {number} */
|
|
109
|
-
CENTERY:
|
|
101
|
+
CENTERY: null,
|
|
110
102
|
/** MATH API */
|
|
111
103
|
/**
|
|
112
104
|
* The value of the mathematical constant PI (π).
|
|
@@ -164,7 +156,7 @@
|
|
|
164
156
|
* @param {number} max
|
|
165
157
|
* @returns {number}
|
|
166
158
|
*/
|
|
167
|
-
clamp: (value, min, max) =>
|
|
159
|
+
clamp: (value, min, max) => Math.min(Math.max(value, min), max),
|
|
168
160
|
/**
|
|
169
161
|
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
170
162
|
*
|
|
@@ -173,7 +165,7 @@
|
|
|
173
165
|
* @param {number} max
|
|
174
166
|
* @returns {number}
|
|
175
167
|
*/
|
|
176
|
-
wrap: (value, min, max) => value - (max - min) *
|
|
168
|
+
wrap: (value, min, max) => value - (max - min) * Math.floor((value - min) / (max - min)),
|
|
177
169
|
/**
|
|
178
170
|
* Re-maps a number from one range to another.
|
|
179
171
|
*
|
|
@@ -198,13 +190,6 @@
|
|
|
198
190
|
* @returns {number} the normalized number.
|
|
199
191
|
*/
|
|
200
192
|
norm: (value, min, max) => instance.map(value, min, max, 0, 1),
|
|
201
|
-
/**
|
|
202
|
-
* Returns the fractional part of a number
|
|
203
|
-
*
|
|
204
|
-
* @param {number} value The number
|
|
205
|
-
* @returns {number}
|
|
206
|
-
*/
|
|
207
|
-
fract: (value) => value % 1,
|
|
208
193
|
/** RNG API */
|
|
209
194
|
/**
|
|
210
195
|
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
@@ -213,7 +198,7 @@
|
|
|
213
198
|
* @param {number} [max=1.0]
|
|
214
199
|
* @returns {number} the random number
|
|
215
200
|
*/
|
|
216
|
-
rand: (min = 0, max = 1) =>
|
|
201
|
+
rand: (min = 0, max = 1) => Math.random() * (max - min) + min,
|
|
217
202
|
/**
|
|
218
203
|
* Generates a pseudorandom integer between min (inclusive) and max (inclusive)
|
|
219
204
|
*
|
|
@@ -228,8 +213,8 @@
|
|
|
228
213
|
*
|
|
229
214
|
* @param {number|null} color The background color (from 0 to 7) or null
|
|
230
215
|
*/
|
|
231
|
-
|
|
232
|
-
if (
|
|
216
|
+
cls(color) {
|
|
217
|
+
if (null == color) {
|
|
233
218
|
_ctx.clearRect(0, 0, instance.WIDTH, instance.HEIGHT);
|
|
234
219
|
} else {
|
|
235
220
|
instance.rectfill(0, 0, instance.WIDTH, instance.HEIGHT, color);
|
|
@@ -245,7 +230,7 @@
|
|
|
245
230
|
* @param {number} [color=0] the color index (generally from 0 to 7)
|
|
246
231
|
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
247
232
|
*/
|
|
248
|
-
rect(x, y, width, height, color = 0, radii =
|
|
233
|
+
rect(x, y, width, height, color = 0, radii = null) {
|
|
249
234
|
_ctx.beginPath();
|
|
250
235
|
_ctx[radii ? "roundRect" : "rect"](
|
|
251
236
|
~~x,
|
|
@@ -266,7 +251,7 @@
|
|
|
266
251
|
* @param {number} [color=0] the color index (generally from 0 to 7)
|
|
267
252
|
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
268
253
|
*/
|
|
269
|
-
rectfill(x, y, width, height, color = 0, radii =
|
|
254
|
+
rectfill(x, y, width, height, color = 0, radii = null) {
|
|
270
255
|
_ctx.beginPath();
|
|
271
256
|
_ctx[radii ? "roundRect" : "rect"](
|
|
272
257
|
~~x,
|
|
@@ -341,26 +326,6 @@
|
|
|
341
326
|
_ctx.setLineDash(Array.isArray(segments) ? segments : [segments]);
|
|
342
327
|
_ctx.lineDashOffset = offset;
|
|
343
328
|
},
|
|
344
|
-
/**
|
|
345
|
-
* Determines the shape used to draw the end points of lines
|
|
346
|
-
* Possible values are: "butt", "round" or "square"
|
|
347
|
-
*
|
|
348
|
-
* @param {string} value
|
|
349
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineCap
|
|
350
|
-
*/
|
|
351
|
-
linecap(value) {
|
|
352
|
-
_ctx.lineCap = value;
|
|
353
|
-
},
|
|
354
|
-
/**
|
|
355
|
-
* Determines the shape used to join two line segments where they meet
|
|
356
|
-
* Possible values are: "round", "bevel", and "miter"
|
|
357
|
-
*
|
|
358
|
-
* @param {string} value
|
|
359
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
|
|
360
|
-
*/
|
|
361
|
-
linejoin(value) {
|
|
362
|
-
_ctx.lineJoin = value;
|
|
363
|
-
},
|
|
364
329
|
/** TEXT RENDERING API */
|
|
365
330
|
/**
|
|
366
331
|
* Draw text
|
|
@@ -605,16 +570,6 @@
|
|
|
605
570
|
blendmode(value) {
|
|
606
571
|
_ctx.globalCompositeOperation = value;
|
|
607
572
|
},
|
|
608
|
-
/**
|
|
609
|
-
* Provides filter effects such as blurring and grayscaling.
|
|
610
|
-
* It is similar to the CSS filter property and accepts the same values.
|
|
611
|
-
*
|
|
612
|
-
* @param {string} effect
|
|
613
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
|
|
614
|
-
*/
|
|
615
|
-
filter(effect) {
|
|
616
|
-
_ctx.filter = effect;
|
|
617
|
-
},
|
|
618
573
|
/** SOUND API */
|
|
619
574
|
/**
|
|
620
575
|
* Play a defined sound or a ZzFX array of params
|
|
@@ -630,7 +585,7 @@
|
|
|
630
585
|
if (navigator.userActivation && !navigator.userActivation.hasBeenActive) {
|
|
631
586
|
return;
|
|
632
587
|
}
|
|
633
|
-
let z = Array.isArray(sound) ? sound :
|
|
588
|
+
let z = Array.isArray(sound) ? sound : sounds[~~sound % sounds.length];
|
|
634
589
|
if (volume !== 1 || pitch || randomness) {
|
|
635
590
|
z = [...z];
|
|
636
591
|
z[0] = (Number(volume) || 1) * (z[0] || 1);
|
|
@@ -666,38 +621,58 @@
|
|
|
666
621
|
* @returns {boolean}
|
|
667
622
|
*/
|
|
668
623
|
colcirc: (x1, y1, r1, x2, y2, r2) => (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
|
|
624
|
+
/**
|
|
625
|
+
* Get the mouse position
|
|
626
|
+
* @returns number[]
|
|
627
|
+
*/
|
|
628
|
+
mousepos: () => [_mouseX, _mouseY],
|
|
669
629
|
/** PLUGINS API */
|
|
670
630
|
/**
|
|
671
631
|
* Prepares a plugin to be loaded
|
|
672
632
|
*
|
|
673
633
|
* @param {pluginCallback} callback
|
|
674
634
|
*/
|
|
675
|
-
use: (callback) => {
|
|
635
|
+
use: (callback, config = {}) => {
|
|
636
|
+
callback.__config = config;
|
|
676
637
|
_initialized ? loadPlugin(callback) : _plugins.push(callback);
|
|
677
638
|
},
|
|
678
639
|
/**
|
|
679
|
-
* Add a game
|
|
640
|
+
* Add a game event listener
|
|
680
641
|
*
|
|
681
|
-
* @param {string} event
|
|
642
|
+
* @param {string} event the event type name
|
|
682
643
|
* @param {function} callback the function that is called when the event occurs
|
|
683
644
|
* @param {boolean} [highPriority=false] determines whether the callback will be called before or after the others
|
|
684
|
-
* @returns {function
|
|
645
|
+
* @returns {function} a function to remove the listener
|
|
685
646
|
*/
|
|
686
647
|
listen(event, callback, highPriority = false) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
_loop[event][highPriority ? "unshift" : "push"](callback);
|
|
648
|
+
_events[event] = _events[event] || [];
|
|
649
|
+
_events[event][highPriority ? "unshift" : "push"](callback);
|
|
690
650
|
return () => {
|
|
691
|
-
|
|
651
|
+
_events[event] = _events[event].filter(
|
|
652
|
+
(item) => item !== callback
|
|
653
|
+
);
|
|
692
654
|
};
|
|
693
655
|
},
|
|
656
|
+
/**
|
|
657
|
+
* Call all listeners attached to a game event
|
|
658
|
+
*
|
|
659
|
+
* @param {string} event The game event type
|
|
660
|
+
* @param {...any} args Arguments passed to all listeners
|
|
661
|
+
*/
|
|
662
|
+
emit(event, ...args) {
|
|
663
|
+
if (!_events[event])
|
|
664
|
+
return;
|
|
665
|
+
for (let i = 0; i < _events[event].length; ++i) {
|
|
666
|
+
_events[event][i](...args);
|
|
667
|
+
}
|
|
668
|
+
},
|
|
694
669
|
/**
|
|
695
670
|
* Get the color value
|
|
696
671
|
*
|
|
697
672
|
* @param {number} index The color number
|
|
698
673
|
* @returns {string} the color value
|
|
699
674
|
*/
|
|
700
|
-
getcolor: (index) =>
|
|
675
|
+
getcolor: (index) => colors[~~index % colors.length],
|
|
701
676
|
/**
|
|
702
677
|
* Create or update a instance variable
|
|
703
678
|
*
|
|
@@ -722,8 +697,6 @@
|
|
|
722
697
|
pageResized();
|
|
723
698
|
}
|
|
724
699
|
};
|
|
725
|
-
instance.cls = instance.clear;
|
|
726
|
-
instance.print = instance.text;
|
|
727
700
|
for (const k of [
|
|
728
701
|
"sin",
|
|
729
702
|
"cos",
|
|
@@ -742,88 +715,142 @@
|
|
|
742
715
|
"sign",
|
|
743
716
|
"exp"
|
|
744
717
|
]) {
|
|
745
|
-
instance[k] =
|
|
718
|
+
instance[k] = Math[k];
|
|
746
719
|
}
|
|
747
720
|
function init() {
|
|
748
721
|
_initialized = true;
|
|
749
722
|
setupCanvas();
|
|
750
|
-
if (settings.tapEvents) {
|
|
751
|
-
const _tappedLimit = 200;
|
|
752
|
-
const _getXY = (event) => {
|
|
753
|
-
return _hasMouse ? [event.pageX, event.pageY] : [event.touches[0].pageX, event.touches[0].pageY];
|
|
754
|
-
}, _eventTapStart = _hasMouse ? "mousedown" : "touchstart", _eventTapEnd = _hasMouse ? "mouseup" : "touchend", _eventTapMove = _hasMouse ? "mousemove" : "touchmove";
|
|
755
|
-
let _tapStartX, _tapStartY, _last, _start;
|
|
756
|
-
_tappingHandler = (ev) => {
|
|
757
|
-
updateTapping(true, ..._getXY(ev));
|
|
758
|
-
};
|
|
759
|
-
on(instance.CANVAS, _eventTapStart, function(ev) {
|
|
760
|
-
ev.preventDefault();
|
|
761
|
-
if (!_rafid)
|
|
762
|
-
_resume();
|
|
763
|
-
on(body, _eventTapMove, _tappingHandler);
|
|
764
|
-
const [x, y] = [_tapStartX, _tapStartY] = _getXY(ev);
|
|
765
|
-
updateTapping(true, x, y);
|
|
766
|
-
_last = _start = time();
|
|
767
|
-
});
|
|
768
|
-
on(instance.CANVAS, _eventTapEnd, function(ev) {
|
|
769
|
-
off(body, _eventTapMove, _tappingHandler);
|
|
770
|
-
updateTapping(false);
|
|
771
|
-
if (time() - _start <= _tappedLimit) {
|
|
772
|
-
updateTapped(true, _tapStartX, _tapStartY);
|
|
773
|
-
}
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
on(root, "focus", () => {
|
|
777
|
-
if (!_rafid)
|
|
778
|
-
_resume();
|
|
779
|
-
});
|
|
780
|
-
function _resume() {
|
|
781
|
-
_lastFrame = time();
|
|
782
|
-
_rafid = requestAnimationFrame(frame);
|
|
783
|
-
}
|
|
784
723
|
on(root, "blur", () => {
|
|
785
724
|
cancelAnimationFrame(_rafid);
|
|
786
725
|
_rafid = 0;
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
);
|
|
793
|
-
updateTapping(false);
|
|
726
|
+
});
|
|
727
|
+
on(root, "focus", () => {
|
|
728
|
+
if (!_rafid) {
|
|
729
|
+
_lastFrame = performance.now();
|
|
730
|
+
_rafid = requestAnimationFrame(drawFrame);
|
|
794
731
|
}
|
|
795
732
|
});
|
|
796
733
|
const source = settings.loop ? settings.loop : root;
|
|
797
|
-
for (const event in
|
|
734
|
+
for (const event in _events) {
|
|
798
735
|
if (source[event])
|
|
799
736
|
instance.listen(event, source[event]);
|
|
800
737
|
}
|
|
801
738
|
for (let i = 0; i < _plugins.length; i++) {
|
|
802
739
|
loadPlugin(_plugins[i]);
|
|
803
740
|
}
|
|
804
|
-
if (NULL != _bg) {
|
|
805
|
-
instance.CANVAS.style.background = instance.getcolor(_bg);
|
|
806
|
-
}
|
|
807
741
|
on(root, "resize", pageResized);
|
|
808
742
|
pageResized();
|
|
809
|
-
emit("init");
|
|
810
|
-
_lastFrame =
|
|
811
|
-
_rafid = requestAnimationFrame(
|
|
743
|
+
instance.emit("init");
|
|
744
|
+
_lastFrame = performance.now();
|
|
745
|
+
_rafid = requestAnimationFrame(drawFrame);
|
|
746
|
+
if (settings.tapEvents) {
|
|
747
|
+
const _getXY = (pageX, pageY) => [
|
|
748
|
+
(pageX - _canvas.offsetLeft) / _scale,
|
|
749
|
+
(pageY - _canvas.offsetTop) / _scale
|
|
750
|
+
], _taps = /* @__PURE__ */ new Map(), _registerTap = (id, x, y) => {
|
|
751
|
+
_taps.set(id, {
|
|
752
|
+
x,
|
|
753
|
+
y,
|
|
754
|
+
startX: x,
|
|
755
|
+
startY: y,
|
|
756
|
+
timestamp: performance.now()
|
|
757
|
+
});
|
|
758
|
+
}, _updateTap = (id, x, y) => {
|
|
759
|
+
const tap = _taps.get(id);
|
|
760
|
+
tap.x = x;
|
|
761
|
+
tap.y = y;
|
|
762
|
+
}, _checkTapped = (tap) => performance.now() - tap.timestamp <= 200;
|
|
763
|
+
let _pressingMouse = false;
|
|
764
|
+
on(_canvas, "mousedown", (ev) => {
|
|
765
|
+
ev.preventDefault();
|
|
766
|
+
const [x, y] = _getXY(ev.pageX, ev.pageY);
|
|
767
|
+
instance.emit("tap", x, y, 0);
|
|
768
|
+
_registerTap(0, x, y);
|
|
769
|
+
_pressingMouse = true;
|
|
770
|
+
});
|
|
771
|
+
on(_canvas, "mousemove", (ev) => {
|
|
772
|
+
ev.preventDefault();
|
|
773
|
+
const [x, y] = [_mouseX, _mouseY] = _getXY(ev.pageX, ev.pageY);
|
|
774
|
+
if (!_pressingMouse)
|
|
775
|
+
return;
|
|
776
|
+
instance.emit("tapping", x, y, 0);
|
|
777
|
+
_updateTap(0, x, y);
|
|
778
|
+
});
|
|
779
|
+
on(_canvas, "mouseup", (ev) => {
|
|
780
|
+
ev.preventDefault();
|
|
781
|
+
const tap = _taps.get(0);
|
|
782
|
+
const [x, y] = _getXY(ev.pageX, ev.pageY);
|
|
783
|
+
if (_checkTapped(tap)) {
|
|
784
|
+
instance.emit("tapped", tap.startX, tap.startY, 0);
|
|
785
|
+
}
|
|
786
|
+
instance.emit("untap", x, y, 0);
|
|
787
|
+
_taps.delete(0);
|
|
788
|
+
_pressingMouse = false;
|
|
789
|
+
});
|
|
790
|
+
on(_canvas, "touchstart", (ev) => {
|
|
791
|
+
ev.preventDefault();
|
|
792
|
+
const touches = ev.changedTouches;
|
|
793
|
+
for (let i = 0; i < touches.length; i++) {
|
|
794
|
+
const touch = touches[i];
|
|
795
|
+
const [x, y] = _getXY(touch.pageX, touch.pageY);
|
|
796
|
+
instance.emit("tap", x, y, touch.identifier + 1);
|
|
797
|
+
_registerTap(touch.identifier + 1, x, y);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
on(_canvas, "touchmove", (ev) => {
|
|
801
|
+
ev.preventDefault();
|
|
802
|
+
const touches = ev.changedTouches;
|
|
803
|
+
for (let i = 0; i < touches.length; i++) {
|
|
804
|
+
const touch = touches[i];
|
|
805
|
+
const [x, y] = _getXY(touch.pageX, touch.pageY);
|
|
806
|
+
instance.emit("tapping", x, y, touch.identifier + 1);
|
|
807
|
+
_updateTap(touch.identifier + 1, x, y);
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
const _touchEndHandler = (ev) => {
|
|
811
|
+
ev.preventDefault();
|
|
812
|
+
const existing = [];
|
|
813
|
+
if (ev.targetTouches.length > 0) {
|
|
814
|
+
for (const touch of ev.targetTouches) {
|
|
815
|
+
existing.push(touch.identifier + 1);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
for (const [id, tap] of _taps) {
|
|
819
|
+
if (existing.includes(id))
|
|
820
|
+
continue;
|
|
821
|
+
if (_checkTapped(tap)) {
|
|
822
|
+
instance.emit("tapped", tap.startX, tap.startY, id);
|
|
823
|
+
}
|
|
824
|
+
instance.emit("untap", tap.x, tap.y, id);
|
|
825
|
+
_taps.delete(id);
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
on(_canvas, "touchend", _touchEndHandler);
|
|
829
|
+
on(_canvas, "touchcancel", _touchEndHandler);
|
|
830
|
+
on(root, "blur", () => {
|
|
831
|
+
_pressingMouse = false;
|
|
832
|
+
if (_taps.size === 0)
|
|
833
|
+
return;
|
|
834
|
+
for (const [id, tap] of _taps) {
|
|
835
|
+
instance.emit("untap", tap.x, tap.y, id);
|
|
836
|
+
_taps.delete(id);
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
812
840
|
}
|
|
813
|
-
function
|
|
841
|
+
function drawFrame(now) {
|
|
814
842
|
let ticks = 0, t = now - _lastFrame;
|
|
815
843
|
_lastFrame = now;
|
|
816
844
|
_accumulated += t;
|
|
817
845
|
while (_accumulated >= _stepMs) {
|
|
818
|
-
emit("update", _step);
|
|
846
|
+
instance.emit("update", _step);
|
|
819
847
|
instance.setvar("ELAPSED", instance.ELAPSED + _step);
|
|
820
848
|
_accumulated -= _stepMs;
|
|
821
849
|
ticks++;
|
|
822
|
-
instance.setvar("TAPPED", false);
|
|
823
850
|
}
|
|
824
851
|
if (ticks) {
|
|
825
852
|
_drawCount++;
|
|
826
|
-
emit("draw");
|
|
853
|
+
instance.emit("draw");
|
|
827
854
|
_drawTime += _stepMs * ticks;
|
|
828
855
|
if (_drawTime + _accumulated >= 1e3) {
|
|
829
856
|
instance.setvar("FPS", _drawCount);
|
|
@@ -832,7 +859,7 @@
|
|
|
832
859
|
}
|
|
833
860
|
}
|
|
834
861
|
if (_rafid)
|
|
835
|
-
_rafid = requestAnimationFrame(
|
|
862
|
+
_rafid = requestAnimationFrame(drawFrame);
|
|
836
863
|
}
|
|
837
864
|
function setupCanvas() {
|
|
838
865
|
_canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
|
|
@@ -843,7 +870,7 @@
|
|
|
843
870
|
_canvas.width = instance.WIDTH;
|
|
844
871
|
_canvas.height = instance.HEIGHT || instance.WIDTH;
|
|
845
872
|
if (!_canvas.parentNode)
|
|
846
|
-
body.appendChild(_canvas);
|
|
873
|
+
document.body.appendChild(_canvas);
|
|
847
874
|
if (!settings.antialias || settings.pixelart) {
|
|
848
875
|
_ctx.imageSmoothingEnabled = false;
|
|
849
876
|
_canvas.style.imageRendering = "pixelated";
|
|
@@ -863,46 +890,27 @@
|
|
|
863
890
|
instance.setvar("WIDTH", innerWidth);
|
|
864
891
|
instance.setvar("HEIGHT", innerHeight);
|
|
865
892
|
} else if (_autoscale) {
|
|
866
|
-
_scale =
|
|
893
|
+
_scale = Math.min(
|
|
867
894
|
innerWidth / instance.WIDTH,
|
|
868
895
|
innerHeight / instance.HEIGHT
|
|
869
896
|
);
|
|
870
|
-
_scale = settings.pixelart ?
|
|
897
|
+
_scale = settings.pixelart ? Math.floor(_scale) : _scale;
|
|
871
898
|
_canvas.style.width = instance.WIDTH * _scale + "px";
|
|
872
899
|
_canvas.style.height = instance.HEIGHT * _scale + "px";
|
|
873
900
|
}
|
|
874
901
|
instance.setvar("CENTERX", instance.WIDTH / 2);
|
|
875
902
|
instance.setvar("CENTERY", instance.HEIGHT / 2);
|
|
876
|
-
_offsetTop = _canvas.offsetTop;
|
|
877
|
-
_offsetLeft = _canvas.offsetLeft;
|
|
878
903
|
instance.textalign(_textAlign, _textBaseline);
|
|
879
|
-
emit("resized");
|
|
880
|
-
}
|
|
881
|
-
function updateTapped(tapped, x, y) {
|
|
882
|
-
instance.setvar("TAPPED", tapped);
|
|
883
|
-
instance.setvar("TAPX", (x - _offsetLeft) / _scale);
|
|
884
|
-
instance.setvar("TAPY", (y - _offsetTop) / _scale);
|
|
885
|
-
}
|
|
886
|
-
function updateTapping(tapped, x, y) {
|
|
887
|
-
instance.setvar("TAPPING", tapped);
|
|
888
|
-
instance.setvar("TAPX", (x - _offsetLeft) / _scale);
|
|
889
|
-
instance.setvar("TAPY", (y - _offsetTop) / _scale);
|
|
904
|
+
instance.emit("resized", _scale);
|
|
890
905
|
}
|
|
891
906
|
function loadPlugin(callback) {
|
|
892
|
-
const pluginData = callback(instance, _helpers);
|
|
907
|
+
const pluginData = callback(instance, _helpers, callback.__config);
|
|
893
908
|
if ("object" === typeof pluginData) {
|
|
894
909
|
for (const key in pluginData) {
|
|
895
910
|
instance.setvar(key, pluginData[key]);
|
|
896
911
|
}
|
|
897
912
|
}
|
|
898
913
|
}
|
|
899
|
-
function emit(event, ...args) {
|
|
900
|
-
if (!_loop[event])
|
|
901
|
-
return;
|
|
902
|
-
for (let i = 0; i < _loop[event].length; ++i) {
|
|
903
|
-
_loop[event][i](...args);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
914
|
if (settings.global) {
|
|
907
915
|
if (root.__litecanvas) {
|
|
908
916
|
throw new Error("Cannot instantiate litecanvas globally twice");
|