@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/actor.js +980 -14
- package/dist/actor.min.js +1 -1
- package/dist/all.js +981 -15
- package/dist/all.min.js +2 -2
- package/dist/noise.js +968 -0
- package/dist/noise.min.js +1 -1
- package/dist/tween.js +968 -0
- package/dist/tween.min.js +1 -1
- package/dist/vector.js +3 -3
- package/package.json +1 -1
- package/src/math/advance.js +2 -2
- package/src/tween/README.md +12 -0
- package/src/vector/index.js +6 -6
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);
|