litecanvas 0.103.4 → 0.103.6
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 +7 -3
- package/dist/dist.dev.js +652 -807
- package/dist/dist.js +261 -636
- package/dist/dist.min.js +1 -1
- package/package.json +3 -3
- package/src/dev.js +1 -1
- package/src/index.js +158 -141
- package/src/version.js +1 -1
package/dist/dist.dev.js
CHANGED
|
@@ -1,121 +1,213 @@
|
|
|
1
1
|
(() => {
|
|
2
|
-
// src/zzfx.js
|
|
3
2
|
var setupZzFX = (global) => {
|
|
4
3
|
const zzfxX = new AudioContext();
|
|
5
4
|
global.zzfxV = 1;
|
|
6
|
-
return (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
return (
|
|
6
|
+
i = 1,
|
|
7
|
+
d = 0.05,
|
|
8
|
+
z = 220,
|
|
9
|
+
e = 0,
|
|
10
|
+
P = 0,
|
|
11
|
+
S = 0.1,
|
|
12
|
+
I = 0,
|
|
13
|
+
c = 1,
|
|
14
|
+
T = 0,
|
|
15
|
+
H = 0,
|
|
16
|
+
V = 0,
|
|
17
|
+
J = 0,
|
|
18
|
+
h = 0,
|
|
19
|
+
j = 0,
|
|
20
|
+
K = 0,
|
|
21
|
+
E = 0,
|
|
22
|
+
r = 0,
|
|
23
|
+
B = 1,
|
|
24
|
+
X = 0,
|
|
25
|
+
L = 0,
|
|
26
|
+
D = 0,
|
|
27
|
+
) => {
|
|
28
|
+
let n = Math,
|
|
29
|
+
t = 2 * n.PI,
|
|
30
|
+
a = 44100,
|
|
31
|
+
F = (T *= (500 * t) / a / a),
|
|
32
|
+
O = (z *= ((1 - d + 2 * d * n.random((d = []))) * t) / a),
|
|
33
|
+
x = 0,
|
|
34
|
+
_ = 0,
|
|
35
|
+
f = 0,
|
|
36
|
+
g = 1,
|
|
37
|
+
$ = 0,
|
|
38
|
+
l = 0,
|
|
39
|
+
o = 0,
|
|
40
|
+
s = D < 0 ? -1 : 1,
|
|
41
|
+
u = (t * s * D * 2) / a,
|
|
42
|
+
G = n.cos(u),
|
|
43
|
+
C = n.sin,
|
|
44
|
+
Q = C(u) / 4,
|
|
45
|
+
M = 1 + Q,
|
|
46
|
+
m = (-2 * G) / M,
|
|
47
|
+
y = (1 - Q) / M,
|
|
48
|
+
R = (1 + s * G) / 2 / M,
|
|
49
|
+
A = -(s + G) / M,
|
|
50
|
+
v = R,
|
|
51
|
+
U = 0,
|
|
52
|
+
W = 0,
|
|
53
|
+
Y = 0,
|
|
54
|
+
Z = 0;
|
|
55
|
+
for (
|
|
56
|
+
e = a * e + 9,
|
|
57
|
+
X *= a,
|
|
58
|
+
P *= a,
|
|
59
|
+
S *= a,
|
|
60
|
+
r *= a,
|
|
61
|
+
H *= (500 * t) / a ** 3,
|
|
62
|
+
K *= t / a,
|
|
63
|
+
V *= t / a,
|
|
64
|
+
J *= a,
|
|
65
|
+
h = (a * h) | 0,
|
|
66
|
+
i *= 0.3 * global.zzfxV,
|
|
67
|
+
s = (e + X + P + S + r) | 0;
|
|
68
|
+
f < s;
|
|
69
|
+
d[f++] = o * i
|
|
70
|
+
)
|
|
71
|
+
(++l % ((100 * E) | 0) ||
|
|
72
|
+
((o = I
|
|
73
|
+
? 1 < I
|
|
74
|
+
? 2 < I
|
|
75
|
+
? 3 < I
|
|
76
|
+
? C(x * x)
|
|
77
|
+
: n.max(n.min(n.tan(x), 1), -1)
|
|
78
|
+
: 1 - (((((2 * x) / t) % 2) + 2) % 2)
|
|
79
|
+
: 1 - 4 * n.abs(n.round(x / t) - x / t)
|
|
80
|
+
: C(x)),
|
|
81
|
+
(o =
|
|
82
|
+
(h ? 1 - L + L * C((t * f) / h) : 1) *
|
|
83
|
+
(o < 0 ? -1 : 1) *
|
|
84
|
+
n.abs(o) ** c *
|
|
85
|
+
(f < e
|
|
86
|
+
? f / e
|
|
87
|
+
: f < e + X
|
|
88
|
+
? 1 - ((f - e) / X) * (1 - B)
|
|
89
|
+
: f < e + X + P
|
|
90
|
+
? B
|
|
91
|
+
: f < s - r
|
|
92
|
+
? ((s - f - r) / S) * B
|
|
93
|
+
: 0)),
|
|
94
|
+
(o = r
|
|
95
|
+
? o / 2 +
|
|
96
|
+
(r > f
|
|
97
|
+
? 0
|
|
98
|
+
: ((f < s - r ? 1 : (s - f) / r) * d[(f - r) | 0]) / 2 / i)
|
|
99
|
+
: o),
|
|
100
|
+
D &&
|
|
101
|
+
(o = Z = v * U + A * (U = W) + R * (W = o) - y * Y - m * (Y = Z))),
|
|
102
|
+
(u = (z += T += H) * n.cos(K * _++)),
|
|
103
|
+
(x += u + u * j * C(f ** 5)),
|
|
104
|
+
g && ++g > J && ((z += V), (O += V), (g = 0)),
|
|
105
|
+
!h || ++$ % h || ((z = O), (T = F), (g = g || 1)));
|
|
106
|
+
((i = zzfxX.createBuffer(1, s, a)),
|
|
107
|
+
i.getChannelData(0).set(d),
|
|
108
|
+
(z = zzfxX.createBufferSource()),
|
|
109
|
+
(z.buffer = i),
|
|
110
|
+
z.connect(zzfxX.destination),
|
|
111
|
+
z.start());
|
|
10
112
|
};
|
|
11
113
|
};
|
|
12
|
-
|
|
13
|
-
// src/palette.js
|
|
14
114
|
var defaultPalette = ["#211e20", "#555568", "#a0a08b", "#e9efec"];
|
|
15
|
-
|
|
16
|
-
// src/dev.js
|
|
17
115
|
var assert = (condition, message = "Assertion failed") => {
|
|
18
|
-
if (!condition) throw new Error(message);
|
|
116
|
+
if (!condition) throw new Error("[litecanvas] " + message);
|
|
19
117
|
};
|
|
20
|
-
|
|
21
|
-
// src/version.js
|
|
22
|
-
var version = "0.103.4";
|
|
23
|
-
|
|
24
|
-
// src/index.js
|
|
118
|
+
var version = "0.103.6";
|
|
25
119
|
function litecanvas(settings = {}) {
|
|
26
|
-
const root = window,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
120
|
+
const root = window,
|
|
121
|
+
math = Math,
|
|
122
|
+
perf = performance,
|
|
123
|
+
TWO_PI = math.PI * 2,
|
|
124
|
+
loggerPrefix = "[Litecanvas] ",
|
|
125
|
+
raf = requestAnimationFrame,
|
|
126
|
+
_browserEventListeners = [],
|
|
127
|
+
on = (elem, evt, callback) => {
|
|
128
|
+
elem.addEventListener(evt, callback, false);
|
|
129
|
+
_browserEventListeners.push(() =>
|
|
130
|
+
elem.removeEventListener(evt, callback, false),
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
lowerCase = (str) => str.toLowerCase(),
|
|
134
|
+
preventDefault = (ev) => ev.preventDefault(),
|
|
135
|
+
beginPath = (c) => c.beginPath(),
|
|
136
|
+
isNumber = Number.isFinite,
|
|
137
|
+
zzfx = setupZzFX(root),
|
|
138
|
+
defaults = {
|
|
139
|
+
width: null,
|
|
140
|
+
height: null,
|
|
141
|
+
autoscale: true,
|
|
142
|
+
canvas: null,
|
|
143
|
+
global: true,
|
|
144
|
+
loop: null,
|
|
145
|
+
tapEvents: true,
|
|
146
|
+
keyboardEvents: true,
|
|
147
|
+
};
|
|
39
148
|
settings = Object.assign(defaults, settings);
|
|
40
|
-
let _initialized = false,
|
|
149
|
+
let _initialized = false,
|
|
150
|
+
_paused = true,
|
|
151
|
+
_canvas,
|
|
152
|
+
_canvasScale = 1,
|
|
153
|
+
_ctx,
|
|
154
|
+
_outline_fix = 0.5,
|
|
155
|
+
_timeScale = 1,
|
|
156
|
+
_lastFrameTime,
|
|
157
|
+
_fpsInterval = 1e3 / 60,
|
|
158
|
+
_accumulated,
|
|
159
|
+
_rafid,
|
|
160
|
+
_defaultTextColor = 3,
|
|
161
|
+
_fontFamily = "sans-serif",
|
|
162
|
+
_fontSize = 20,
|
|
163
|
+
_fontLineHeight = 1.2,
|
|
164
|
+
_rngSeed = Date.now(),
|
|
165
|
+
_colorPalette = defaultPalette,
|
|
166
|
+
_colorPaletteState = [],
|
|
167
|
+
_defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
|
|
168
|
+
_coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized",
|
|
169
|
+
_mathFunctions =
|
|
170
|
+
"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp",
|
|
171
|
+
_eventListeners = {};
|
|
41
172
|
const instance = {
|
|
42
|
-
/** @type {number} */
|
|
43
173
|
W: 0,
|
|
44
|
-
/** @type {number} */
|
|
45
174
|
H: 0,
|
|
46
|
-
/** @type {number} */
|
|
47
175
|
T: 0,
|
|
48
|
-
/** @type {number} */
|
|
49
176
|
MX: -1,
|
|
50
|
-
/** @type {number} */
|
|
51
177
|
MY: -1,
|
|
52
|
-
/** MATH API */
|
|
53
|
-
/**
|
|
54
|
-
* Twice the value of the mathematical constant PI (π).
|
|
55
|
-
* Approximately 6.28318
|
|
56
|
-
*
|
|
57
|
-
* Note: TWO_PI radians equals 360°, PI radians equals 180°,
|
|
58
|
-
* HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
|
|
59
|
-
*
|
|
60
|
-
* @type {number}
|
|
61
|
-
*/
|
|
62
178
|
TWO_PI,
|
|
63
|
-
/**
|
|
64
|
-
* Half the value of the mathematical constant PI (π).
|
|
65
|
-
* Approximately 1.57079
|
|
66
|
-
*
|
|
67
|
-
* @type {number}
|
|
68
|
-
*/
|
|
69
179
|
HALF_PI: TWO_PI / 4,
|
|
70
|
-
/**
|
|
71
|
-
* Calculates a linear (interpolation) value over t%.
|
|
72
|
-
*
|
|
73
|
-
* @param {number} start
|
|
74
|
-
* @param {number} end
|
|
75
|
-
* @param {number} t The progress in percentage, where 0 = 0% and 1 = 100%.
|
|
76
|
-
* @returns {number} The unterpolated value
|
|
77
|
-
* @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
|
|
78
|
-
*/
|
|
79
180
|
lerp: (start, end, t) => {
|
|
80
|
-
DEV: assert(
|
|
81
|
-
|
|
82
|
-
|
|
181
|
+
DEV: assert(
|
|
182
|
+
isNumber(start),
|
|
183
|
+
loggerPrefix + "lerp() 1st param must be a number",
|
|
184
|
+
);
|
|
185
|
+
DEV: assert(
|
|
186
|
+
isNumber(end),
|
|
187
|
+
loggerPrefix + "lerp() 2nd param must be a number",
|
|
188
|
+
);
|
|
189
|
+
DEV: assert(
|
|
190
|
+
isNumber(t),
|
|
191
|
+
loggerPrefix + "lerp() 3rd param must be a number",
|
|
192
|
+
);
|
|
83
193
|
return start + t * (end - start);
|
|
84
194
|
},
|
|
85
|
-
/**
|
|
86
|
-
* Convert degrees to radians
|
|
87
|
-
*
|
|
88
|
-
* @param {number} degs
|
|
89
|
-
* @returns {number} the value in radians
|
|
90
|
-
*/
|
|
91
195
|
deg2rad: (degs) => {
|
|
92
196
|
DEV: assert(isNumber(degs), "deg2rad: 1st param must be a number");
|
|
93
|
-
return math.PI / 180 * degs;
|
|
197
|
+
return (math.PI / 180) * degs;
|
|
94
198
|
},
|
|
95
|
-
/**
|
|
96
|
-
* Convert radians to degrees
|
|
97
|
-
*
|
|
98
|
-
* @param {number} rads
|
|
99
|
-
* @returns {number} the value in degrees
|
|
100
|
-
*/
|
|
101
199
|
rad2deg: (rads) => {
|
|
102
200
|
DEV: assert(isNumber(rads), "rad2deg: 1st param must be a number");
|
|
103
|
-
return 180 / math.PI * rads;
|
|
201
|
+
return (180 / math.PI) * rads;
|
|
104
202
|
},
|
|
105
|
-
/**
|
|
106
|
-
* Returns the rounded value of an number to optional precision (number of digits after the decimal point).
|
|
107
|
-
*
|
|
108
|
-
* Note: precision is optional but must be >= 0
|
|
109
|
-
*
|
|
110
|
-
* @param {number} n number to round.
|
|
111
|
-
* @param {number} [precision] number of decimal digits to round to, default is 0.
|
|
112
|
-
* @returns {number} rounded number.
|
|
113
|
-
*/
|
|
114
203
|
round: (n, precision = 0) => {
|
|
115
|
-
DEV: assert(
|
|
204
|
+
DEV: assert(
|
|
205
|
+
isNumber(n),
|
|
206
|
+
loggerPrefix + "round() 1st param must be a number",
|
|
207
|
+
);
|
|
116
208
|
DEV: assert(
|
|
117
209
|
isNumber(precision) && precision >= 0,
|
|
118
|
-
"
|
|
210
|
+
loggerPrefix + "round() 2nd param must be a positive number or zero",
|
|
119
211
|
);
|
|
120
212
|
if (!precision) {
|
|
121
213
|
return math.round(n);
|
|
@@ -123,203 +215,197 @@
|
|
|
123
215
|
const multiplier = 10 ** precision;
|
|
124
216
|
return math.round(n * multiplier) / multiplier;
|
|
125
217
|
},
|
|
126
|
-
/**
|
|
127
|
-
* Constrains a number between `min` and `max`.
|
|
128
|
-
*
|
|
129
|
-
* @param {number} value
|
|
130
|
-
* @param {number} min
|
|
131
|
-
* @param {number} max
|
|
132
|
-
* @returns {number}
|
|
133
|
-
*/
|
|
134
218
|
clamp: (value, min, max) => {
|
|
135
|
-
DEV: assert(
|
|
136
|
-
|
|
137
|
-
|
|
219
|
+
DEV: assert(
|
|
220
|
+
isNumber(value),
|
|
221
|
+
loggerPrefix + "clamp() 1st param must be a number",
|
|
222
|
+
);
|
|
223
|
+
DEV: assert(
|
|
224
|
+
isNumber(min),
|
|
225
|
+
loggerPrefix + "clamp() 2nd param must be a number",
|
|
226
|
+
);
|
|
227
|
+
DEV: assert(
|
|
228
|
+
isNumber(max),
|
|
229
|
+
loggerPrefix + "clamp() 3rd param must be a number",
|
|
230
|
+
);
|
|
138
231
|
DEV: assert(
|
|
139
232
|
max > min,
|
|
140
|
-
|
|
233
|
+
loggerPrefix +
|
|
234
|
+
"clamp() the 2nd param must be less than the 3rd param",
|
|
141
235
|
);
|
|
142
236
|
if (value < min) return min;
|
|
143
237
|
if (value > max) return max;
|
|
144
238
|
return value;
|
|
145
239
|
},
|
|
146
|
-
/**
|
|
147
|
-
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
148
|
-
*
|
|
149
|
-
* @param {number} x1
|
|
150
|
-
* @param {number} y1
|
|
151
|
-
* @param {number} x2
|
|
152
|
-
* @param {number} y2
|
|
153
|
-
* @returns {number}
|
|
154
|
-
*/
|
|
155
240
|
dist: (x1, y1, x2, y2) => {
|
|
156
|
-
DEV: assert(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
241
|
+
DEV: assert(
|
|
242
|
+
isNumber(x1),
|
|
243
|
+
loggerPrefix + "dist() 1st param must be a number",
|
|
244
|
+
);
|
|
245
|
+
DEV: assert(
|
|
246
|
+
isNumber(y1),
|
|
247
|
+
loggerPrefix + "dist() 2nd param must be a number",
|
|
248
|
+
);
|
|
249
|
+
DEV: assert(
|
|
250
|
+
isNumber(x2),
|
|
251
|
+
loggerPrefix + "dist() 3rd param must be a number",
|
|
252
|
+
);
|
|
253
|
+
DEV: assert(
|
|
254
|
+
isNumber(y2),
|
|
255
|
+
loggerPrefix + "dist() 4th param must be a number",
|
|
256
|
+
);
|
|
160
257
|
return math.hypot(x2 - x1, y2 - y1);
|
|
161
258
|
},
|
|
162
|
-
/**
|
|
163
|
-
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
164
|
-
*
|
|
165
|
-
* @param {number} value
|
|
166
|
-
* @param {number} min
|
|
167
|
-
* @param {number} max
|
|
168
|
-
* @returns {number}
|
|
169
|
-
*/
|
|
170
259
|
wrap: (value, min, max) => {
|
|
171
|
-
DEV: assert(
|
|
172
|
-
|
|
173
|
-
|
|
260
|
+
DEV: assert(
|
|
261
|
+
isNumber(value),
|
|
262
|
+
loggerPrefix + "wrap() 1st param must be a number",
|
|
263
|
+
);
|
|
264
|
+
DEV: assert(
|
|
265
|
+
isNumber(min),
|
|
266
|
+
loggerPrefix + "wrap() 2nd param must be a number",
|
|
267
|
+
);
|
|
268
|
+
DEV: assert(
|
|
269
|
+
isNumber(max),
|
|
270
|
+
loggerPrefix + "wrap() 3rd param must be a number",
|
|
271
|
+
);
|
|
174
272
|
DEV: assert(
|
|
175
273
|
max > min,
|
|
176
|
-
"
|
|
274
|
+
loggerPrefix + "wrap() the 2nd param must be less than the 3rd param",
|
|
177
275
|
);
|
|
178
276
|
return value - (max - min) * math.floor((value - min) / (max - min));
|
|
179
277
|
},
|
|
180
|
-
/**
|
|
181
|
-
* Re-maps a number from one range to another.
|
|
182
|
-
*
|
|
183
|
-
* @param {number} value the value to be remapped.
|
|
184
|
-
* @param {number} start1 lower bound of the value's current range.
|
|
185
|
-
* @param {number} stop1 upper bound of the value's current range.
|
|
186
|
-
* @param {number} start2 lower bound of the value's target range.
|
|
187
|
-
* @param {number} stop2 upper bound of the value's target range.
|
|
188
|
-
* @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
|
|
189
|
-
* @returns {number} the remapped number
|
|
190
|
-
*/
|
|
191
278
|
map(value, start1, stop1, start2, stop2, withinBounds) {
|
|
192
|
-
DEV: assert(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
DEV: assert(
|
|
279
|
+
DEV: assert(
|
|
280
|
+
isNumber(value),
|
|
281
|
+
loggerPrefix + "map() 1st param must be a number",
|
|
282
|
+
);
|
|
283
|
+
DEV: assert(
|
|
284
|
+
isNumber(start1),
|
|
285
|
+
loggerPrefix + "map() 2nd param must be a number",
|
|
286
|
+
);
|
|
287
|
+
DEV: assert(
|
|
288
|
+
isNumber(stop1),
|
|
289
|
+
loggerPrefix + "map() 3rd param must be a number",
|
|
290
|
+
);
|
|
291
|
+
DEV: assert(
|
|
292
|
+
isNumber(start2),
|
|
293
|
+
loggerPrefix + "map() 4th param must be a number",
|
|
294
|
+
);
|
|
295
|
+
DEV: assert(
|
|
296
|
+
isNumber(stop2),
|
|
297
|
+
loggerPrefix + "map() 5th param must be a number",
|
|
298
|
+
);
|
|
197
299
|
DEV: assert(
|
|
198
300
|
stop1 !== start1,
|
|
199
|
-
|
|
301
|
+
loggerPrefix +
|
|
302
|
+
"map() the 2nd param must be different than the 3rd param",
|
|
200
303
|
);
|
|
201
|
-
const result =
|
|
304
|
+
const result =
|
|
305
|
+
((value - start1) / (stop1 - start1)) * (stop2 - start2) + start2;
|
|
202
306
|
return withinBounds ? instance.clamp(result, start2, stop2) : result;
|
|
203
307
|
},
|
|
204
|
-
/**
|
|
205
|
-
* Maps a number from one range to a value between 0 and 1.
|
|
206
|
-
* Identical to `map(value, min, max, 0, 1)`.
|
|
207
|
-
* Note: Numbers outside the range are not clamped to 0 and 1.
|
|
208
|
-
*
|
|
209
|
-
* @param {number} value
|
|
210
|
-
* @param {number} start
|
|
211
|
-
* @param {number} stop
|
|
212
|
-
* @returns {number} the normalized number.
|
|
213
|
-
*/
|
|
214
308
|
norm: (value, start, stop) => {
|
|
215
|
-
DEV: assert(
|
|
216
|
-
|
|
217
|
-
|
|
309
|
+
DEV: assert(
|
|
310
|
+
isNumber(value),
|
|
311
|
+
loggerPrefix + "norm() 1st param must be a number",
|
|
312
|
+
);
|
|
313
|
+
DEV: assert(
|
|
314
|
+
isNumber(start),
|
|
315
|
+
loggerPrefix + "norm() 2nd param must be a number",
|
|
316
|
+
);
|
|
317
|
+
DEV: assert(
|
|
318
|
+
isNumber(stop),
|
|
319
|
+
loggerPrefix + "norm() 3rd param must be a number",
|
|
320
|
+
);
|
|
218
321
|
DEV: assert(
|
|
219
322
|
start !== stop,
|
|
220
|
-
|
|
323
|
+
loggerPrefix +
|
|
324
|
+
"norm() the 2nd param must be different than the 3rd param",
|
|
221
325
|
);
|
|
222
326
|
return instance.map(value, start, stop, 0, 1);
|
|
223
327
|
},
|
|
224
|
-
/** RNG API */
|
|
225
|
-
/**
|
|
226
|
-
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
227
|
-
* using the Linear Congruential Generator (LCG) algorithm.
|
|
228
|
-
*
|
|
229
|
-
* @param {number} [min=0.0]
|
|
230
|
-
* @param {number} [max=1.0]
|
|
231
|
-
* @returns {number} the random number
|
|
232
|
-
*/
|
|
233
328
|
rand: (min = 0, max = 1) => {
|
|
234
|
-
DEV: assert(
|
|
235
|
-
|
|
329
|
+
DEV: assert(
|
|
330
|
+
isNumber(min),
|
|
331
|
+
loggerPrefix + "rand() 1st param must be a number",
|
|
332
|
+
);
|
|
333
|
+
DEV: assert(
|
|
334
|
+
isNumber(max),
|
|
335
|
+
loggerPrefix + "rand() 2nd param must be a number",
|
|
336
|
+
);
|
|
236
337
|
DEV: assert(
|
|
237
338
|
max > min,
|
|
238
|
-
"
|
|
339
|
+
loggerPrefix + "rand() the 1st param must be less than the 2nd param",
|
|
239
340
|
);
|
|
240
341
|
const a = 1664525;
|
|
241
342
|
const c = 1013904223;
|
|
242
343
|
const m = 4294967296;
|
|
243
344
|
_rngSeed = (a * _rngSeed + c) % m;
|
|
244
|
-
return _rngSeed / m * (max - min) + min;
|
|
345
|
+
return (_rngSeed / m) * (max - min) + min;
|
|
245
346
|
},
|
|
246
|
-
/**
|
|
247
|
-
* Generates a pseudorandom integer between min (inclusive) and max (inclusive)
|
|
248
|
-
*
|
|
249
|
-
* @param {number} [min=0]
|
|
250
|
-
* @param {number} [max=1]
|
|
251
|
-
* @returns {number} the random number
|
|
252
|
-
*/
|
|
253
347
|
randi: (min = 0, max = 1) => {
|
|
254
|
-
DEV: assert(
|
|
255
|
-
|
|
348
|
+
DEV: assert(
|
|
349
|
+
isNumber(min),
|
|
350
|
+
loggerPrefix + "randi() 1st param must be a number",
|
|
351
|
+
);
|
|
352
|
+
DEV: assert(
|
|
353
|
+
isNumber(max),
|
|
354
|
+
loggerPrefix + "randi() 2nd param must be a number",
|
|
355
|
+
);
|
|
256
356
|
DEV: assert(
|
|
257
357
|
min <= max,
|
|
258
|
-
|
|
358
|
+
loggerPrefix +
|
|
359
|
+
"randi() the 1st param must be less than the 2nd param",
|
|
259
360
|
);
|
|
260
|
-
return
|
|
361
|
+
return ~~instance.rand(min, max + 1);
|
|
261
362
|
},
|
|
262
|
-
/**
|
|
263
|
-
* Initializes the random number generator with an explicit seed value.
|
|
264
|
-
*
|
|
265
|
-
* Note: The seed should be a integer number greater than or equal to zero.
|
|
266
|
-
*
|
|
267
|
-
* @param {number} value
|
|
268
|
-
*/
|
|
269
363
|
rseed(value) {
|
|
270
364
|
DEV: assert(
|
|
271
365
|
isNumber(value) && value >= 0,
|
|
272
|
-
"
|
|
366
|
+
loggerPrefix + "rseed() 1st param must be a positive integer or zero",
|
|
273
367
|
);
|
|
274
368
|
_rngSeed = ~~value;
|
|
275
369
|
},
|
|
276
|
-
/** BASIC GRAPHICS API */
|
|
277
|
-
/**
|
|
278
|
-
* Clear the game screen with an optional color
|
|
279
|
-
*
|
|
280
|
-
* @param {number} [color] The background color (index) or null/undefined (for transparent)
|
|
281
|
-
*/
|
|
282
370
|
cls(color) {
|
|
283
371
|
DEV: assert(
|
|
284
|
-
null == color || isNumber(color) && color >= 0,
|
|
285
|
-
|
|
372
|
+
null == color || (isNumber(color) && color >= 0),
|
|
373
|
+
loggerPrefix +
|
|
374
|
+
"cls() 1st param must be a positive number or zero or undefined",
|
|
286
375
|
);
|
|
287
376
|
if (null == color) {
|
|
288
|
-
_ctx.clearRect(0, 0,
|
|
377
|
+
_ctx.clearRect(0, 0, instance.W, instance.H);
|
|
289
378
|
} else {
|
|
290
|
-
instance.rectfill(0, 0,
|
|
379
|
+
instance.rectfill(0, 0, instance.W, instance.H, color);
|
|
291
380
|
}
|
|
292
381
|
},
|
|
293
|
-
/**
|
|
294
|
-
* Draw a rectangle outline
|
|
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
|
|
301
|
-
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
302
|
-
*
|
|
303
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect
|
|
304
|
-
*/
|
|
305
382
|
rect(x, y, width, height, color, radii) {
|
|
306
|
-
DEV: assert(
|
|
307
|
-
|
|
383
|
+
DEV: assert(
|
|
384
|
+
isNumber(x),
|
|
385
|
+
loggerPrefix + "rect() 1st param must be a number",
|
|
386
|
+
);
|
|
387
|
+
DEV: assert(
|
|
388
|
+
isNumber(y),
|
|
389
|
+
loggerPrefix + "rect() 2nd param must be a number",
|
|
390
|
+
);
|
|
308
391
|
DEV: assert(
|
|
309
392
|
isNumber(width) && width > 0,
|
|
310
|
-
"
|
|
393
|
+
loggerPrefix + "rect() 3rd param must be a positive number",
|
|
311
394
|
);
|
|
312
395
|
DEV: assert(
|
|
313
396
|
isNumber(height) && height >= 0,
|
|
314
|
-
"
|
|
397
|
+
loggerPrefix + "rect() 4th param must be a positive number or zero",
|
|
315
398
|
);
|
|
316
399
|
DEV: assert(
|
|
317
|
-
null == color || isNumber(color) && color >= 0,
|
|
318
|
-
"
|
|
400
|
+
null == color || (isNumber(color) && color >= 0),
|
|
401
|
+
loggerPrefix + "rect() 5th param must be a positive number or zero",
|
|
319
402
|
);
|
|
320
403
|
DEV: assert(
|
|
321
|
-
null == radii ||
|
|
322
|
-
|
|
404
|
+
null == radii ||
|
|
405
|
+
isNumber(radii) ||
|
|
406
|
+
(Array.isArray(radii) && radii.length >= 1),
|
|
407
|
+
loggerPrefix +
|
|
408
|
+
"rect() 6th param must be a number or array of numbers",
|
|
323
409
|
);
|
|
324
410
|
beginPath(_ctx);
|
|
325
411
|
_ctx[radii ? "roundRect" : "rect"](
|
|
@@ -327,159 +413,151 @@
|
|
|
327
413
|
~~y - _outline_fix,
|
|
328
414
|
~~width + _outline_fix * 2,
|
|
329
415
|
~~height + _outline_fix * 2,
|
|
330
|
-
radii
|
|
416
|
+
radii,
|
|
331
417
|
);
|
|
332
418
|
instance.stroke(color);
|
|
333
419
|
},
|
|
334
|
-
/**
|
|
335
|
-
* Draw a color-filled rectangle
|
|
336
|
-
*
|
|
337
|
-
* @param {number} x
|
|
338
|
-
* @param {number} y
|
|
339
|
-
* @param {number} width
|
|
340
|
-
* @param {number} height
|
|
341
|
-
* @param {number} [color=0] the color index
|
|
342
|
-
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
343
|
-
*/
|
|
344
420
|
rectfill(x, y, width, height, color, radii) {
|
|
345
|
-
DEV: assert(
|
|
346
|
-
|
|
421
|
+
DEV: assert(
|
|
422
|
+
isNumber(x),
|
|
423
|
+
loggerPrefix + "rectfill() 1st param must be a number",
|
|
424
|
+
);
|
|
425
|
+
DEV: assert(
|
|
426
|
+
isNumber(y),
|
|
427
|
+
loggerPrefix + "rectfill() 2nd param must be a number",
|
|
428
|
+
);
|
|
347
429
|
DEV: assert(
|
|
348
430
|
isNumber(width) && width >= 0,
|
|
349
|
-
|
|
431
|
+
loggerPrefix +
|
|
432
|
+
"rectfill() 3rd param must be a positive number or zero",
|
|
350
433
|
);
|
|
351
434
|
DEV: assert(
|
|
352
435
|
isNumber(height) && height >= 0,
|
|
353
|
-
|
|
436
|
+
loggerPrefix +
|
|
437
|
+
"rectfill() 4th param must be a positive number or zero",
|
|
354
438
|
);
|
|
355
439
|
DEV: assert(
|
|
356
|
-
null == color || isNumber(color) && color >= 0,
|
|
357
|
-
|
|
440
|
+
null == color || (isNumber(color) && color >= 0),
|
|
441
|
+
loggerPrefix +
|
|
442
|
+
"rectfill() 5th param must be a positive number or zero",
|
|
358
443
|
);
|
|
359
444
|
DEV: assert(
|
|
360
|
-
null == radii ||
|
|
361
|
-
|
|
445
|
+
null == radii ||
|
|
446
|
+
isNumber(radii) ||
|
|
447
|
+
(Array.isArray(radii) && radii.length >= 1),
|
|
448
|
+
loggerPrefix +
|
|
449
|
+
"rectfill() 6th param must be a number or array of at least 2 numbers",
|
|
362
450
|
);
|
|
363
451
|
beginPath(_ctx);
|
|
364
452
|
_ctx[radii ? "roundRect" : "rect"](~~x, ~~y, ~~width, ~~height, radii);
|
|
365
453
|
instance.fill(color);
|
|
366
454
|
},
|
|
367
|
-
/**
|
|
368
|
-
* Draw a circle outline
|
|
369
|
-
*
|
|
370
|
-
* @param {number} x
|
|
371
|
-
* @param {number} y
|
|
372
|
-
* @param {number} radius
|
|
373
|
-
* @param {number} [color=0] the color index
|
|
374
|
-
*/
|
|
375
455
|
circ(x, y, radius, color) {
|
|
376
|
-
DEV: assert(
|
|
377
|
-
|
|
456
|
+
DEV: assert(
|
|
457
|
+
isNumber(x),
|
|
458
|
+
loggerPrefix + "circ() 1st param must be a number",
|
|
459
|
+
);
|
|
460
|
+
DEV: assert(
|
|
461
|
+
isNumber(y),
|
|
462
|
+
loggerPrefix + "circ() 2nd param must be a number",
|
|
463
|
+
);
|
|
378
464
|
DEV: assert(
|
|
379
465
|
isNumber(radius) && radius >= 0,
|
|
380
|
-
"
|
|
466
|
+
loggerPrefix + "circ() 3rd param must be a positive number or zero",
|
|
381
467
|
);
|
|
382
468
|
DEV: assert(
|
|
383
|
-
null == color || isNumber(color) && color >= 0,
|
|
384
|
-
"
|
|
469
|
+
null == color || (isNumber(color) && color >= 0),
|
|
470
|
+
loggerPrefix + "circ() 4th param must be a positive number or zero",
|
|
385
471
|
);
|
|
386
472
|
beginPath(_ctx);
|
|
387
473
|
_ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
|
|
388
474
|
instance.stroke(color);
|
|
389
475
|
},
|
|
390
|
-
/**
|
|
391
|
-
* Draw a color-filled circle
|
|
392
|
-
*
|
|
393
|
-
* @param {number} x
|
|
394
|
-
* @param {number} y
|
|
395
|
-
* @param {number} radius
|
|
396
|
-
* @param {number} [color=0] the color index
|
|
397
|
-
*/
|
|
398
476
|
circfill(x, y, radius, color) {
|
|
399
|
-
DEV: assert(
|
|
400
|
-
|
|
477
|
+
DEV: assert(
|
|
478
|
+
isNumber(x),
|
|
479
|
+
loggerPrefix + "circfill() 1st param must be a number",
|
|
480
|
+
);
|
|
481
|
+
DEV: assert(
|
|
482
|
+
isNumber(y),
|
|
483
|
+
loggerPrefix + "circfill() 2nd param must be a number",
|
|
484
|
+
);
|
|
401
485
|
DEV: assert(
|
|
402
486
|
isNumber(radius) && radius >= 0,
|
|
403
|
-
|
|
487
|
+
loggerPrefix +
|
|
488
|
+
"circfill() 3rd param must be a positive number or zero",
|
|
404
489
|
);
|
|
405
490
|
DEV: assert(
|
|
406
|
-
null == color || isNumber(color) && color >= 0,
|
|
407
|
-
|
|
491
|
+
null == color || (isNumber(color) && color >= 0),
|
|
492
|
+
loggerPrefix +
|
|
493
|
+
"circfill() 4th param must be a positive number or zero",
|
|
408
494
|
);
|
|
409
495
|
beginPath(_ctx);
|
|
410
496
|
_ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
|
|
411
497
|
instance.fill(color);
|
|
412
498
|
},
|
|
413
|
-
/**
|
|
414
|
-
* Draw a ellipse outline
|
|
415
|
-
*
|
|
416
|
-
* @param {number} x
|
|
417
|
-
* @param {number} y
|
|
418
|
-
* @param {number} radiusX
|
|
419
|
-
* @param {number} radiusY
|
|
420
|
-
* @param {number} [color=0] the color index
|
|
421
|
-
*/
|
|
422
499
|
oval(x, y, radiusX, radiusY, color) {
|
|
423
|
-
DEV: assert(
|
|
424
|
-
|
|
500
|
+
DEV: assert(
|
|
501
|
+
isNumber(x),
|
|
502
|
+
loggerPrefix + "oval() 1st param must be a number",
|
|
503
|
+
);
|
|
504
|
+
DEV: assert(
|
|
505
|
+
isNumber(y),
|
|
506
|
+
loggerPrefix + "oval() 2nd param must be a number",
|
|
507
|
+
);
|
|
425
508
|
DEV: assert(
|
|
426
509
|
isNumber(radiusX) && radiusX >= 0,
|
|
427
|
-
"
|
|
510
|
+
loggerPrefix + "oval() 3rd param must be a positive number or zero",
|
|
428
511
|
);
|
|
429
512
|
DEV: assert(
|
|
430
513
|
isNumber(radiusY) && radiusY >= 0,
|
|
431
|
-
"
|
|
514
|
+
loggerPrefix + "oval() 4th param must be a positive number or zero",
|
|
432
515
|
);
|
|
433
516
|
DEV: assert(
|
|
434
|
-
null == color || isNumber(color) && color >= 0,
|
|
435
|
-
"
|
|
517
|
+
null == color || (isNumber(color) && color >= 0),
|
|
518
|
+
loggerPrefix + "oval() 5th param must be a positive number or zero",
|
|
436
519
|
);
|
|
437
520
|
beginPath(_ctx);
|
|
438
521
|
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
|
|
439
522
|
instance.stroke(color);
|
|
440
523
|
},
|
|
441
|
-
/**
|
|
442
|
-
* Draw a color-filled ellipse
|
|
443
|
-
*
|
|
444
|
-
* @param {number} x
|
|
445
|
-
* @param {number} y
|
|
446
|
-
* @param {number} radiusX
|
|
447
|
-
* @param {number} radiusY
|
|
448
|
-
* @param {number} [color=0] the color index
|
|
449
|
-
*/
|
|
450
524
|
ovalfill(x, y, radiusX, radiusY, color) {
|
|
451
|
-
DEV: assert(
|
|
452
|
-
|
|
525
|
+
DEV: assert(
|
|
526
|
+
isNumber(x),
|
|
527
|
+
loggerPrefix + "ovalfill() 1st param must be a number",
|
|
528
|
+
);
|
|
529
|
+
DEV: assert(
|
|
530
|
+
isNumber(y),
|
|
531
|
+
loggerPrefix + "ovalfill() 2nd param must be a number",
|
|
532
|
+
);
|
|
453
533
|
DEV: assert(
|
|
454
534
|
isNumber(radiusX) && radiusX >= 0,
|
|
455
|
-
|
|
535
|
+
loggerPrefix +
|
|
536
|
+
"ovalfill() 3rd param must be a positive number or zero",
|
|
456
537
|
);
|
|
457
538
|
DEV: assert(
|
|
458
539
|
isNumber(radiusY) && radiusY >= 0,
|
|
459
|
-
|
|
540
|
+
loggerPrefix +
|
|
541
|
+
"ovalfill() 4th param must be a positive number or zero",
|
|
460
542
|
);
|
|
461
543
|
DEV: assert(
|
|
462
|
-
null == color || isNumber(color) && color >= 0,
|
|
463
|
-
|
|
544
|
+
null == color || (isNumber(color) && color >= 0),
|
|
545
|
+
loggerPrefix +
|
|
546
|
+
"ovalfill() 5th param must be a positive number or zero",
|
|
464
547
|
);
|
|
465
548
|
beginPath(_ctx);
|
|
466
549
|
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
|
|
467
550
|
instance.fill(color);
|
|
468
551
|
},
|
|
469
|
-
/**
|
|
470
|
-
* Make a custom shape in the canvas context.
|
|
471
|
-
* Then, just use `fill` or `stroke` to draw the shape.
|
|
472
|
-
*
|
|
473
|
-
* @param {number[]} points an array of Xs and Ys coordinates
|
|
474
|
-
*/
|
|
475
552
|
shape(points) {
|
|
476
553
|
DEV: assert(
|
|
477
554
|
Array.isArray(points),
|
|
478
|
-
"
|
|
555
|
+
loggerPrefix + "shape() 1st param must be an array of numbers",
|
|
479
556
|
);
|
|
480
557
|
DEV: assert(
|
|
481
558
|
points.length >= 6,
|
|
482
|
-
|
|
559
|
+
loggerPrefix +
|
|
560
|
+
"shape() 1st param must be an array with at least 6 numbers (3 points)",
|
|
483
561
|
);
|
|
484
562
|
beginPath(_ctx);
|
|
485
563
|
for (let i = 0; i < points.length; i += 2) {
|
|
@@ -491,29 +569,26 @@
|
|
|
491
569
|
}
|
|
492
570
|
_ctx.lineTo(~~points[0], ~~points[1]);
|
|
493
571
|
},
|
|
494
|
-
/**
|
|
495
|
-
* Draw a line
|
|
496
|
-
*
|
|
497
|
-
* @param {number} x1
|
|
498
|
-
* @param {number} y1
|
|
499
|
-
* @param {number} x2
|
|
500
|
-
* @param {number} y2
|
|
501
|
-
* @param {number} [color=0] the color index
|
|
502
|
-
*/
|
|
503
572
|
line(x1, y1, x2, y2, color) {
|
|
504
|
-
DEV: assert(
|
|
505
|
-
|
|
573
|
+
DEV: assert(
|
|
574
|
+
isNumber(x1),
|
|
575
|
+
loggerPrefix + "line() 1st param must be a number",
|
|
576
|
+
);
|
|
577
|
+
DEV: assert(
|
|
578
|
+
isNumber(y1),
|
|
579
|
+
loggerPrefix + "line() 2nd param must be a number",
|
|
580
|
+
);
|
|
506
581
|
DEV: assert(
|
|
507
582
|
isNumber(x2),
|
|
508
|
-
"
|
|
583
|
+
loggerPrefix + "line() 3rd param must be a positive number or zero",
|
|
509
584
|
);
|
|
510
585
|
DEV: assert(
|
|
511
586
|
isNumber(y2),
|
|
512
|
-
"
|
|
587
|
+
loggerPrefix + "line() 4th param must be a positive number or zero",
|
|
513
588
|
);
|
|
514
589
|
DEV: assert(
|
|
515
|
-
null == color || isNumber(color) && color >= 0,
|
|
516
|
-
"
|
|
590
|
+
null == color || (isNumber(color) && color >= 0),
|
|
591
|
+
loggerPrefix + "line() 5th param must be a positive number or zero",
|
|
517
592
|
);
|
|
518
593
|
beginPath(_ctx);
|
|
519
594
|
let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0;
|
|
@@ -522,187 +597,162 @@
|
|
|
522
597
|
_ctx.lineTo(~~x2 + xfix, ~~y2 + yfix);
|
|
523
598
|
instance.stroke(color);
|
|
524
599
|
},
|
|
525
|
-
/**
|
|
526
|
-
* Sets the thickness of the lines
|
|
527
|
-
*
|
|
528
|
-
* @param {number} value
|
|
529
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
|
|
530
|
-
*/
|
|
531
600
|
linewidth(value) {
|
|
532
601
|
DEV: assert(
|
|
533
602
|
isNumber(value) && value >= 0,
|
|
534
|
-
|
|
603
|
+
loggerPrefix +
|
|
604
|
+
"linewidth() 1st param must be a positive number or zero",
|
|
535
605
|
);
|
|
536
606
|
_ctx.lineWidth = ~~value;
|
|
537
607
|
_outline_fix = 0 === ~~value % 2 ? 0 : 0.5;
|
|
538
608
|
},
|
|
539
|
-
/**
|
|
540
|
-
* Sets the line dash pattern used when drawing lines
|
|
541
|
-
*
|
|
542
|
-
* @param {number[]} segments the line dash pattern
|
|
543
|
-
* @param {number} [offset=0] the line dash offset, or "phase".
|
|
544
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
545
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
|
|
546
|
-
*/
|
|
547
609
|
linedash(segments, offset = 0) {
|
|
548
610
|
DEV: assert(
|
|
549
611
|
Array.isArray(segments) && segments.length > 0,
|
|
550
|
-
"
|
|
612
|
+
loggerPrefix + "linedash() 1st param must be an array of numbers",
|
|
613
|
+
);
|
|
614
|
+
DEV: assert(
|
|
615
|
+
isNumber(offset),
|
|
616
|
+
loggerPrefix + "linedash() 2nd param must be a number",
|
|
551
617
|
);
|
|
552
|
-
DEV: assert(isNumber(offset), "[litecanvas] linedash() 2nd param must be a number");
|
|
553
618
|
_ctx.setLineDash(segments);
|
|
554
619
|
_ctx.lineDashOffset = offset;
|
|
555
620
|
},
|
|
556
|
-
/** TEXT RENDERING API */
|
|
557
|
-
/**
|
|
558
|
-
* Draw text. You can use `\n` to break lines.
|
|
559
|
-
*
|
|
560
|
-
* @param {number} x
|
|
561
|
-
* @param {number} y
|
|
562
|
-
* @param {string} message the text message
|
|
563
|
-
* @param {number} [color] the color index
|
|
564
|
-
* @param {string} [fontStyle] can be "normal" (default), "italic" and/or "bold".
|
|
565
|
-
*/
|
|
566
621
|
text(x, y, message, color = _defaultTextColor, fontStyle = "normal") {
|
|
567
|
-
DEV: assert(isNumber(x), "[litecanvas] text() 1st param must be a number");
|
|
568
|
-
DEV: assert(isNumber(y), "[litecanvas] text() 2nd param must be a number");
|
|
569
622
|
DEV: assert(
|
|
570
|
-
|
|
571
|
-
"
|
|
623
|
+
isNumber(x),
|
|
624
|
+
loggerPrefix + "text() 1st param must be a number",
|
|
625
|
+
);
|
|
626
|
+
DEV: assert(
|
|
627
|
+
isNumber(y),
|
|
628
|
+
loggerPrefix + "text() 2nd param must be a number",
|
|
629
|
+
);
|
|
630
|
+
DEV: assert(
|
|
631
|
+
null == color || (isNumber(color) && color >= 0),
|
|
632
|
+
loggerPrefix + "text() 4th param must be a positive number or zero",
|
|
572
633
|
);
|
|
573
634
|
DEV: assert(
|
|
574
635
|
"string" === typeof fontStyle,
|
|
575
|
-
"
|
|
636
|
+
loggerPrefix + "text() 5th param must be a string",
|
|
576
637
|
);
|
|
577
638
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
|
|
578
639
|
_ctx.fillStyle = getColor(color);
|
|
579
640
|
const messages = ("" + message).split("\n");
|
|
580
641
|
for (let i = 0; i < messages.length; i++) {
|
|
581
|
-
_ctx.fillText(
|
|
642
|
+
_ctx.fillText(
|
|
643
|
+
messages[i],
|
|
644
|
+
~~x,
|
|
645
|
+
~~y + _fontSize * _fontLineHeight * i,
|
|
646
|
+
);
|
|
582
647
|
}
|
|
583
648
|
},
|
|
584
|
-
/**
|
|
585
|
-
* Sets the height ratio of the text lines based on current text size.
|
|
586
|
-
*
|
|
587
|
-
* Default = `1.2`
|
|
588
|
-
*
|
|
589
|
-
* @param value
|
|
590
|
-
*/
|
|
591
649
|
textgap(value) {
|
|
592
650
|
_fontLineHeight = value;
|
|
593
651
|
},
|
|
594
|
-
/**
|
|
595
|
-
* Set the font family
|
|
596
|
-
*
|
|
597
|
-
* @param {string} family
|
|
598
|
-
*/
|
|
599
652
|
textfont(family) {
|
|
600
653
|
DEV: assert(
|
|
601
654
|
"string" === typeof family,
|
|
602
|
-
"
|
|
655
|
+
loggerPrefix + "textfont() 1st param must be a string",
|
|
603
656
|
);
|
|
604
657
|
_fontFamily = family;
|
|
605
658
|
},
|
|
606
|
-
/**
|
|
607
|
-
* Set the font size
|
|
608
|
-
*
|
|
609
|
-
* @param {number} size
|
|
610
|
-
*/
|
|
611
659
|
textsize(size) {
|
|
612
|
-
DEV: assert(
|
|
660
|
+
DEV: assert(
|
|
661
|
+
isNumber(size),
|
|
662
|
+
loggerPrefix + "textsize() 1st param must be a number",
|
|
663
|
+
);
|
|
613
664
|
_fontSize = size;
|
|
614
665
|
},
|
|
615
|
-
/**
|
|
616
|
-
* Sets the alignment used when drawing texts
|
|
617
|
-
*
|
|
618
|
-
* @param {CanvasTextAlign} align the horizontal alignment. Possible values: "left", "right", "center", "start" or "end"
|
|
619
|
-
* @param {CanvasTextBaseline} baseline the vertical alignment. Possible values: "top", "bottom", "middle", "hanging" or "ideographic"
|
|
620
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
|
|
621
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
|
|
622
|
-
*/
|
|
623
666
|
textalign(align, baseline) {
|
|
624
667
|
DEV: assert(
|
|
625
|
-
null == align ||
|
|
626
|
-
|
|
668
|
+
null == align ||
|
|
669
|
+
["left", "right", "center", "start", "end"].includes(align),
|
|
670
|
+
loggerPrefix +
|
|
671
|
+
"textalign() 1st param must be null or one of the following strings: center, left, right, start or end.",
|
|
627
672
|
);
|
|
628
673
|
DEV: assert(
|
|
629
|
-
null == baseline ||
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
674
|
+
null == baseline ||
|
|
675
|
+
[
|
|
676
|
+
"top",
|
|
677
|
+
"bottom",
|
|
678
|
+
"middle",
|
|
679
|
+
"hanging",
|
|
680
|
+
"alphabetic",
|
|
681
|
+
"ideographic",
|
|
682
|
+
].includes(baseline),
|
|
683
|
+
loggerPrefix +
|
|
684
|
+
"textalign() 2nd param must be null or one of the following strings: middle, top, bottom, hanging, alphabetic or ideographic.",
|
|
633
685
|
);
|
|
634
686
|
if (align) _ctx.textAlign = align;
|
|
635
687
|
if (baseline) _ctx.textBaseline = baseline;
|
|
636
688
|
},
|
|
637
|
-
/** IMAGE GRAPHICS API */
|
|
638
|
-
/**
|
|
639
|
-
* Draw an image
|
|
640
|
-
*
|
|
641
|
-
* @param {number} x
|
|
642
|
-
* @param {number} y
|
|
643
|
-
* @param {CanvasImageSource} source
|
|
644
|
-
*/
|
|
645
689
|
image(x, y, source2) {
|
|
646
|
-
DEV: assert(
|
|
647
|
-
|
|
690
|
+
DEV: assert(
|
|
691
|
+
isNumber(x),
|
|
692
|
+
loggerPrefix + "image() 1st param must be a number",
|
|
693
|
+
);
|
|
694
|
+
DEV: assert(
|
|
695
|
+
isNumber(y),
|
|
696
|
+
loggerPrefix + "image() 2nd param must be a number",
|
|
697
|
+
);
|
|
648
698
|
_ctx.drawImage(source2, ~~x, ~~y);
|
|
649
699
|
},
|
|
650
|
-
/**
|
|
651
|
-
* Draw a sprite pixel by pixel represented by a string. Each pixel must be a base 36 number (0-9 or a-z) or a dot.
|
|
652
|
-
*
|
|
653
|
-
* @param {number} x
|
|
654
|
-
* @param {number} y
|
|
655
|
-
* @param {string} pixels
|
|
656
|
-
*/
|
|
657
700
|
spr(x, y, pixels) {
|
|
658
|
-
DEV: assert(
|
|
659
|
-
|
|
660
|
-
|
|
701
|
+
DEV: assert(
|
|
702
|
+
isNumber(x),
|
|
703
|
+
loggerPrefix + "spr() 1st param must be a number",
|
|
704
|
+
);
|
|
705
|
+
DEV: assert(
|
|
706
|
+
isNumber(y),
|
|
707
|
+
loggerPrefix + "spr() 2nd param must be a number",
|
|
708
|
+
);
|
|
709
|
+
DEV: assert(
|
|
710
|
+
"string" === typeof pixels,
|
|
711
|
+
loggerPrefix + "spr() 3rd param must be a string",
|
|
712
|
+
);
|
|
661
713
|
const rows = pixels.trim().split("\n");
|
|
662
714
|
for (let row = 0; row < rows.length; row++) {
|
|
663
715
|
const chars = rows[row].trim();
|
|
664
716
|
for (let col = 0; col < chars.length; col++) {
|
|
665
717
|
const char = chars[col];
|
|
666
718
|
if (char !== "." && char !== " ") {
|
|
667
|
-
instance.rectfill(
|
|
719
|
+
instance.rectfill(
|
|
720
|
+
x + col,
|
|
721
|
+
y + row,
|
|
722
|
+
1,
|
|
723
|
+
1,
|
|
724
|
+
parseInt(char, 36) || 0,
|
|
725
|
+
);
|
|
668
726
|
}
|
|
669
727
|
}
|
|
670
728
|
}
|
|
671
729
|
},
|
|
672
|
-
/**
|
|
673
|
-
* Draw in an OffscreenCanvas and returns its image.
|
|
674
|
-
*
|
|
675
|
-
* @param {number} width
|
|
676
|
-
* @param {number} height
|
|
677
|
-
* @param {drawCallback} callback
|
|
678
|
-
* @param {object} [options]
|
|
679
|
-
* @param {number} [options.scale=1]
|
|
680
|
-
* @param {OffscreenCanvas} [options.canvas]
|
|
681
|
-
* @returns {ImageBitmap}
|
|
682
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
|
|
683
|
-
*/
|
|
684
730
|
paint(width, height, callback, options = {}) {
|
|
685
731
|
DEV: assert(
|
|
686
732
|
isNumber(width) && width >= 1,
|
|
687
|
-
"
|
|
733
|
+
loggerPrefix + "paint() 1st param must be a positive number",
|
|
688
734
|
);
|
|
689
735
|
DEV: assert(
|
|
690
736
|
isNumber(height) && height >= 1,
|
|
691
|
-
"
|
|
737
|
+
loggerPrefix + "paint() 2nd param must be a positive number",
|
|
692
738
|
);
|
|
693
739
|
DEV: assert(
|
|
694
740
|
"function" === typeof callback,
|
|
695
|
-
"
|
|
741
|
+
loggerPrefix + "paint() 3rd param must be a function",
|
|
696
742
|
);
|
|
697
743
|
DEV: assert(
|
|
698
|
-
options && null == options.scale || isNumber(options.scale),
|
|
699
|
-
"
|
|
744
|
+
(options && null == options.scale) || isNumber(options.scale),
|
|
745
|
+
loggerPrefix + "paint() 4th param (options.scale) must be a number",
|
|
700
746
|
);
|
|
701
747
|
DEV: assert(
|
|
702
|
-
options && null == options.canvas ||
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
748
|
+
(options && null == options.canvas) ||
|
|
749
|
+
options.canvas instanceof OffscreenCanvas,
|
|
750
|
+
loggerPrefix +
|
|
751
|
+
"paint() 4th param (options.canvas) must be an OffscreenCanvas",
|
|
752
|
+
);
|
|
753
|
+
const canvas = options.canvas || new OffscreenCanvas(1, 1),
|
|
754
|
+
scale = options.scale || 1,
|
|
755
|
+
currentContext = _ctx;
|
|
706
756
|
canvas.width = width * scale;
|
|
707
757
|
canvas.height = height * scale;
|
|
708
758
|
_ctx = canvas.getContext("2d");
|
|
@@ -711,138 +761,96 @@
|
|
|
711
761
|
_ctx = currentContext;
|
|
712
762
|
return canvas.transferToImageBitmap();
|
|
713
763
|
},
|
|
714
|
-
/** ADVANCED GRAPHICS API */
|
|
715
|
-
/**
|
|
716
|
-
* Get or set the canvas context 2D
|
|
717
|
-
*
|
|
718
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
719
|
-
* @returns {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
|
|
720
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
|
|
721
|
-
*/
|
|
722
764
|
ctx(context) {
|
|
723
765
|
if (context) {
|
|
724
766
|
_ctx = context;
|
|
725
767
|
}
|
|
726
768
|
return _ctx;
|
|
727
769
|
},
|
|
728
|
-
/**
|
|
729
|
-
* saves the current drawing style settings and transformations
|
|
730
|
-
*
|
|
731
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
|
|
732
|
-
*/
|
|
733
770
|
push() {
|
|
734
771
|
_ctx.save();
|
|
735
772
|
},
|
|
736
|
-
/**
|
|
737
|
-
* restores the drawing style settings and transformations
|
|
738
|
-
*
|
|
739
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
|
|
740
|
-
*/
|
|
741
773
|
pop() {
|
|
742
774
|
_ctx.restore();
|
|
743
775
|
},
|
|
744
|
-
/**
|
|
745
|
-
* Adds a translation to the transformation matrix.
|
|
746
|
-
*
|
|
747
|
-
* @param {number} x
|
|
748
|
-
* @param {number} y
|
|
749
|
-
*/
|
|
750
776
|
translate(x, y) {
|
|
751
|
-
DEV: assert(
|
|
752
|
-
|
|
777
|
+
DEV: assert(
|
|
778
|
+
isNumber(x),
|
|
779
|
+
loggerPrefix + "translate() 1st param must be a number",
|
|
780
|
+
);
|
|
781
|
+
DEV: assert(
|
|
782
|
+
isNumber(y),
|
|
783
|
+
loggerPrefix + "translate() 2nd param must be a number",
|
|
784
|
+
);
|
|
753
785
|
_ctx.translate(~~x, ~~y);
|
|
754
786
|
},
|
|
755
|
-
/**
|
|
756
|
-
* Adds a scaling transformation to the canvas units horizontally and/or vertically.
|
|
757
|
-
*
|
|
758
|
-
* @param {number} x
|
|
759
|
-
* @param {number} [y]
|
|
760
|
-
*/
|
|
761
787
|
scale(x, y) {
|
|
762
|
-
DEV: assert(
|
|
763
|
-
|
|
788
|
+
DEV: assert(
|
|
789
|
+
isNumber(x),
|
|
790
|
+
loggerPrefix + "scale() 1st param must be a number",
|
|
791
|
+
);
|
|
792
|
+
DEV: assert(
|
|
793
|
+
null == y || isNumber(y),
|
|
794
|
+
loggerPrefix + "scale() 2nd param must be a number",
|
|
795
|
+
);
|
|
764
796
|
_ctx.scale(x, y || x);
|
|
765
797
|
},
|
|
766
|
-
/**
|
|
767
|
-
* Adds a rotation to the transformation matrix.
|
|
768
|
-
*
|
|
769
|
-
* @param {number} radians
|
|
770
|
-
*/
|
|
771
798
|
rotate(radians) {
|
|
772
|
-
DEV: assert(
|
|
799
|
+
DEV: assert(
|
|
800
|
+
isNumber(radians),
|
|
801
|
+
loggerPrefix + "rotate() 1st param must be a number",
|
|
802
|
+
);
|
|
773
803
|
_ctx.rotate(radians);
|
|
774
804
|
},
|
|
775
|
-
/**
|
|
776
|
-
* Sets the alpha (opacity) value to apply when drawing new shapes and images
|
|
777
|
-
*
|
|
778
|
-
* @param {number} value float from 0 to 1 (e.g: 0.5 = 50% transparent)
|
|
779
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
|
|
780
|
-
*/
|
|
781
805
|
alpha(value) {
|
|
782
|
-
DEV: assert(
|
|
806
|
+
DEV: assert(
|
|
807
|
+
isNumber(value),
|
|
808
|
+
loggerPrefix + "alpha() 1st param must be a number",
|
|
809
|
+
);
|
|
783
810
|
_ctx.globalAlpha = instance.clamp(value, 0, 1);
|
|
784
811
|
},
|
|
785
|
-
/**
|
|
786
|
-
* Fills the current path with a given color.
|
|
787
|
-
*
|
|
788
|
-
* @param {number} [color=0]
|
|
789
|
-
*/
|
|
790
812
|
fill(color) {
|
|
791
813
|
DEV: assert(
|
|
792
|
-
null == color || isNumber(color) && color >= 0,
|
|
793
|
-
"
|
|
814
|
+
null == color || (isNumber(color) && color >= 0),
|
|
815
|
+
loggerPrefix + "fill() 1st param must be a positive number or zero",
|
|
794
816
|
);
|
|
795
817
|
_ctx.fillStyle = getColor(color);
|
|
796
818
|
_ctx.fill();
|
|
797
819
|
},
|
|
798
|
-
/**
|
|
799
|
-
* Outlines the current path with a given color.
|
|
800
|
-
*
|
|
801
|
-
* @param {number} [color=0]
|
|
802
|
-
*/
|
|
803
820
|
stroke(color) {
|
|
804
821
|
DEV: assert(
|
|
805
|
-
null == color || isNumber(color) && color >= 0,
|
|
806
|
-
"
|
|
822
|
+
null == color || (isNumber(color) && color >= 0),
|
|
823
|
+
loggerPrefix + "stroke() 1st param must be a positive number or zero",
|
|
807
824
|
);
|
|
808
825
|
_ctx.strokeStyle = getColor(color);
|
|
809
826
|
_ctx.stroke();
|
|
810
827
|
},
|
|
811
|
-
/**
|
|
812
|
-
* Turns a path (in the callback) into the current clipping region.
|
|
813
|
-
*
|
|
814
|
-
* @param {clipCallback} callback
|
|
815
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
|
|
816
|
-
*/
|
|
817
828
|
clip(callback) {
|
|
818
829
|
DEV: assert(
|
|
819
830
|
"function" === typeof callback,
|
|
820
|
-
"
|
|
831
|
+
loggerPrefix + "clip() 1st param must be a function",
|
|
821
832
|
);
|
|
822
833
|
beginPath(_ctx);
|
|
823
834
|
callback(_ctx);
|
|
824
835
|
_ctx.clip();
|
|
825
836
|
},
|
|
826
|
-
/** SOUND API */
|
|
827
|
-
/**
|
|
828
|
-
* Play a sound effects using ZzFX library.
|
|
829
|
-
* If the first argument is omitted, plays an default sound.
|
|
830
|
-
*
|
|
831
|
-
* @param {number[]} [zzfxParams] a ZzFX array of params
|
|
832
|
-
* @param {number} [pitchSlide] a value to increment/decrement the pitch
|
|
833
|
-
* @param {number} [volumeFactor] the volume factor
|
|
834
|
-
* @returns {number[] | boolean} The sound that was played or `false`
|
|
835
|
-
*
|
|
836
|
-
* @see https://github.com/KilledByAPixel/ZzFX
|
|
837
|
-
*/
|
|
838
837
|
sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
|
|
839
838
|
DEV: assert(
|
|
840
839
|
null == zzfxParams || Array.isArray(zzfxParams),
|
|
841
|
-
"
|
|
840
|
+
loggerPrefix + "sfx() 1st param must be an array",
|
|
841
|
+
);
|
|
842
|
+
DEV: assert(
|
|
843
|
+
isNumber(pitchSlide),
|
|
844
|
+
loggerPrefix + "sfx() 2nd param must be a number",
|
|
845
|
+
);
|
|
846
|
+
DEV: assert(
|
|
847
|
+
isNumber(volumeFactor),
|
|
848
|
+
loggerPrefix + "sfx() 3rd param must be a number",
|
|
842
849
|
);
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
850
|
+
if (
|
|
851
|
+
!root.zzfxV ||
|
|
852
|
+
(navigator.userActivation && !navigator.userActivation.hasBeenActive)
|
|
853
|
+
) {
|
|
846
854
|
return false;
|
|
847
855
|
}
|
|
848
856
|
zzfxParams = zzfxParams || _defaultSound;
|
|
@@ -854,76 +862,43 @@
|
|
|
854
862
|
zzfx.apply(0, zzfxParams);
|
|
855
863
|
return zzfxParams;
|
|
856
864
|
},
|
|
857
|
-
/**
|
|
858
|
-
* Set the ZzFX's global volume factor.
|
|
859
|
-
* Note: use 0 to mute all sound effects.
|
|
860
|
-
*
|
|
861
|
-
* @param {number} value
|
|
862
|
-
*/
|
|
863
865
|
volume(value) {
|
|
864
866
|
DEV: assert(
|
|
865
867
|
isNumber(value) && value >= 0,
|
|
866
|
-
"
|
|
868
|
+
loggerPrefix + "volume() 1st param must be a positive number or zero",
|
|
867
869
|
);
|
|
868
870
|
root.zzfxV = value;
|
|
869
871
|
},
|
|
870
|
-
/** PLUGINS API */
|
|
871
|
-
/**
|
|
872
|
-
* Returns the canvas
|
|
873
|
-
*
|
|
874
|
-
* @returns {HTMLCanvasElement}
|
|
875
|
-
*/
|
|
876
872
|
canvas: () => _canvas,
|
|
877
|
-
/**
|
|
878
|
-
* Prepares a plugin to be loaded
|
|
879
|
-
*
|
|
880
|
-
* @param {pluginCallback} callback
|
|
881
|
-
*/
|
|
882
873
|
use(callback, config = {}) {
|
|
883
874
|
DEV: assert(
|
|
884
875
|
"function" === typeof callback,
|
|
885
|
-
"
|
|
876
|
+
loggerPrefix + "use() 1st param must be a function",
|
|
886
877
|
);
|
|
887
878
|
DEV: assert(
|
|
888
879
|
"object" === typeof config,
|
|
889
|
-
"
|
|
880
|
+
loggerPrefix + "use() 2nd param must be an object",
|
|
890
881
|
);
|
|
891
882
|
loadPlugin(callback, config);
|
|
892
883
|
},
|
|
893
|
-
/**
|
|
894
|
-
* Add a game event listener
|
|
895
|
-
*
|
|
896
|
-
* @param {string} eventName the event type name
|
|
897
|
-
* @param {Function} callback the function that is called when the event occurs
|
|
898
|
-
* @returns {Function} a function to remove the listener
|
|
899
|
-
*/
|
|
900
884
|
listen(eventName, callback) {
|
|
901
885
|
DEV: assert(
|
|
902
886
|
"string" === typeof eventName,
|
|
903
|
-
"
|
|
887
|
+
loggerPrefix + "listen() 1st param must be a string",
|
|
904
888
|
);
|
|
905
889
|
DEV: assert(
|
|
906
890
|
"function" === typeof callback,
|
|
907
|
-
"
|
|
891
|
+
loggerPrefix + "listen() 2nd param must be a function",
|
|
908
892
|
);
|
|
909
893
|
eventName = lowerCase(eventName);
|
|
910
|
-
_eventListeners[eventName] = _eventListeners[eventName] ||
|
|
894
|
+
_eventListeners[eventName] = _eventListeners[eventName] || new Set();
|
|
911
895
|
_eventListeners[eventName].add(callback);
|
|
912
896
|
return () => _eventListeners[eventName]?.delete(callback);
|
|
913
897
|
},
|
|
914
|
-
/**
|
|
915
|
-
* Call all listeners attached to a game event
|
|
916
|
-
*
|
|
917
|
-
* @param {string} eventName The event type name
|
|
918
|
-
* @param {*} [arg1] any data to be passed over the listeners
|
|
919
|
-
* @param {*} [arg2] any data to be passed over the listeners
|
|
920
|
-
* @param {*} [arg3] any data to be passed over the listeners
|
|
921
|
-
* @param {*} [arg4] any data to be passed over the listeners
|
|
922
|
-
*/
|
|
923
898
|
emit(eventName, arg1, arg2, arg3, arg4) {
|
|
924
899
|
DEV: assert(
|
|
925
900
|
"string" === typeof eventName,
|
|
926
|
-
"
|
|
901
|
+
loggerPrefix + "emit() 1st param must be a string",
|
|
927
902
|
);
|
|
928
903
|
if (_initialized) {
|
|
929
904
|
eventName = lowerCase(eventName);
|
|
@@ -932,43 +907,27 @@
|
|
|
932
907
|
triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
|
|
933
908
|
}
|
|
934
909
|
},
|
|
935
|
-
/**
|
|
936
|
-
* Set new palette colors or restore the default palette.
|
|
937
|
-
*
|
|
938
|
-
* @param {string[]} [colors] an array of colors
|
|
939
|
-
* @param {number} [textColor] the default text color this palette
|
|
940
|
-
*/
|
|
941
910
|
pal(colors, textColor = 3) {
|
|
942
911
|
DEV: assert(
|
|
943
|
-
null == colors || Array.isArray(colors) && colors.length > 0,
|
|
944
|
-
"
|
|
912
|
+
null == colors || (Array.isArray(colors) && colors.length > 0),
|
|
913
|
+
loggerPrefix + "pal() 1st param must be a array of color strings",
|
|
945
914
|
);
|
|
946
915
|
DEV: assert(
|
|
947
916
|
isNumber(textColor) && textColor >= 0,
|
|
948
|
-
"
|
|
917
|
+
loggerPrefix + "pal() 2nd param must be a positive number or zero",
|
|
949
918
|
);
|
|
950
919
|
_colorPalette = colors || defaultPalette;
|
|
951
920
|
_colorPaletteState = [];
|
|
952
921
|
_defaultTextColor = textColor;
|
|
953
922
|
},
|
|
954
|
-
/**
|
|
955
|
-
* Replace the color "a" with color "b".
|
|
956
|
-
*
|
|
957
|
-
* If called without arguments, reset the current palette.
|
|
958
|
-
*
|
|
959
|
-
* Note: `palc()` don't affect drawings made with `image()`.
|
|
960
|
-
*
|
|
961
|
-
* @param {number?} a
|
|
962
|
-
* @param {number?} b
|
|
963
|
-
*/
|
|
964
923
|
palc(a, b) {
|
|
965
924
|
DEV: assert(
|
|
966
|
-
null == a || isNumber(a) && a >= 0,
|
|
967
|
-
"
|
|
925
|
+
null == a || (isNumber(a) && a >= 0),
|
|
926
|
+
loggerPrefix + "palc() 1st param must be a positive number",
|
|
968
927
|
);
|
|
969
928
|
DEV: assert(
|
|
970
929
|
isNumber(a) ? isNumber(b) && b >= 0 : null == b,
|
|
971
|
-
"
|
|
930
|
+
loggerPrefix + "palc() 2nd param must be a positive number",
|
|
972
931
|
);
|
|
973
932
|
if (a == null) {
|
|
974
933
|
_colorPaletteState = [];
|
|
@@ -976,17 +935,15 @@
|
|
|
976
935
|
_colorPaletteState[a] = b;
|
|
977
936
|
}
|
|
978
937
|
},
|
|
979
|
-
/**
|
|
980
|
-
* Define or update a instance property.
|
|
981
|
-
*
|
|
982
|
-
* @param {string} key
|
|
983
|
-
* @param {*} value
|
|
984
|
-
*/
|
|
985
938
|
def(key, value) {
|
|
986
|
-
DEV: assert(
|
|
939
|
+
DEV: assert(
|
|
940
|
+
"string" === typeof key,
|
|
941
|
+
loggerPrefix + "def() 1st param must be a string",
|
|
942
|
+
);
|
|
987
943
|
DEV: if (null == value) {
|
|
988
944
|
console.warn(
|
|
989
|
-
|
|
945
|
+
loggerPrefix +
|
|
946
|
+
`def() changed the key "${key}" to null (previous value was ${instance[key]})`,
|
|
990
947
|
);
|
|
991
948
|
}
|
|
992
949
|
instance[key] = value;
|
|
@@ -994,110 +951,66 @@
|
|
|
994
951
|
root[key] = value;
|
|
995
952
|
}
|
|
996
953
|
},
|
|
997
|
-
/**
|
|
998
|
-
* The scale of the game's delta time (dt).
|
|
999
|
-
* Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
|
|
1000
|
-
* A value of 0 freezes time and is effectively equivalent to pausing.
|
|
1001
|
-
*
|
|
1002
|
-
* @param {number} value
|
|
1003
|
-
*/
|
|
1004
954
|
timescale(value) {
|
|
1005
955
|
DEV: assert(
|
|
1006
956
|
isNumber(value) && value >= 0,
|
|
1007
|
-
|
|
957
|
+
loggerPrefix +
|
|
958
|
+
"timescale() 1st param must be a positive number or zero",
|
|
1008
959
|
);
|
|
1009
960
|
_timeScale = value;
|
|
1010
961
|
},
|
|
1011
|
-
/**
|
|
1012
|
-
* Set the target FPS (frames per second).
|
|
1013
|
-
*
|
|
1014
|
-
* @param {number} value
|
|
1015
|
-
*/
|
|
1016
962
|
framerate(value) {
|
|
1017
963
|
DEV: assert(
|
|
1018
964
|
isNumber(value) && value >= 1,
|
|
1019
|
-
"
|
|
965
|
+
loggerPrefix + "framerate() 1st param must be a positive number",
|
|
1020
966
|
);
|
|
1021
967
|
_fpsInterval = 1e3 / ~~value;
|
|
1022
968
|
},
|
|
1023
|
-
/**
|
|
1024
|
-
* Returns information about the engine instance.
|
|
1025
|
-
*
|
|
1026
|
-
* @param {number|string} index
|
|
1027
|
-
* @returns {any}
|
|
1028
|
-
*/
|
|
1029
969
|
stat(index) {
|
|
1030
970
|
DEV: assert(
|
|
1031
971
|
isNumber(index) || "string" === typeof index,
|
|
1032
|
-
"
|
|
972
|
+
loggerPrefix + "stat() 1st param must be a number or string",
|
|
1033
973
|
);
|
|
1034
974
|
const internals = [
|
|
1035
|
-
// 0
|
|
1036
975
|
settings,
|
|
1037
|
-
// 1
|
|
1038
976
|
_initialized,
|
|
1039
|
-
// 2
|
|
1040
977
|
_fpsInterval / 1e3,
|
|
1041
|
-
// 3
|
|
1042
978
|
_canvasScale,
|
|
1043
|
-
// 4
|
|
1044
979
|
_eventListeners,
|
|
1045
|
-
// 5
|
|
1046
980
|
_colorPalette,
|
|
1047
|
-
// 6
|
|
1048
981
|
_defaultSound,
|
|
1049
|
-
// 7
|
|
1050
982
|
_timeScale,
|
|
1051
|
-
// 8
|
|
1052
983
|
root.zzfxV,
|
|
1053
|
-
// 9
|
|
1054
984
|
_rngSeed,
|
|
1055
|
-
// 10
|
|
1056
985
|
_fontSize,
|
|
1057
|
-
// 11
|
|
1058
986
|
_fontFamily,
|
|
1059
|
-
// 12
|
|
1060
987
|
_colorPaletteState,
|
|
1061
|
-
|
|
1062
|
-
_fontLineHeight
|
|
988
|
+
_fontLineHeight,
|
|
1063
989
|
];
|
|
1064
990
|
const data = { index, value: internals[index] };
|
|
1065
991
|
instance.emit("stat", data);
|
|
1066
992
|
return data.value;
|
|
1067
993
|
},
|
|
1068
|
-
/**
|
|
1069
|
-
* Pauses the engine loop (update & draw).
|
|
1070
|
-
*/
|
|
1071
994
|
pause() {
|
|
1072
995
|
_paused = true;
|
|
1073
996
|
cancelAnimationFrame(_rafid);
|
|
1074
997
|
},
|
|
1075
|
-
/**
|
|
1076
|
-
* Resumes (if paused) the engine loop.
|
|
1077
|
-
*/
|
|
1078
998
|
resume() {
|
|
1079
999
|
DEV: assert(
|
|
1080
1000
|
_initialized,
|
|
1081
|
-
|
|
1001
|
+
loggerPrefix +
|
|
1002
|
+
'resume() cannot be called before the "init" event and neither after the quit() function',
|
|
1082
1003
|
);
|
|
1083
1004
|
if (_initialized && _paused) {
|
|
1084
1005
|
_paused = false;
|
|
1085
1006
|
_accumulated = _fpsInterval;
|
|
1086
|
-
_lastFrameTime =
|
|
1007
|
+
_lastFrameTime = perf.now();
|
|
1087
1008
|
_rafid = raf(drawFrame);
|
|
1088
1009
|
}
|
|
1089
1010
|
},
|
|
1090
|
-
/**
|
|
1091
|
-
* Returns `true` if the engine loop is paused.
|
|
1092
|
-
*
|
|
1093
|
-
* @returns {boolean}
|
|
1094
|
-
*/
|
|
1095
1011
|
paused() {
|
|
1096
1012
|
return _paused;
|
|
1097
1013
|
},
|
|
1098
|
-
/**
|
|
1099
|
-
* Shutdown the litecanvas instance and remove all event listeners.
|
|
1100
|
-
*/
|
|
1101
1014
|
quit() {
|
|
1102
1015
|
instance.emit("quit");
|
|
1103
1016
|
instance.pause();
|
|
@@ -1112,8 +1025,10 @@
|
|
|
1112
1025
|
}
|
|
1113
1026
|
delete root.ENGINE;
|
|
1114
1027
|
}
|
|
1115
|
-
DEV: console.warn(
|
|
1116
|
-
|
|
1028
|
+
DEV: console.warn(
|
|
1029
|
+
loggerPrefix + "quit() terminated a Litecanvas instance.",
|
|
1030
|
+
);
|
|
1031
|
+
},
|
|
1117
1032
|
};
|
|
1118
1033
|
for (const k of _mathFunctions.split(",")) {
|
|
1119
1034
|
instance[k] = math[k];
|
|
@@ -1123,138 +1038,72 @@
|
|
|
1123
1038
|
on(root, "resize", resizeCanvas);
|
|
1124
1039
|
}
|
|
1125
1040
|
if (settings.tapEvents) {
|
|
1126
|
-
const _getXY = (
|
|
1127
|
-
/**
|
|
1128
|
-
* @param {MouseEvent | Touch} ev
|
|
1129
|
-
*/
|
|
1130
|
-
(ev) => [
|
|
1041
|
+
const _getXY = (ev) => [
|
|
1131
1042
|
(ev.pageX - _canvas.offsetLeft) / _canvasScale,
|
|
1132
|
-
(ev.pageY - _canvas.offsetTop) / _canvasScale
|
|
1133
|
-
]
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
* @param {number} [x]
|
|
1138
|
-
* @param {number} [y]
|
|
1139
|
-
*/
|
|
1140
|
-
(id, x, y) => {
|
|
1141
|
-
const tap = {
|
|
1142
|
-
// current x
|
|
1143
|
-
x,
|
|
1144
|
-
// current y
|
|
1145
|
-
y,
|
|
1146
|
-
// initial x
|
|
1147
|
-
xi: x,
|
|
1148
|
-
// initial y
|
|
1149
|
-
yi: y,
|
|
1150
|
-
// timestamp
|
|
1151
|
-
t: Date.now()
|
|
1152
|
-
};
|
|
1043
|
+
(ev.pageY - _canvas.offsetTop) / _canvasScale,
|
|
1044
|
+
],
|
|
1045
|
+
_taps = new Map(),
|
|
1046
|
+
_registerTap = (id, x, y) => {
|
|
1047
|
+
const tap = { x, y, xi: x, yi: y, t: perf.now() };
|
|
1153
1048
|
_taps.set(id, tap);
|
|
1154
1049
|
return tap;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
/**
|
|
1158
|
-
* @param {number} id
|
|
1159
|
-
* @param {number} x
|
|
1160
|
-
* @param {number} y
|
|
1161
|
-
*/
|
|
1162
|
-
(id, x, y) => {
|
|
1050
|
+
},
|
|
1051
|
+
_updateTap = (id, x, y) => {
|
|
1163
1052
|
const tap = _taps.get(id) || _registerTap(id);
|
|
1164
1053
|
tap.x = x;
|
|
1165
1054
|
tap.y = y;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
/**
|
|
1169
|
-
* @param {{t: number}} tap
|
|
1170
|
-
*/
|
|
1171
|
-
(tap) => tap && Date.now() - tap.t <= 300
|
|
1172
|
-
);
|
|
1055
|
+
},
|
|
1056
|
+
_checkTapped = (tap) => tap && perf.now() - tap.t <= 300;
|
|
1173
1057
|
let _pressingMouse = false;
|
|
1174
|
-
on(
|
|
1175
|
-
|
|
1176
|
-
"mousedown",
|
|
1177
|
-
/**
|
|
1178
|
-
* @param {MouseEvent} ev
|
|
1179
|
-
*/
|
|
1180
|
-
(ev) => {
|
|
1181
|
-
if (ev.button === 0) {
|
|
1182
|
-
preventDefault(ev);
|
|
1183
|
-
const [x, y] = _getXY(ev);
|
|
1184
|
-
instance.emit("tap", x, y, 0);
|
|
1185
|
-
_registerTap(0, x, y);
|
|
1186
|
-
_pressingMouse = true;
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
);
|
|
1190
|
-
on(
|
|
1191
|
-
_canvas,
|
|
1192
|
-
"mouseup",
|
|
1193
|
-
/**
|
|
1194
|
-
* @param {MouseEvent} ev
|
|
1195
|
-
*/
|
|
1196
|
-
(ev) => {
|
|
1197
|
-
if (ev.button === 0) {
|
|
1198
|
-
preventDefault(ev);
|
|
1199
|
-
const tap = _taps.get(0);
|
|
1200
|
-
const [x, y] = _getXY(ev);
|
|
1201
|
-
if (_checkTapped(tap)) {
|
|
1202
|
-
instance.emit("tapped", tap.xi, tap.yi, 0);
|
|
1203
|
-
}
|
|
1204
|
-
instance.emit("untap", x, y, 0);
|
|
1205
|
-
_taps.delete(0);
|
|
1206
|
-
_pressingMouse = false;
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
);
|
|
1210
|
-
on(
|
|
1211
|
-
root,
|
|
1212
|
-
"mousemove",
|
|
1213
|
-
/**
|
|
1214
|
-
* @param {MouseEvent} ev
|
|
1215
|
-
*/
|
|
1216
|
-
(ev) => {
|
|
1058
|
+
on(_canvas, "mousedown", (ev) => {
|
|
1059
|
+
if (ev.button === 0) {
|
|
1217
1060
|
preventDefault(ev);
|
|
1218
1061
|
const [x, y] = _getXY(ev);
|
|
1219
|
-
instance.
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
instance.emit("tapping", x, y, 0);
|
|
1223
|
-
_updateTap(0, x, y);
|
|
1062
|
+
instance.emit("tap", x, y, 0);
|
|
1063
|
+
_registerTap(0, x, y);
|
|
1064
|
+
_pressingMouse = true;
|
|
1224
1065
|
}
|
|
1225
|
-
);
|
|
1226
|
-
on(
|
|
1227
|
-
|
|
1228
|
-
"touchstart",
|
|
1229
|
-
/**
|
|
1230
|
-
* @param {TouchEvent} ev
|
|
1231
|
-
*/
|
|
1232
|
-
(ev) => {
|
|
1066
|
+
});
|
|
1067
|
+
on(_canvas, "mouseup", (ev) => {
|
|
1068
|
+
if (ev.button === 0) {
|
|
1233
1069
|
preventDefault(ev);
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
instance.emit("
|
|
1238
|
-
_registerTap(touch.identifier + 1, x, y);
|
|
1070
|
+
const tap = _taps.get(0);
|
|
1071
|
+
const [x, y] = _getXY(ev);
|
|
1072
|
+
if (_checkTapped(tap)) {
|
|
1073
|
+
instance.emit("tapped", tap.xi, tap.yi, 0);
|
|
1239
1074
|
}
|
|
1075
|
+
instance.emit("untap", x, y, 0);
|
|
1076
|
+
_taps.delete(0);
|
|
1077
|
+
_pressingMouse = false;
|
|
1240
1078
|
}
|
|
1241
|
-
);
|
|
1242
|
-
on(
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
(
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1079
|
+
});
|
|
1080
|
+
on(root, "mousemove", (ev) => {
|
|
1081
|
+
preventDefault(ev);
|
|
1082
|
+
const [x, y] = _getXY(ev);
|
|
1083
|
+
instance.def("MX", x);
|
|
1084
|
+
instance.def("MY", y);
|
|
1085
|
+
if (!_pressingMouse) return;
|
|
1086
|
+
instance.emit("tapping", x, y, 0);
|
|
1087
|
+
_updateTap(0, x, y);
|
|
1088
|
+
});
|
|
1089
|
+
on(_canvas, "touchstart", (ev) => {
|
|
1090
|
+
preventDefault(ev);
|
|
1091
|
+
const touches = ev.changedTouches;
|
|
1092
|
+
for (const touch of touches) {
|
|
1093
|
+
const [x, y] = _getXY(touch);
|
|
1094
|
+
instance.emit("tap", x, y, touch.identifier + 1);
|
|
1095
|
+
_registerTap(touch.identifier + 1, x, y);
|
|
1256
1096
|
}
|
|
1257
|
-
);
|
|
1097
|
+
});
|
|
1098
|
+
on(_canvas, "touchmove", (ev) => {
|
|
1099
|
+
preventDefault(ev);
|
|
1100
|
+
const touches = ev.changedTouches;
|
|
1101
|
+
for (const touch of touches) {
|
|
1102
|
+
const [x, y] = _getXY(touch);
|
|
1103
|
+
instance.emit("tapping", x, y, touch.identifier + 1);
|
|
1104
|
+
_updateTap(touch.identifier + 1, x, y);
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1258
1107
|
const _touchEndHandler = (ev) => {
|
|
1259
1108
|
preventDefault(ev);
|
|
1260
1109
|
const existing = [];
|
|
@@ -1283,11 +1132,13 @@
|
|
|
1283
1132
|
});
|
|
1284
1133
|
}
|
|
1285
1134
|
if (settings.keyboardEvents) {
|
|
1286
|
-
const _keysDown =
|
|
1287
|
-
const _keysPress =
|
|
1135
|
+
const _keysDown = new Set();
|
|
1136
|
+
const _keysPress = new Set();
|
|
1288
1137
|
const keyCheck = (keySet, key = "") => {
|
|
1289
1138
|
key = lowerCase(key);
|
|
1290
|
-
return !key
|
|
1139
|
+
return !key
|
|
1140
|
+
? keySet.size > 0
|
|
1141
|
+
: keySet.has("space" === key ? " " : key);
|
|
1291
1142
|
};
|
|
1292
1143
|
let _lastKey = "";
|
|
1293
1144
|
on(root, "keydown", (event) => {
|
|
@@ -1303,41 +1154,23 @@
|
|
|
1303
1154
|
});
|
|
1304
1155
|
on(root, "blur", () => _keysDown.clear());
|
|
1305
1156
|
instance.listen("after:update", () => _keysPress.clear());
|
|
1306
|
-
instance.def(
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
(key)
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
* @param {string} [key]
|
|
1324
|
-
* @returns {boolean}
|
|
1325
|
-
*/
|
|
1326
|
-
(key) => {
|
|
1327
|
-
DEV: assert(
|
|
1328
|
-
null == key || "string" === typeof key,
|
|
1329
|
-
"[litecanvas] iskeypressed() 1st param must be a string or undefined"
|
|
1330
|
-
);
|
|
1331
|
-
return keyCheck(_keysPress, key);
|
|
1332
|
-
}
|
|
1333
|
-
);
|
|
1334
|
-
instance.def(
|
|
1335
|
-
"lastkey",
|
|
1336
|
-
/**
|
|
1337
|
-
* @returns {string}
|
|
1338
|
-
*/
|
|
1339
|
-
() => _lastKey
|
|
1340
|
-
);
|
|
1157
|
+
instance.def("iskeydown", (key) => {
|
|
1158
|
+
DEV: assert(
|
|
1159
|
+
null == key || "string" === typeof key,
|
|
1160
|
+
loggerPrefix +
|
|
1161
|
+
"iskeydown() 1st param must be a string or undefined",
|
|
1162
|
+
);
|
|
1163
|
+
return keyCheck(_keysDown, key);
|
|
1164
|
+
});
|
|
1165
|
+
instance.def("iskeypressed", (key) => {
|
|
1166
|
+
DEV: assert(
|
|
1167
|
+
null == key || "string" === typeof key,
|
|
1168
|
+
loggerPrefix +
|
|
1169
|
+
"iskeypressed() 1st param must be a string or undefined",
|
|
1170
|
+
);
|
|
1171
|
+
return keyCheck(_keysPress, key);
|
|
1172
|
+
});
|
|
1173
|
+
instance.def("lastkey", () => _lastKey);
|
|
1341
1174
|
}
|
|
1342
1175
|
_initialized = true;
|
|
1343
1176
|
instance.resume();
|
|
@@ -1345,7 +1178,7 @@
|
|
|
1345
1178
|
}
|
|
1346
1179
|
function drawFrame() {
|
|
1347
1180
|
_rafid = raf(drawFrame);
|
|
1348
|
-
let now =
|
|
1181
|
+
let now = perf.now();
|
|
1349
1182
|
let updated = 0;
|
|
1350
1183
|
let frameTime = now - _lastFrameTime;
|
|
1351
1184
|
_lastFrameTime = now;
|
|
@@ -1353,7 +1186,7 @@
|
|
|
1353
1186
|
while (_accumulated >= _fpsInterval) {
|
|
1354
1187
|
updated++;
|
|
1355
1188
|
_accumulated -= _fpsInterval;
|
|
1356
|
-
let dt = _fpsInterval / 1e3 * _timeScale;
|
|
1189
|
+
let dt = (_fpsInterval / 1e3) * _timeScale;
|
|
1357
1190
|
instance.emit("update", dt, updated);
|
|
1358
1191
|
instance.def("T", instance.T + dt);
|
|
1359
1192
|
}
|
|
@@ -1362,7 +1195,10 @@
|
|
|
1362
1195
|
if (updated > 1) {
|
|
1363
1196
|
_accumulated = 0;
|
|
1364
1197
|
DEV: console.warn(
|
|
1365
|
-
|
|
1198
|
+
loggerPrefix +
|
|
1199
|
+
"the last frame updated " +
|
|
1200
|
+
updated +
|
|
1201
|
+
" times. This can drop the FPS if it keeps happening.",
|
|
1366
1202
|
);
|
|
1367
1203
|
}
|
|
1368
1204
|
}
|
|
@@ -1372,7 +1208,8 @@
|
|
|
1372
1208
|
_canvas = document.querySelector(settings.canvas);
|
|
1373
1209
|
DEV: assert(
|
|
1374
1210
|
null != _canvas,
|
|
1375
|
-
|
|
1211
|
+
loggerPrefix +
|
|
1212
|
+
'litecanvas() option "canvas" is an invalid CSS selector',
|
|
1376
1213
|
);
|
|
1377
1214
|
} else {
|
|
1378
1215
|
_canvas = settings.canvas;
|
|
@@ -1380,7 +1217,8 @@
|
|
|
1380
1217
|
_canvas = _canvas || document.createElement("canvas");
|
|
1381
1218
|
DEV: assert(
|
|
1382
1219
|
"CANVAS" === _canvas.tagName,
|
|
1383
|
-
|
|
1220
|
+
loggerPrefix +
|
|
1221
|
+
'litecanvas() option "canvas" should be a canvas element or string (CSS selector)',
|
|
1384
1222
|
);
|
|
1385
1223
|
_ctx = _canvas.getContext("2d");
|
|
1386
1224
|
on(_canvas, "click", () => focus());
|
|
@@ -1393,18 +1231,25 @@
|
|
|
1393
1231
|
}
|
|
1394
1232
|
function resizeCanvas() {
|
|
1395
1233
|
DEV: assert(
|
|
1396
|
-
null == settings.width ||
|
|
1397
|
-
|
|
1234
|
+
null == settings.width ||
|
|
1235
|
+
(isNumber(settings.width) && settings.width > 0),
|
|
1236
|
+
loggerPrefix +
|
|
1237
|
+
'litecanvas() option "width" should be a positive number when defined',
|
|
1398
1238
|
);
|
|
1399
1239
|
DEV: assert(
|
|
1400
|
-
null == settings.height ||
|
|
1401
|
-
|
|
1240
|
+
null == settings.height ||
|
|
1241
|
+
(isNumber(settings.height) && settings.height > 0),
|
|
1242
|
+
loggerPrefix +
|
|
1243
|
+
'litecanvas() option "height" should be a positive number when defined',
|
|
1402
1244
|
);
|
|
1403
1245
|
DEV: assert(
|
|
1404
|
-
null == settings.height || settings.width > 0 && settings.height > 0,
|
|
1405
|
-
|
|
1246
|
+
null == settings.height || (settings.width > 0 && settings.height > 0),
|
|
1247
|
+
loggerPrefix +
|
|
1248
|
+
'litecanvas() option "width" is required when the option "height" is defined',
|
|
1406
1249
|
);
|
|
1407
|
-
const width = settings.width > 0 ? settings.width : innerWidth,
|
|
1250
|
+
const width = settings.width > 0 ? settings.width : innerWidth,
|
|
1251
|
+
height =
|
|
1252
|
+
settings.width > 0 ? settings.height || settings.width : innerHeight;
|
|
1408
1253
|
instance.def("W", width);
|
|
1409
1254
|
instance.def("H", height);
|
|
1410
1255
|
_canvas.width = width;
|
|
@@ -1416,7 +1261,8 @@
|
|
|
1416
1261
|
_canvas.style.margin = "auto";
|
|
1417
1262
|
}
|
|
1418
1263
|
_canvasScale = math.min(innerWidth / width, innerHeight / height);
|
|
1419
|
-
_canvasScale =
|
|
1264
|
+
_canvasScale =
|
|
1265
|
+
maxScale > 1 && _canvasScale > maxScale ? maxScale : _canvasScale;
|
|
1420
1266
|
_canvas.style.width = width * _canvasScale + "px";
|
|
1421
1267
|
_canvas.style.height = height * _canvasScale + "px";
|
|
1422
1268
|
}
|
|
@@ -1434,7 +1280,8 @@
|
|
|
1434
1280
|
const pluginData = callback(instance, config);
|
|
1435
1281
|
DEV: assert(
|
|
1436
1282
|
null == pluginData || "object" === typeof pluginData,
|
|
1437
|
-
|
|
1283
|
+
loggerPrefix +
|
|
1284
|
+
"litecanvas() plugins should return an object or nothing",
|
|
1438
1285
|
);
|
|
1439
1286
|
for (const key in pluginData) {
|
|
1440
1287
|
instance.def(key, pluginData[key]);
|
|
@@ -1451,13 +1298,13 @@
|
|
|
1451
1298
|
Object.assign(root, instance);
|
|
1452
1299
|
root.ENGINE = instance;
|
|
1453
1300
|
}
|
|
1454
|
-
DEV: console.info(`
|
|
1455
|
-
DEV: console.debug(`
|
|
1301
|
+
DEV: console.info(loggerPrefix + `version ${version} started`);
|
|
1302
|
+
DEV: console.debug(loggerPrefix + `litecanvas() options =`, settings);
|
|
1456
1303
|
setupCanvas();
|
|
1457
1304
|
const source = settings.loop ? settings.loop : root;
|
|
1458
1305
|
for (const event of _coreEvents.split(",")) {
|
|
1459
1306
|
DEV: if (root === source && source[event]) {
|
|
1460
|
-
console.info(`
|
|
1307
|
+
console.info(loggerPrefix + `using window.${event}()`);
|
|
1461
1308
|
}
|
|
1462
1309
|
if (source[event]) instance.listen(event, source[event]);
|
|
1463
1310
|
}
|
|
@@ -1468,7 +1315,5 @@
|
|
|
1468
1315
|
}
|
|
1469
1316
|
return instance;
|
|
1470
1317
|
}
|
|
1471
|
-
|
|
1472
|
-
// src/web.js
|
|
1473
1318
|
window.litecanvas = litecanvas;
|
|
1474
1319
|
})();
|