@litecanvas/utils 0.24.0 → 0.24.2

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/dist/tween.js CHANGED
@@ -32,6 +32,974 @@
32
32
  LINEAR: () => LINEAR,
33
33
  tween: () => tween
34
34
  });
35
+
36
+ // node_modules/litecanvas/src/zzfx.js
37
+ var zzfxX = /* @__PURE__ */ new AudioContext();
38
+ var zzfx = (p = 1, k = 0.05, b = 220, e = 0, r = 0, t = 0.1, q = 0, D = 1, u = 0, y = 0, v = 0, z = 0, l = 0, E = 0, A = 0, F = 0, c = 0, w = 1, m = 0, B = 0, N = 0) => {
39
+ let M = Math, d = 2 * M.PI, R = 44100, G = u *= 500 * d / R / R, C = b *= (1 - k + 2 * k * M.random(k = [])) * d / R, g = 0, H = 0, a = 0, n = 1, I = 0, J = 0, f = 0, h = N < 0 ? -1 : 1, x = d * h * N * 2 / R, L = M.cos(x), Z = M.sin, K = Z(x) / 4, O = 1 + K, X = -2 * L / O, Y = (1 - K) / O, P = (1 + h * L) / 2 / O, Q = -(h + L) / O, S = P, T = 0, U = 0, V = 0, W = 0;
40
+ e = R * e + 9;
41
+ m *= R;
42
+ r *= R;
43
+ t *= R;
44
+ c *= R;
45
+ y *= 500 * d / R ** 3;
46
+ A *= d / R;
47
+ v *= d / R;
48
+ z *= R;
49
+ l = R * l | 0;
50
+ p *= 0.3 * (globalThis.zzfxV || 1);
51
+ for (h = e + m + r + t + c | 0; a < h; k[a++] = f * p)
52
+ ++J % (100 * F | 0) || (f = q ? 1 < q ? 2 < q ? 3 < q ? Z(g * g) : M.max(M.min(M.tan(g), 1), -1) : 1 - (2 * g / d % 2 + 2) % 2 : 1 - 4 * M.abs(M.round(g / d) - g / d) : Z(g), f = (l ? 1 - B + B * Z(d * a / l) : 1) * (f < 0 ? -1 : 1) * M.abs(f) ** D * (a < e ? a / e : a < e + m ? 1 - (a - e) / m * (1 - w) : a < e + m + r ? w : a < h - c ? (h - a - c) / t * w : 0), f = c ? f / 2 + (c > a ? 0 : (a < h - c ? 1 : (h - a) / c) * k[a - c | 0] / 2 / p) : f, N ? f = W = S * T + Q * (T = U) + P * (U = f) - Y * V - X * (V = W) : 0), x = (b += u += y) * M.cos(A * H++), g += x + x * E * Z(a ** 5), n && ++n > z && (b += v, C += v, n = 0), !l || ++I % l || (b = C, u = G, n = n || 1);
53
+ p = zzfxX.createBuffer(1, h, R);
54
+ p.getChannelData(0).set(k);
55
+ b = zzfxX.createBufferSource();
56
+ b.buffer = p;
57
+ b.connect(zzfxX.destination);
58
+ b.start();
59
+ };
60
+
61
+ // node_modules/litecanvas/src/palette.js
62
+ var colors = [
63
+ "#111",
64
+ "#6a7799",
65
+ "#aec2c2",
66
+ "#FFF1E8",
67
+ "#e83b3b",
68
+ "#fabc20",
69
+ "#155fd9",
70
+ "#3cbcfc",
71
+ "#327345",
72
+ "#63c64d",
73
+ "#6c2c1f",
74
+ "#ac7c00"
75
+ ];
76
+
77
+ // node_modules/litecanvas/src/index.js
78
+ globalThis.litecanvas = litecanvas;
79
+ function litecanvas(settings = {}) {
80
+ const root = globalThis, PI = Math.PI, TWO_PI = PI * 2, raf = requestAnimationFrame, _browserEventListeners = [], on = (elem, evt, callback) => {
81
+ elem.addEventListener(evt, callback, false);
82
+ _browserEventListeners.push(
83
+ () => elem.removeEventListener(evt, callback, false)
84
+ );
85
+ }, defaults = {
86
+ fps: 60,
87
+ fullscreen: true,
88
+ width: null,
89
+ height: null,
90
+ autoscale: true,
91
+ pixelart: false,
92
+ antialias: false,
93
+ canvas: null,
94
+ global: true,
95
+ loop: null,
96
+ pauseOnBlur: true,
97
+ tapEvents: true,
98
+ keyboardEvents: true,
99
+ animate: true
100
+ };
101
+ settings = Object.assign(defaults, settings);
102
+ let _initialized = false, _plugins = [], _canvas = settings.canvas || document.createElement("canvas"), _fullscreen = settings.fullscreen, _autoscale = settings.autoscale, _animated = settings.animate, _scale = 1, _ctx, _timeScale = 1, _lastFrame, _step, _stepMs, _accumulated = 0, _focused = true, _fontFamily = "sans-serif", _fontStyle = "", _fontSize = 32, _rng_seed = Date.now(), _global = settings.global, _events = {
103
+ init: null,
104
+ update: null,
105
+ draw: null,
106
+ resized: null,
107
+ tap: null,
108
+ untap: null,
109
+ tapping: null,
110
+ tapped: null
111
+ }, _helpers = {
112
+ settings: Object.assign({}, settings),
113
+ colors
114
+ };
115
+ const instance = {
116
+ /** @type {number} */
117
+ WIDTH: settings.width,
118
+ /** @type {number} */
119
+ HEIGHT: settings.height || settings.width,
120
+ /** @type {HTMLCanvasElement} */
121
+ CANVAS: null,
122
+ /** @type {number} */
123
+ ELAPSED: 0,
124
+ /** @type {number} */
125
+ CENTERX: 0,
126
+ /** @type {number} */
127
+ CENTERY: 0,
128
+ /** @type {number} */
129
+ MOUSEX: -1,
130
+ /** @type {number} */
131
+ MOUSEY: -1,
132
+ /** @type {number[]} */
133
+ DEFAULT_SFX: [0.5, , 1675, , 0.06, 0.2, 1, 1.8, , , 637, 0.06],
134
+ /** MATH API */
135
+ /**
136
+ * The value of the mathematical constant PI (π).
137
+ * Approximately 3.14159
138
+ *
139
+ * @type {number}
140
+ */
141
+ PI,
142
+ /**
143
+ * Twice the value of the mathematical constant PI (π).
144
+ * Approximately 6.28318
145
+ *
146
+ * Note: TWO_PI radians equals 360°, PI radians equals 180°,
147
+ * HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
148
+ *
149
+ * @type {number}
150
+ */
151
+ TWO_PI,
152
+ /**
153
+ * Half the value of the mathematical constant PI (π).
154
+ * Approximately 1.57079
155
+ *
156
+ * @type {number}
157
+ */
158
+ HALF_PI: PI * 0.5,
159
+ /**
160
+ * Calculates a linear (interpolation) value over t%.
161
+ *
162
+ * @param {number} start
163
+ * @param {number} end
164
+ * @param {number} t The progress in percentage, where 0 = 0% and 1 = 100%.
165
+ * @returns {number} The unterpolated value
166
+ * @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
167
+ */
168
+ lerp: (start, end, t) => start + t * (end - start),
169
+ /**
170
+ * Convert degrees to radians
171
+ *
172
+ * @param {number} degs
173
+ * @returns {number} the value in radians
174
+ */
175
+ deg2rad: (degs) => PI / 180 * degs,
176
+ /**
177
+ * Convert radians to degrees
178
+ *
179
+ * @param {number} rads
180
+ * @returns {number} the value in degrees
181
+ */
182
+ rad2deg: (rads) => 180 / PI * rads,
183
+ /**
184
+ * Constrains a number between `min` and `max`.
185
+ *
186
+ * @param {number} value
187
+ * @param {number} min
188
+ * @param {number} max
189
+ * @returns {number}
190
+ */
191
+ clamp: (value, min, max) => {
192
+ if (value < min) return min;
193
+ if (value > max) return max;
194
+ return value;
195
+ },
196
+ /**
197
+ * Wraps a number between `min` (inclusive) and `max` (exclusive).
198
+ *
199
+ * @param {number} value
200
+ * @param {number} min
201
+ * @param {number} max
202
+ * @returns {number}
203
+ */
204
+ wrap: (value, min, max) => value - (max - min) * Math.floor((value - min) / (max - min)),
205
+ /**
206
+ * Re-maps a number from one range to another.
207
+ *
208
+ * @param {number} value the value to be remapped.
209
+ * @param {number} min1 lower bound of the value's current range.
210
+ * @param {number} max1 upper bound of the value's current range.
211
+ * @param {number} min2 lower bound of the value's target range.
212
+ * @param {number} max2 upper bound of the value's target range.
213
+ * @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
214
+ * @returns {number} the remapped number
215
+ */
216
+ map(value, min1, max1, min2, max2, withinBounds) {
217
+ const result = (value - min1) / (max1 - min1) * (max2 - min2) + min2;
218
+ return withinBounds ? instance.clamp(result, min2, max2) : result;
219
+ },
220
+ /**
221
+ * Maps a number from one range to a value between 0 and 1.
222
+ * Identical to `map(value, min, max, 0, 1)`.
223
+ * Note: Numbers outside the range are not clamped to 0 and 1.
224
+ *
225
+ * @param {number} value
226
+ * @param {number} min
227
+ * @param {number} min
228
+ * @returns {number} the normalized number.
229
+ */
230
+ norm: (value, min, max) => instance.map(value, min, max, 0, 1),
231
+ /** RNG API */
232
+ /**
233
+ * Generates a pseudorandom float between min (inclusive) and max (exclusive)
234
+ * using the Linear Congruential Generator (LCG) algorithm.
235
+ *
236
+ * @param {number} [min=0.0]
237
+ * @param {number} [max=1.0]
238
+ * @returns {number} the random number
239
+ */
240
+ rand: (min = 0, max = 1) => {
241
+ const a = 1664525;
242
+ const c = 1013904223;
243
+ const m = 4294967296;
244
+ _rng_seed = (a * _rng_seed + c) % m;
245
+ return _rng_seed / m * (max - min) + min;
246
+ },
247
+ /**
248
+ * Generates a pseudorandom integer between min (inclusive) and max (inclusive)
249
+ *
250
+ * @param {number} [min=0]
251
+ * @param {number} [max=1]
252
+ * @returns {number} the random number
253
+ */
254
+ randi: (min = 0, max = 1) => Math.floor(instance.rand(min, max + 1)),
255
+ /**
256
+ * If a value is passed, initializes the random number generator with an explicit seed value.
257
+ * Otherwise, returns the current seed state.
258
+ *
259
+ * @param {number} value
260
+ * @returns {number} the seed state
261
+ */
262
+ seed: (value) => {
263
+ return null == value ? _rng_seed : _rng_seed = ~~value;
264
+ },
265
+ /** BASIC GRAPHICS API */
266
+ /**
267
+ * Clear the game screen
268
+ *
269
+ * @param {number|null} color The background color (from 0 to 7) or null (for transparent)
270
+ */
271
+ cls(color) {
272
+ if (null == color) {
273
+ _ctx.clearRect(0, 0, instance.WIDTH, instance.HEIGHT);
274
+ } else {
275
+ instance.rectfill(0, 0, instance.WIDTH, instance.HEIGHT, color);
276
+ }
277
+ },
278
+ /**
279
+ * Draw a rectangle outline
280
+ *
281
+ * @param {number} x
282
+ * @param {number} y
283
+ * @param {number} width
284
+ * @param {number} height
285
+ * @param {number} [color=0] the color index (generally from 0 to 7)
286
+ * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
287
+ */
288
+ rect(x, y, width, height, color = 0, radii = null) {
289
+ _ctx.beginPath();
290
+ _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
291
+ instance.stroke(color);
292
+ },
293
+ /**
294
+ * Draw a color-filled rectangle
295
+ *
296
+ * @param {number} x
297
+ * @param {number} y
298
+ * @param {number} width
299
+ * @param {number} height
300
+ * @param {number} [color=0] the color index (generally from 0 to 7)
301
+ * @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
302
+ */
303
+ rectfill(x, y, width, height, color = 0, radii = null) {
304
+ _ctx.beginPath();
305
+ _ctx[radii ? "roundRect" : "rect"](~~x, ~~y, width, height, radii);
306
+ instance.fill(color);
307
+ },
308
+ /**
309
+ * Draw a circle outline
310
+ *
311
+ * @param {number} x
312
+ * @param {number} y
313
+ * @param {number} radius
314
+ * @param {number} [color=0] the color index (generally from 0 to 7)
315
+ */
316
+ circ(x, y, radius, color) {
317
+ _ctx.beginPath();
318
+ _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
319
+ instance.stroke(color);
320
+ },
321
+ /**
322
+ * Draw a color-filled circle
323
+ *
324
+ * @param {number} x
325
+ * @param {number} y
326
+ * @param {number} radius
327
+ * @param {number} [color=0] the color index (generally from 0 to 7)
328
+ */
329
+ circfill(x, y, radius, color) {
330
+ _ctx.beginPath();
331
+ _ctx.arc(~~x, ~~y, radius, 0, TWO_PI);
332
+ instance.fill(color);
333
+ },
334
+ /**
335
+ * Draw a line
336
+ *
337
+ * @param {number} x1
338
+ * @param {number} y1
339
+ * @param {number} x2
340
+ * @param {number} y2
341
+ * @param {number} [color=0] the color index (generally from 0 to 7)
342
+ */
343
+ line(x1, y1, x2, y2, color) {
344
+ _ctx.beginPath();
345
+ _ctx.moveTo(~~x1, ~~y1);
346
+ _ctx.lineTo(~~x2, ~~y2);
347
+ instance.stroke(color);
348
+ },
349
+ /**
350
+ * Sets the thickness of lines
351
+ *
352
+ * @param {number} value
353
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
354
+ */
355
+ linewidth(value) {
356
+ _ctx.lineWidth = value;
357
+ },
358
+ /**
359
+ * Sets the line dash pattern used when drawing lines
360
+ *
361
+ * @param {number[]} segments the line dash pattern
362
+ * @param {number} [offset=0] the line dash offset, or "phase".
363
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
364
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
365
+ */
366
+ linedash(segments, offset = 0) {
367
+ _ctx.setLineDash(segments);
368
+ _ctx.lineDashOffset = offset;
369
+ },
370
+ /** TEXT RENDERING API */
371
+ /**
372
+ * Draw text
373
+ *
374
+ * @param {number} x
375
+ * @param {number} y
376
+ * @param {string} text the text message
377
+ * @param {number} [color=3] the color index (generally from 0 to 7)
378
+ */
379
+ text(x, y, text, color = 3) {
380
+ _ctx.font = `${_fontStyle} ${_fontSize}px ${_fontFamily}`;
381
+ _ctx.fillStyle = instance.getcolor(color);
382
+ _ctx.fillText(text, ~~x, ~~y);
383
+ },
384
+ /**
385
+ * Set the font family
386
+ *
387
+ * @param {string} fontFamily
388
+ */
389
+ textfont(fontFamily) {
390
+ _fontFamily = fontFamily;
391
+ },
392
+ /**
393
+ * Set the font size
394
+ *
395
+ * @param {string} size
396
+ */
397
+ textsize(size) {
398
+ _fontSize = size;
399
+ },
400
+ /**
401
+ * Sets whether a font should be styled with a "normal", "italic", or "bold".
402
+ *
403
+ * @param {string} style
404
+ */
405
+ textstyle(style) {
406
+ _fontStyle = style || "";
407
+ },
408
+ /**
409
+ * Sets the alignment used when drawing texts
410
+ *
411
+ * @param {string} align the horizontal alignment. Possible values: "left", "right", "center", "start" or "end"
412
+ * @param {string} baseline the vertical alignment. Possible values: "top", "bottom", "middle", "hanging" or "ideographic"
413
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
414
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
415
+ */
416
+ textalign(align, baseline) {
417
+ if (align) _ctx.textAlign = align;
418
+ if (baseline) _ctx.textBaseline = baseline;
419
+ },
420
+ /**
421
+ * Returns a TextMetrics object that contains information about the measured text (such as its width, for example)
422
+ *
423
+ * @param {string} text
424
+ * @param {number} [size]
425
+ * @returns {TextMetrics}
426
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
427
+ */
428
+ textmetrics(text, size = _fontSize) {
429
+ _ctx.font = `${_fontStyle} ${size}px ${_fontFamily}`;
430
+ const metrics = _ctx.measureText(text);
431
+ metrics.height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
432
+ return metrics;
433
+ },
434
+ /** IMAGE GRAPHICS API */
435
+ /**
436
+ * Draw an image
437
+ *
438
+ * @param {number} x
439
+ * @param {number} y
440
+ * @param {OffscreenCanvas|HTMLImageElement|HTMLCanvasElement} image
441
+ */
442
+ image(x, y, image) {
443
+ _ctx.drawImage(image, ~~x, ~~y);
444
+ },
445
+ /**
446
+ * Creates a offscreen canvas to draw on it
447
+ *
448
+ * @param {number} width
449
+ * @param {number} height
450
+ * @param {string[]|drawCallback} draw
451
+ * @param {object} [options]
452
+ * @param {number} [options.scale=1]
453
+ * @param {OffscreenCanvas | HTMLCanvasElement} [options.canvas]
454
+ * @returns {OffscreenCanvas}
455
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
456
+ */
457
+ paint(width, height, draw, options = {}) {
458
+ const canvas = options.canvas || new OffscreenCanvas(1, 1), scale = options.scale || 1, contextOriginal = _ctx;
459
+ canvas.width = width * scale;
460
+ canvas.height = height * scale;
461
+ _ctx = canvas.getContext("2d");
462
+ _ctx.scale(scale, scale);
463
+ if (draw.push) {
464
+ let x = 0, y = 0;
465
+ _ctx.imageSmoothingEnabled = false;
466
+ for (const str of draw) {
467
+ for (const color of str) {
468
+ if (" " !== color && "." !== color) {
469
+ instance.rectfill(x, y, 1, 1, parseInt(color, 16));
470
+ }
471
+ x++;
472
+ }
473
+ y++;
474
+ x = 0;
475
+ }
476
+ } else {
477
+ draw(_ctx);
478
+ }
479
+ _ctx = contextOriginal;
480
+ return canvas;
481
+ },
482
+ /** ADVANCED GRAPHICS API */
483
+ /**
484
+ * Get or set the canvas context 2D
485
+ *
486
+ * @param {CanvasRenderingContext2D} [context]
487
+ * @returns {CanvasRenderingContext2D}
488
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
489
+ */
490
+ ctx(context) {
491
+ if (context) {
492
+ _ctx = context;
493
+ }
494
+ return _ctx;
495
+ },
496
+ /**
497
+ * saves the current drawing style settings and transformations
498
+ *
499
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
500
+ */
501
+ push: () => _ctx.save(),
502
+ /**
503
+ * restores the drawing style settings and transformations
504
+ *
505
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
506
+ */
507
+ pop: () => _ctx.restore(),
508
+ /**
509
+ * Adds a translation to the transformation matrix.
510
+ *
511
+ * @param {number} x
512
+ * @param {number} y
513
+ */
514
+ translate: (x, y) => _ctx.translate(~~x, ~~y),
515
+ /**
516
+ * Adds a scaling transformation to the canvas units horizontally and/or vertically.
517
+ *
518
+ * @param {number} x
519
+ * @param {number} [y]
520
+ */
521
+ scale: (x, y) => _ctx.scale(x, y || x),
522
+ /**
523
+ * Adds a rotation to the transformation matrix.
524
+ *
525
+ * @param {number} radians
526
+ */
527
+ rotate: (radians) => _ctx.rotate(radians),
528
+ /**
529
+ * @param {number} a
530
+ * @param {number} b
531
+ * @param {number} c
532
+ * @param {number} d
533
+ * @param {number} e
534
+ * @param {number} f
535
+ * @param {boolean} [resetFirst=true] `false` to use _ctx.transform(); by default use _ctx.setTransform()
536
+ *
537
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform
538
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
539
+ */
540
+ transform: (a, b, c, d, e, f, resetFirst = true) => _ctx[resetFirst ? "setTransform" : "transform"](a, b, c, d, e, f),
541
+ /**
542
+ * Sets the alpha (opacity) value to apply when drawing new shapes and images
543
+ *
544
+ * @param {number} alpha float from 0 to 1 (e.g: 0.5 = 50% transparent)
545
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
546
+ */
547
+ alpha(value) {
548
+ _ctx.globalAlpha = instance.clamp(value, 0, 1);
549
+ },
550
+ /**
551
+ * Returns a newly instantiated Path2D object, optionally with another
552
+ * path as an argument (creates a copy), or optionally with a string
553
+ * consisting of SVG path data.
554
+ *
555
+ * @param {Path2D|string} [arg]
556
+ * @returns Path2D
557
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
558
+ */
559
+ path: (arg) => new Path2D(arg),
560
+ /**
561
+ * Fills the current or given path with a given color.
562
+ *
563
+ * @param {number} [color=0]
564
+ * @param {Path2D} [path]
565
+ */
566
+ fill(color, path) {
567
+ _ctx.fillStyle = instance.getcolor(color);
568
+ if (path) {
569
+ _ctx.fill(path);
570
+ } else {
571
+ _ctx.fill();
572
+ }
573
+ },
574
+ /**
575
+ * Outlines the current or given path with a given color.
576
+ *
577
+ * @param {number} [color=0]
578
+ * @param {Path2D} [path]
579
+ */
580
+ stroke(color, path) {
581
+ _ctx.strokeStyle = instance.getcolor(color);
582
+ if (path) {
583
+ _ctx.stroke(path);
584
+ } else {
585
+ _ctx.stroke();
586
+ }
587
+ },
588
+ /**
589
+ * Turn given path into a clipping region.
590
+ *
591
+ * @param {Path2D} path
592
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
593
+ */
594
+ clip(path) {
595
+ _ctx.clip(path);
596
+ },
597
+ /** SOUND API */
598
+ /**
599
+ * Play a sound effects using ZzFX library.
600
+ * If the first argument is omitted, plays an default sound.
601
+ *
602
+ * @param {number[]} [zzfxParams] a ZzFX array of params
603
+ * @param {number} [pitchSlide] a value to increment/decrement the pitch
604
+ * @param {number} [volumeFactor] the volume factor
605
+ * @returns {number[] | boolean} The sound that was played or `false`
606
+ *
607
+ * @see https://github.com/KilledByAPixel/ZzFX
608
+ */
609
+ sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
610
+ if (root.zzfxV <= 0 || navigator.userActivation && !navigator.userActivation.hasBeenActive) {
611
+ return false;
612
+ }
613
+ zzfxParams = zzfxParams || instance.DEFAULT_SFX;
614
+ if (pitchSlide > 0 || volumeFactor !== 1) {
615
+ zzfxParams = zzfxParams.slice();
616
+ zzfxParams[0] = volumeFactor * (zzfxParams[0] || 1);
617
+ zzfxParams[10] = ~~zzfxParams[10] + pitchSlide;
618
+ }
619
+ zzfx.apply(0, zzfxParams);
620
+ return zzfxParams;
621
+ },
622
+ /**
623
+ * Set the ZzFX's global volume factor.
624
+ * Note: use 0 to mute all sound effects.
625
+ *
626
+ * @param {number} value
627
+ */
628
+ volume(value) {
629
+ root.zzfxV = +value;
630
+ },
631
+ /** UTILS API */
632
+ /**
633
+ * Check a collision between two rectangles
634
+ *
635
+ * @param {number} x1 first rectangle position X
636
+ * @param {number} y1 first rectangle position Y
637
+ * @param {number} w1 first rectangle width
638
+ * @param {number} h1 first rectangle height
639
+ * @param {number} x2 second rectangle position X
640
+ * @param {number} y2 second rectangle position Y
641
+ * @param {number} w2 second rectangle width
642
+ * @param {number} h2 second rectangle height
643
+ * @returns {boolean}
644
+ */
645
+ colrect: (x1, y1, w1, h1, x2, y2, w2, h2) => x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2,
646
+ /**
647
+ * Check a collision between two circles
648
+ *
649
+ * @param {number} x1 first circle position X
650
+ * @param {number} y1 first circle position Y
651
+ * @param {number} r1 first circle position radius
652
+ * @param {number} x2 second circle position X
653
+ * @param {number} y2 second circle position Y
654
+ * @param {number} r2 second circle position radius
655
+ * @returns {boolean}
656
+ */
657
+ colcirc: (x1, y1, r1, x2, y2, r2) => (x2 - x1) ** 2 + (y2 - y1) ** 2 <= (r1 + r2) ** 2,
658
+ /** PLUGINS API */
659
+ /**
660
+ * Prepares a plugin to be loaded
661
+ *
662
+ * @param {pluginCallback} callback
663
+ */
664
+ use(callback, config = {}) {
665
+ _initialized ? loadPlugin(callback, config) : _plugins.push([callback, config]);
666
+ },
667
+ /**
668
+ * Add a game event listener
669
+ *
670
+ * @param {string} eventName the event type name
671
+ * @param {Function} callback the function that is called when the event occurs
672
+ * @returns {Function} a function to remove the listener
673
+ */
674
+ listen(eventName, callback) {
675
+ _events[eventName] = _events[eventName] || /* @__PURE__ */ new Set();
676
+ _events[eventName].add(callback);
677
+ return () => _events[eventName].delete(callback);
678
+ },
679
+ /**
680
+ * Call all listeners attached to a game event
681
+ *
682
+ * @param {string} eventName The event type name
683
+ * @param {*} [arg1] any data to be passed over the listeners
684
+ * @param {*} [arg2] any data to be passed over the listeners
685
+ * @param {*} [arg3] any data to be passed over the listeners
686
+ * @param {*} [arg4] any data to be passed over the listeners
687
+ */
688
+ emit(eventName, arg1, arg2, arg3, arg4) {
689
+ triggerEvent("before:" + eventName, arg1, arg2, arg3, arg4);
690
+ triggerEvent(eventName, arg1, arg2, arg3, arg4);
691
+ triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
692
+ },
693
+ /**
694
+ * Get a color by index
695
+ *
696
+ * @param {number} [index=0] The color number
697
+ * @returns {string} the color code
698
+ */
699
+ getcolor: (index) => colors[~~index % colors.length],
700
+ /**
701
+ * Create or update a instance variable
702
+ *
703
+ * @param {string} key
704
+ * @param {*} value
705
+ */
706
+ setvar(key, value) {
707
+ instance[key] = value;
708
+ if (_global) {
709
+ root[key] = value;
710
+ }
711
+ },
712
+ /**
713
+ * Resizes the game canvas and emit the "resized" event
714
+ *
715
+ * @param {number} width
716
+ * @param {number} height
717
+ */
718
+ resize(width, height) {
719
+ instance.setvar("WIDTH", _canvas.width = width);
720
+ instance.setvar("HEIGHT", _canvas.height = height || width);
721
+ pageResized();
722
+ },
723
+ /**
724
+ * The scale of the game's delta time (dt).
725
+ * Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
726
+ * A value of 0 freezes time and is effectively equivalent to pausing.
727
+ *
728
+ * @param {number} value
729
+ */
730
+ timescale(value) {
731
+ _timeScale = value;
732
+ },
733
+ /**
734
+ * Set the target FPS at runtime.
735
+ *
736
+ * @param {number} fps
737
+ */
738
+ setfps(fps) {
739
+ _step = 1 / fps;
740
+ _stepMs = _step * 1e3;
741
+ _accumulated = 0;
742
+ },
743
+ /**
744
+ * Stops the litecanvas instance and remove all event listeners.
745
+ */
746
+ quit() {
747
+ instance.emit("quit");
748
+ for (const removeListener of _browserEventListeners) {
749
+ removeListener();
750
+ }
751
+ _focused = _events = false;
752
+ if (_global) {
753
+ for (const key in instance) {
754
+ delete root[key];
755
+ }
756
+ delete root.__litecanvas;
757
+ }
758
+ }
759
+ };
760
+ for (const k of [
761
+ "sin",
762
+ "cos",
763
+ "atan2",
764
+ "hypot",
765
+ "tan",
766
+ "abs",
767
+ "ceil",
768
+ "round",
769
+ "floor",
770
+ "trunc",
771
+ "min",
772
+ "max",
773
+ "pow",
774
+ "sqrt",
775
+ "sign",
776
+ "exp"
777
+ ]) {
778
+ instance[k] = Math[k];
779
+ }
780
+ function init() {
781
+ _initialized = true;
782
+ const source = settings.loop ? settings.loop : root;
783
+ for (const event in _events) {
784
+ if (source[event]) instance.listen(event, source[event]);
785
+ }
786
+ for (const [callback, config] of _plugins) {
787
+ loadPlugin(callback, config);
788
+ }
789
+ if (_fullscreen || _autoscale) {
790
+ on(root, "resize", pageResized);
791
+ }
792
+ pageResized();
793
+ if (settings.tapEvents) {
794
+ const _getXY = (pageX, pageY) => [
795
+ (pageX - _canvas.offsetLeft) / _scale,
796
+ (pageY - _canvas.offsetTop) / _scale
797
+ ], _taps = /* @__PURE__ */ new Map(), _registerTap = (id, x, y) => {
798
+ const tap = {
799
+ x,
800
+ y,
801
+ startX: x,
802
+ startY: y,
803
+ // timestamp
804
+ ts: performance.now()
805
+ };
806
+ _taps.set(id, tap);
807
+ return tap;
808
+ }, _updateTap = (id, x, y) => {
809
+ const tap = _taps.get(id) || _registerTap(id);
810
+ tap.x = x;
811
+ tap.y = y;
812
+ }, _checkTapped = (tap) => tap && performance.now() - tap.ts <= 200;
813
+ let _pressingMouse = false;
814
+ on(_canvas, "mousedown", (ev) => {
815
+ ev.preventDefault();
816
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
817
+ instance.emit("tap", x, y, 0);
818
+ _registerTap(0, x, y);
819
+ _pressingMouse = true;
820
+ });
821
+ on(_canvas, "mousemove", (ev) => {
822
+ ev.preventDefault();
823
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
824
+ instance.setvar("MOUSEX", x);
825
+ instance.setvar("MOUSEY", y);
826
+ if (!_pressingMouse) return;
827
+ instance.emit("tapping", x, y, 0);
828
+ _updateTap(0, x, y);
829
+ });
830
+ on(_canvas, "mouseup", (ev) => {
831
+ ev.preventDefault();
832
+ const tap = _taps.get(0);
833
+ const [x, y] = _getXY(ev.pageX, ev.pageY);
834
+ if (_checkTapped(tap)) {
835
+ instance.emit("tapped", tap.startX, tap.startY, 0);
836
+ }
837
+ instance.emit("untap", x, y, 0);
838
+ _taps.delete(0);
839
+ _pressingMouse = false;
840
+ });
841
+ on(_canvas, "touchstart", (ev) => {
842
+ ev.preventDefault();
843
+ const touches = ev.changedTouches;
844
+ for (const touch of touches) {
845
+ const [x, y] = _getXY(touch.pageX, touch.pageY);
846
+ instance.emit("tap", x, y, touch.identifier + 1);
847
+ _registerTap(touch.identifier + 1, x, y);
848
+ }
849
+ });
850
+ on(_canvas, "touchmove", (ev) => {
851
+ ev.preventDefault();
852
+ const touches = ev.changedTouches;
853
+ for (const touch of touches) {
854
+ const [x, y] = _getXY(touch.pageX, touch.pageY);
855
+ instance.emit("tapping", x, y, touch.identifier + 1);
856
+ _updateTap(touch.identifier + 1, x, y);
857
+ }
858
+ });
859
+ const _touchEndHandler = (ev) => {
860
+ ev.preventDefault();
861
+ const existing = [];
862
+ if (ev.targetTouches.length > 0) {
863
+ for (const touch of ev.targetTouches) {
864
+ existing.push(touch.identifier + 1);
865
+ }
866
+ }
867
+ for (const [id, tap] of _taps) {
868
+ if (existing.includes(id)) continue;
869
+ if (_checkTapped(tap)) {
870
+ instance.emit("tapped", tap.startX, tap.startY, id);
871
+ }
872
+ instance.emit("untap", tap.x, tap.y, id);
873
+ _taps.delete(id);
874
+ }
875
+ };
876
+ on(_canvas, "touchend", _touchEndHandler);
877
+ on(_canvas, "touchcancel", _touchEndHandler);
878
+ on(root, "blur", () => {
879
+ _pressingMouse = false;
880
+ for (const [id, tap] of _taps) {
881
+ instance.emit("untap", tap.x, tap.y, id);
882
+ _taps.delete(id);
883
+ }
884
+ });
885
+ }
886
+ if (settings.keyboardEvents) {
887
+ const _keys = /* @__PURE__ */ new Set();
888
+ const iskeydown = (key) => "any" === key ? _keys.size > 0 : _keys.has(key.toLowerCase());
889
+ instance.setvar("iskeydown", iskeydown);
890
+ on(root, "keydown", (event) => {
891
+ _keys.add(event.key.toLowerCase());
892
+ });
893
+ on(root, "keyup", (event) => {
894
+ _keys.delete(event.key.toLowerCase());
895
+ });
896
+ on(root, "blur", () => _keys.clear());
897
+ }
898
+ if (settings.pauseOnBlur) {
899
+ on(root, "blur", () => {
900
+ _focused = false;
901
+ });
902
+ on(root, "focus", () => {
903
+ _focused = true;
904
+ raf(drawFrame);
905
+ });
906
+ }
907
+ instance.setfps(settings.fps);
908
+ instance.emit("init", instance);
909
+ _lastFrame = performance.now();
910
+ raf(drawFrame);
911
+ }
912
+ function drawFrame(now) {
913
+ let shouldRender = !_animated, delta = now - _lastFrame;
914
+ _accumulated += delta > 100 ? _stepMs : delta;
915
+ _lastFrame = now;
916
+ while (_accumulated >= _stepMs) {
917
+ instance.emit("update", _step * _timeScale);
918
+ instance.setvar("ELAPSED", instance.ELAPSED + _step * _timeScale);
919
+ _accumulated -= _stepMs;
920
+ shouldRender = true;
921
+ }
922
+ if (shouldRender) {
923
+ instance.textalign("start", "top");
924
+ instance.emit("draw");
925
+ }
926
+ if (_focused && _animated) {
927
+ raf(drawFrame);
928
+ }
929
+ }
930
+ function setupCanvas() {
931
+ _canvas = "string" === typeof _canvas ? document.querySelector(_canvas) : _canvas;
932
+ instance.setvar("CANVAS", _canvas);
933
+ _ctx = _canvas.getContext("2d");
934
+ on(_canvas, "click", () => root.focus());
935
+ if (instance.WIDTH > 0) {
936
+ _fullscreen = false;
937
+ }
938
+ _canvas.style = "";
939
+ _canvas.width = instance.WIDTH;
940
+ _canvas.height = instance.HEIGHT || instance.WIDTH;
941
+ if (!_canvas.parentNode) document.body.appendChild(_canvas);
942
+ }
943
+ function pageResized() {
944
+ const pageWidth = root.innerWidth, pageHeight = root.innerHeight, styles = _canvas.style;
945
+ styles.display = "block";
946
+ if (_fullscreen) {
947
+ styles.position = "absolute";
948
+ styles.inset = 0;
949
+ instance.setvar("WIDTH", _canvas.width = pageWidth);
950
+ instance.setvar("HEIGHT", _canvas.height = pageHeight);
951
+ } else if (_autoscale) {
952
+ styles.margin = "auto";
953
+ _scale = Math.min(
954
+ pageWidth / instance.WIDTH,
955
+ pageHeight / instance.HEIGHT
956
+ );
957
+ _scale = (settings.pixelart ? ~~_scale : _scale) || 1;
958
+ styles.width = instance.WIDTH * _scale + "px";
959
+ styles.height = instance.HEIGHT * _scale + "px";
960
+ }
961
+ instance.setvar("CENTERX", instance.WIDTH / 2);
962
+ instance.setvar("CENTERY", instance.HEIGHT / 2);
963
+ if (!settings.antialias || settings.pixelart) {
964
+ _ctx.imageSmoothingEnabled = false;
965
+ _canvas.style.imageRendering = "pixelated";
966
+ }
967
+ instance.emit("resized", _scale);
968
+ if (!_animated) {
969
+ raf(drawFrame);
970
+ }
971
+ }
972
+ function triggerEvent(eventName, arg1, arg2, arg3, arg4) {
973
+ if (!_events[eventName]) return;
974
+ for (const callback of _events[eventName]) {
975
+ callback(arg1, arg2, arg3, arg4);
976
+ }
977
+ }
978
+ function loadPlugin(callback, config) {
979
+ const pluginData = callback(instance, _helpers, config);
980
+ if ("object" === typeof pluginData) {
981
+ for (const key of Object.keys(pluginData)) {
982
+ instance.setvar(key, pluginData[key]);
983
+ }
984
+ }
985
+ }
986
+ if (_global) {
987
+ if (root.__litecanvas) {
988
+ throw "global litecanvas already instantiated";
989
+ }
990
+ Object.assign(root, instance);
991
+ root.__litecanvas = instance;
992
+ }
993
+ setupCanvas();
994
+ if ("loading" === document.readyState) {
995
+ on(root, "DOMContentLoaded", () => raf(init));
996
+ } else {
997
+ raf(init);
998
+ }
999
+ return instance;
1000
+ }
1001
+
1002
+ // src/tween/index.js
35
1003
  var HALF_PI = Math.PI / 2;
36
1004
  var tween = (object, prop, toValue, duration = 1, easing = LINEAR) => {
37
1005
  return new TweenController(object, prop, toValue, duration, easing);