litecanvas 0.40.0 → 0.41.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 +20 -16
- package/dist/dist.js +171 -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 +200 -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,145 @@
|
|
|
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
|
+
const tap = {
|
|
752
|
+
x,
|
|
753
|
+
y,
|
|
754
|
+
startX: x,
|
|
755
|
+
startY: y,
|
|
756
|
+
// timestamp
|
|
757
|
+
ts: performance.now()
|
|
758
|
+
};
|
|
759
|
+
_taps.set(id, tap);
|
|
760
|
+
return tap;
|
|
761
|
+
}, _updateTap = (id, x, y) => {
|
|
762
|
+
const tap = _taps.get(id) || _registerTap(id);
|
|
763
|
+
tap.x = x;
|
|
764
|
+
tap.y = y;
|
|
765
|
+
}, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
|
|
766
|
+
let _pressingMouse = false;
|
|
767
|
+
on(_canvas, "mousedown", (ev) => {
|
|
768
|
+
ev.preventDefault();
|
|
769
|
+
const [x, y] = _getXY(ev.pageX, ev.pageY);
|
|
770
|
+
instance.emit("tap", x, y, 0);
|
|
771
|
+
_registerTap(0, x, y);
|
|
772
|
+
_pressingMouse = true;
|
|
773
|
+
});
|
|
774
|
+
on(_canvas, "mousemove", (ev) => {
|
|
775
|
+
ev.preventDefault();
|
|
776
|
+
const [x, y] = [_mouseX, _mouseY] = _getXY(ev.pageX, ev.pageY);
|
|
777
|
+
if (!_pressingMouse)
|
|
778
|
+
return;
|
|
779
|
+
instance.emit("tapping", x, y, 0);
|
|
780
|
+
_updateTap(0, x, y);
|
|
781
|
+
});
|
|
782
|
+
on(_canvas, "mouseup", (ev) => {
|
|
783
|
+
ev.preventDefault();
|
|
784
|
+
const tap = _taps.get(0);
|
|
785
|
+
const [x, y] = _getXY(ev.pageX, ev.pageY);
|
|
786
|
+
if (_checkTapped(tap)) {
|
|
787
|
+
instance.emit("tapped", tap.startX, tap.startY, 0);
|
|
788
|
+
}
|
|
789
|
+
instance.emit("untap", x, y, 0);
|
|
790
|
+
_taps.delete(0);
|
|
791
|
+
_pressingMouse = false;
|
|
792
|
+
});
|
|
793
|
+
on(_canvas, "touchstart", (ev) => {
|
|
794
|
+
ev.preventDefault();
|
|
795
|
+
const touches = ev.changedTouches;
|
|
796
|
+
for (let i = 0; i < touches.length; i++) {
|
|
797
|
+
const touch = touches[i];
|
|
798
|
+
const [x, y] = _getXY(touch.pageX, touch.pageY);
|
|
799
|
+
instance.emit("tap", x, y, touch.identifier + 1);
|
|
800
|
+
_registerTap(touch.identifier + 1, x, y);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
on(_canvas, "touchmove", (ev) => {
|
|
804
|
+
ev.preventDefault();
|
|
805
|
+
const touches = ev.changedTouches;
|
|
806
|
+
for (let i = 0; i < touches.length; i++) {
|
|
807
|
+
const touch = touches[i];
|
|
808
|
+
const [x, y] = _getXY(touch.pageX, touch.pageY);
|
|
809
|
+
instance.emit("tapping", x, y, touch.identifier + 1);
|
|
810
|
+
_updateTap(touch.identifier + 1, x, y);
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
const _touchEndHandler = (ev) => {
|
|
814
|
+
ev.preventDefault();
|
|
815
|
+
const existing = [];
|
|
816
|
+
if (ev.targetTouches.length > 0) {
|
|
817
|
+
for (const touch of ev.targetTouches) {
|
|
818
|
+
existing.push(touch.identifier + 1);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
for (const [id, tap] of _taps) {
|
|
822
|
+
if (existing.includes(id))
|
|
823
|
+
continue;
|
|
824
|
+
if (_checkTapped(tap)) {
|
|
825
|
+
instance.emit("tapped", tap.startX, tap.startY, id);
|
|
826
|
+
}
|
|
827
|
+
instance.emit("untap", tap.x, tap.y, id);
|
|
828
|
+
_taps.delete(id);
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
on(_canvas, "touchend", _touchEndHandler);
|
|
832
|
+
on(_canvas, "touchcancel", _touchEndHandler);
|
|
833
|
+
on(root, "blur", () => {
|
|
834
|
+
_pressingMouse = false;
|
|
835
|
+
if (_taps.size === 0)
|
|
836
|
+
return;
|
|
837
|
+
for (const [id, tap] of _taps) {
|
|
838
|
+
instance.emit("untap", tap.x, tap.y, id);
|
|
839
|
+
_taps.delete(id);
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
}
|
|
812
843
|
}
|
|
813
|
-
function
|
|
844
|
+
function drawFrame(now) {
|
|
814
845
|
let ticks = 0, t = now - _lastFrame;
|
|
815
846
|
_lastFrame = now;
|
|
816
847
|
_accumulated += t;
|
|
817
848
|
while (_accumulated >= _stepMs) {
|
|
818
|
-
emit("update", _step);
|
|
849
|
+
instance.emit("update", _step);
|
|
819
850
|
instance.setvar("ELAPSED", instance.ELAPSED + _step);
|
|
820
851
|
_accumulated -= _stepMs;
|
|
821
852
|
ticks++;
|
|
822
|
-
instance.setvar("TAPPED", false);
|
|
823
853
|
}
|
|
824
854
|
if (ticks) {
|
|
825
855
|
_drawCount++;
|
|
826
|
-
emit("draw");
|
|
856
|
+
instance.emit("draw");
|
|
827
857
|
_drawTime += _stepMs * ticks;
|
|
828
858
|
if (_drawTime + _accumulated >= 1e3) {
|
|
829
859
|
instance.setvar("FPS", _drawCount);
|
|
@@ -832,7 +862,7 @@
|
|
|
832
862
|
}
|
|
833
863
|
}
|
|
834
864
|
if (_rafid)
|
|
835
|
-
_rafid = requestAnimationFrame(
|
|
865
|
+
_rafid = requestAnimationFrame(drawFrame);
|
|
836
866
|
}
|
|
837
867
|
function setupCanvas() {
|
|
838
868
|
_canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
|
|
@@ -843,7 +873,7 @@
|
|
|
843
873
|
_canvas.width = instance.WIDTH;
|
|
844
874
|
_canvas.height = instance.HEIGHT || instance.WIDTH;
|
|
845
875
|
if (!_canvas.parentNode)
|
|
846
|
-
body.appendChild(_canvas);
|
|
876
|
+
document.body.appendChild(_canvas);
|
|
847
877
|
if (!settings.antialias || settings.pixelart) {
|
|
848
878
|
_ctx.imageSmoothingEnabled = false;
|
|
849
879
|
_canvas.style.imageRendering = "pixelated";
|
|
@@ -863,46 +893,27 @@
|
|
|
863
893
|
instance.setvar("WIDTH", innerWidth);
|
|
864
894
|
instance.setvar("HEIGHT", innerHeight);
|
|
865
895
|
} else if (_autoscale) {
|
|
866
|
-
_scale =
|
|
896
|
+
_scale = Math.min(
|
|
867
897
|
innerWidth / instance.WIDTH,
|
|
868
898
|
innerHeight / instance.HEIGHT
|
|
869
899
|
);
|
|
870
|
-
_scale = settings.pixelart ?
|
|
900
|
+
_scale = settings.pixelart ? Math.floor(_scale) : _scale;
|
|
871
901
|
_canvas.style.width = instance.WIDTH * _scale + "px";
|
|
872
902
|
_canvas.style.height = instance.HEIGHT * _scale + "px";
|
|
873
903
|
}
|
|
874
904
|
instance.setvar("CENTERX", instance.WIDTH / 2);
|
|
875
905
|
instance.setvar("CENTERY", instance.HEIGHT / 2);
|
|
876
|
-
_offsetTop = _canvas.offsetTop;
|
|
877
|
-
_offsetLeft = _canvas.offsetLeft;
|
|
878
906
|
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);
|
|
907
|
+
instance.emit("resized", _scale);
|
|
890
908
|
}
|
|
891
909
|
function loadPlugin(callback) {
|
|
892
|
-
const pluginData = callback(instance, _helpers);
|
|
910
|
+
const pluginData = callback(instance, _helpers, callback.__config);
|
|
893
911
|
if ("object" === typeof pluginData) {
|
|
894
912
|
for (const key in pluginData) {
|
|
895
913
|
instance.setvar(key, pluginData[key]);
|
|
896
914
|
}
|
|
897
915
|
}
|
|
898
916
|
}
|
|
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
917
|
if (settings.global) {
|
|
907
918
|
if (root.__litecanvas) {
|
|
908
919
|
throw new Error("Cannot instantiate litecanvas globally twice");
|