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 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
- // called at 60 fps by default
58
- // use to update your things
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
- // example: tap to change the circle position
61
- if (TAPPED) {
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
- // use to draw your things
72
+ // this function render the game scene
68
73
  function draw() {
69
- clear(bg) // clear the screen
70
- circfill(posx, posy, 50, color) // draw a circle
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=eJy1VV1SE0EQfs8p2qfdJQv5AZSiCFYKIlClYkFKzOO4O5tMuZlNzU6AEvEKnsA3D%2BF5vIBXsHt6drNRtHixKiTT0z1f%2F33d5MrKROhrUYZ3LYAbldrZPmz3uzFKM6mmM7sPO3tO7HRALG1RJiKX%2B5CJvJSt%2B6jVypY6sarQoLSyYQQEtBDpFQyg1%2B%2BycErCLp%2Ff0bnrFRMUdrZJSGVpSUUWKL4XeU7i0ej1eHRR3Uzqmwlswuno7OR0DB3Y8epL9VFWnkge6mlOFw5fGeeZjxN%2FLBdSpnjuu4DKpDCVfa4yWeJ5G89W3lqPfXV2PD5Fl3tkboWx7jlXg4uUFyIFAcmytMUcskJbQsPLF3gMg3mhi6kR8yCGoEPaslNdbVmb4XVoZBnB4NBVEkBl%2FoaiyNYxImch0TnYmSluIDgSGnRhOQqyDtAE23TfaNRykQorw9Rys8jBy%2FPh8dnrkwiMtEuj%2Fe0Tn2HkQ1klPB6%2BeTM6dpf1i3v%2FyldugHWs8KguUzGXUFxL89wXaiZ0iu1RerG0pX9LuC4OdliR4vNn0rzDnjtmdaAfOYcMNEdUzF%2BSEhE9lKPaE4zCgVSInoC5NAtnEbM6hu5Wd7cJmhY6wDJK20BGUXhXZWKk1E1XB5SuhycCua7U2jZHfsgEqg2ZTpxWy6Mx0dsrRh96plc5VLPRe9qtZSL0MxYr5vLvpuM59i67DbebCTIL3GNYFKUiatSD1x7wwGz4CdmA1NYzyMrJupJB3xdIMg%2BKTFurkkdu5sXpf%2FrkvR7UupoALogBbK6S6EUNrnFAD76rRnztFUeZzGTygYNMijxXJU3FjbKzdQahzsjEcuAxJx%2FXrponZhLtM%2Fd9FUMv%2Bi2UKgO3Ytq0AuvYuhxbc0RTI278Lk2QdIZtHj%2BptCtErqY6DBKprTS0buaKkvNLgyxKDD6sltvqOvRLN652Lb7F8YPxOVyOhxdjxGImrTjOXDukEbjzWyGxmcrz8M%2FS0P8Dj4DZKZM4u78VGYfy4XirLbCWrCsD5YrLZar0tJFs2OtiW%2FAv%2BPH128%2FvXyDYMnIhheXgoxh2Gq48ntTpw2h%2FK1010OQIP2EQIONd06MtTPyS4gufoi5aL%2BL%2FaBuG0d9FgJPhqxGcvx1dBHXZ%2F6zmBm7Avd1%2FobW5epdH5xejfUrrEckhqX8Bx8Nfnw%3D%3D)
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=eJxVUE1PAjEQve%2BvGA%2BGdrdilw%2FFKAcTSDTxYKIJB8Kh7ha2SWnJdtCNhv%2FulAWUQz9m3pv3ZsYa1IVynyowniTLrSvQeAfGGQTG4ScBWOsQ1ErDGDozbQu%2F1oAe7KnwokOkhuDZ8%2BT9if4bZSma98VADMWNuBUjcSdyKfJ8kez%2BmWw3pUINrMTWCKlq%2BvL4%2BjadUBTMtz6KXh966FrtVlgRWhE0lHvjqzH0pYQUSjyTL2v1dZyhsFrVTNKIAEtfA7MawZCGvKfnAc71KZdlbSFAZGJsDTMmu3lq%2BClNB3VN0LE8bD8C1swIyP9Yhbc%2Bkmgt86X1vmaI6fCSwoMdX%2By5qBuMQ7N48VOKrVXDGgE9yTOTRiyV3ZGAKuvJLBgX1QY8rcShHdEatgKFd8Fbmsuv2N6W%2F%2Fclyo5W9guGqpXp)
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 palette_default = colors = [
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 sounds_default = sounds = [
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 body = document.body, math = Math, PI = math.PI, TWO_PI = PI * 2, on = (elem, evt, callback) => elem.addEventListener(evt, callback), off = (elem, evt, callback) => elem.removeEventListener(evt, callback), time = () => performance.now(), NULL = null, UNDEF = void 0, defaults = {
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: NULL,
63
- height: NULL,
62
+ width: null,
63
+ height: null,
64
64
  autoscale: true,
65
65
  pixelart: false,
66
66
  antialias: true,
67
- background: NULL,
68
- canvas: NULL,
67
+ canvas: null,
69
68
  global: true,
70
69
  tapEvents: true,
71
- useMouse: false,
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, _bg = settings.background, _hasMouse = settings.useMouse || matchMedia("(pointer:fine)").matches, _tappingHandler, _scale = 1, _offsetTop = 0, _offsetLeft = 0, _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", _loop = {
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: palette_default,
83
- sounds: sounds_default
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: NULL,
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
- DT: _step,
106
- /** @type {number} */
107
- CENTERX: NULL,
99
+ CENTERX: null,
108
100
  /** @type {number} */
109
- CENTERY: NULL,
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) => math.min(math.max(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) * math.floor((value - min) / (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) => math.random() * (max - min) + min,
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
- clear(color) {
232
- if (NULL == color) {
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 = UNDEF) {
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 = UNDEF) {
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 : sounds_default[~~sound % sounds_default.length];
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 loop event listener
640
+ * Add a game event listener
680
641
  *
681
- * @param {string} event should be "init", "update", "draw" or "resized"
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?} a function to remove the listener or `undefined` if passed a invalid event
645
+ * @returns {function} a function to remove the listener
685
646
  */
686
647
  listen(event, callback, highPriority = false) {
687
- if (!_loop[event])
688
- return;
689
- _loop[event][highPriority ? "unshift" : "push"](callback);
648
+ _events[event] = _events[event] || [];
649
+ _events[event][highPriority ? "unshift" : "push"](callback);
690
650
  return () => {
691
- _loop[event] = _loop[event].filter((f) => f !== callback);
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) => palette_default[~~index % palette_default.length],
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] = math[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
- if (settings.tapEvents) {
788
- off(
789
- body,
790
- _hasMouse ? "mousemove" : "touchmove",
791
- _tappingHandler
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 _loop) {
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 = time();
811
- _rafid = requestAnimationFrame(frame);
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 frame(now) {
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(frame);
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 = math.min(
893
+ _scale = Math.min(
867
894
  innerWidth / instance.WIDTH,
868
895
  innerHeight / instance.HEIGHT
869
896
  );
870
- _scale = settings.pixelart ? math.floor(_scale) : _scale;
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");