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.js
CHANGED
|
@@ -1,103 +1,187 @@
|
|
|
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/index.js
|
|
17
115
|
function litecanvas(settings = {}) {
|
|
18
|
-
const root = window,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
116
|
+
const root = window,
|
|
117
|
+
math = Math,
|
|
118
|
+
perf = performance,
|
|
119
|
+
TWO_PI = math.PI * 2,
|
|
120
|
+
loggerPrefix = "[Litecanvas] ",
|
|
121
|
+
raf = requestAnimationFrame,
|
|
122
|
+
_browserEventListeners = [],
|
|
123
|
+
on = (elem, evt, callback) => {
|
|
124
|
+
elem.addEventListener(evt, callback, false);
|
|
125
|
+
_browserEventListeners.push(() =>
|
|
126
|
+
elem.removeEventListener(evt, callback, false),
|
|
127
|
+
);
|
|
128
|
+
},
|
|
129
|
+
lowerCase = (str) => str.toLowerCase(),
|
|
130
|
+
preventDefault = (ev) => ev.preventDefault(),
|
|
131
|
+
beginPath = (c) => c.beginPath(),
|
|
132
|
+
isNumber = Number.isFinite,
|
|
133
|
+
zzfx = setupZzFX(root),
|
|
134
|
+
defaults = {
|
|
135
|
+
width: null,
|
|
136
|
+
height: null,
|
|
137
|
+
autoscale: true,
|
|
138
|
+
canvas: null,
|
|
139
|
+
global: true,
|
|
140
|
+
loop: null,
|
|
141
|
+
tapEvents: true,
|
|
142
|
+
keyboardEvents: true,
|
|
143
|
+
};
|
|
31
144
|
settings = Object.assign(defaults, settings);
|
|
32
|
-
let _initialized = false,
|
|
145
|
+
let _initialized = false,
|
|
146
|
+
_paused = true,
|
|
147
|
+
_canvas,
|
|
148
|
+
_canvasScale = 1,
|
|
149
|
+
_ctx,
|
|
150
|
+
_outline_fix = 0.5,
|
|
151
|
+
_timeScale = 1,
|
|
152
|
+
_lastFrameTime,
|
|
153
|
+
_fpsInterval = 1e3 / 60,
|
|
154
|
+
_accumulated,
|
|
155
|
+
_rafid,
|
|
156
|
+
_defaultTextColor = 3,
|
|
157
|
+
_fontFamily = "sans-serif",
|
|
158
|
+
_fontSize = 20,
|
|
159
|
+
_fontLineHeight = 1.2,
|
|
160
|
+
_rngSeed = Date.now(),
|
|
161
|
+
_colorPalette = defaultPalette,
|
|
162
|
+
_colorPaletteState = [],
|
|
163
|
+
_defaultSound = [0.5, 0, 1750, , , 0.3, 1, , , , 600, 0.1],
|
|
164
|
+
_coreEvents = "init,update,draw,tap,untap,tapping,tapped,resized",
|
|
165
|
+
_mathFunctions =
|
|
166
|
+
"PI,sin,cos,atan2,hypot,tan,abs,ceil,floor,trunc,min,max,pow,sqrt,sign,exp",
|
|
167
|
+
_eventListeners = {};
|
|
33
168
|
const instance = {
|
|
34
|
-
/** @type {number} */
|
|
35
169
|
W: 0,
|
|
36
|
-
/** @type {number} */
|
|
37
170
|
H: 0,
|
|
38
|
-
/** @type {number} */
|
|
39
171
|
T: 0,
|
|
40
|
-
/** @type {number} */
|
|
41
172
|
MX: -1,
|
|
42
|
-
/** @type {number} */
|
|
43
173
|
MY: -1,
|
|
44
|
-
/** MATH API */
|
|
45
|
-
/**
|
|
46
|
-
* Twice the value of the mathematical constant PI (π).
|
|
47
|
-
* Approximately 6.28318
|
|
48
|
-
*
|
|
49
|
-
* Note: TWO_PI radians equals 360°, PI radians equals 180°,
|
|
50
|
-
* HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
|
|
51
|
-
*
|
|
52
|
-
* @type {number}
|
|
53
|
-
*/
|
|
54
174
|
TWO_PI,
|
|
55
|
-
/**
|
|
56
|
-
* Half the value of the mathematical constant PI (π).
|
|
57
|
-
* Approximately 1.57079
|
|
58
|
-
*
|
|
59
|
-
* @type {number}
|
|
60
|
-
*/
|
|
61
175
|
HALF_PI: TWO_PI / 4,
|
|
62
|
-
/**
|
|
63
|
-
* Calculates a linear (interpolation) value over t%.
|
|
64
|
-
*
|
|
65
|
-
* @param {number} start
|
|
66
|
-
* @param {number} end
|
|
67
|
-
* @param {number} t The progress in percentage, where 0 = 0% and 1 = 100%.
|
|
68
|
-
* @returns {number} The unterpolated value
|
|
69
|
-
* @tutorial https://gamedev.net/tutorials/programming/general-and-gameplay-programming/a-brief-introduction-to-lerp-r4954/
|
|
70
|
-
*/
|
|
71
176
|
lerp: (start, end, t) => {
|
|
72
177
|
return start + t * (end - start);
|
|
73
178
|
},
|
|
74
|
-
/**
|
|
75
|
-
* Convert degrees to radians
|
|
76
|
-
*
|
|
77
|
-
* @param {number} degs
|
|
78
|
-
* @returns {number} the value in radians
|
|
79
|
-
*/
|
|
80
179
|
deg2rad: (degs) => {
|
|
81
|
-
return math.PI / 180 * degs;
|
|
180
|
+
return (math.PI / 180) * degs;
|
|
82
181
|
},
|
|
83
|
-
/**
|
|
84
|
-
* Convert radians to degrees
|
|
85
|
-
*
|
|
86
|
-
* @param {number} rads
|
|
87
|
-
* @returns {number} the value in degrees
|
|
88
|
-
*/
|
|
89
182
|
rad2deg: (rads) => {
|
|
90
|
-
return 180 / math.PI * rads;
|
|
183
|
+
return (180 / math.PI) * rads;
|
|
91
184
|
},
|
|
92
|
-
/**
|
|
93
|
-
* Returns the rounded value of an number to optional precision (number of digits after the decimal point).
|
|
94
|
-
*
|
|
95
|
-
* Note: precision is optional but must be >= 0
|
|
96
|
-
*
|
|
97
|
-
* @param {number} n number to round.
|
|
98
|
-
* @param {number} [precision] number of decimal digits to round to, default is 0.
|
|
99
|
-
* @returns {number} rounded number.
|
|
100
|
-
*/
|
|
101
185
|
round: (n, precision = 0) => {
|
|
102
186
|
if (!precision) {
|
|
103
187
|
return math.round(n);
|
|
@@ -105,131 +189,45 @@
|
|
|
105
189
|
const multiplier = 10 ** precision;
|
|
106
190
|
return math.round(n * multiplier) / multiplier;
|
|
107
191
|
},
|
|
108
|
-
/**
|
|
109
|
-
* Constrains a number between `min` and `max`.
|
|
110
|
-
*
|
|
111
|
-
* @param {number} value
|
|
112
|
-
* @param {number} min
|
|
113
|
-
* @param {number} max
|
|
114
|
-
* @returns {number}
|
|
115
|
-
*/
|
|
116
192
|
clamp: (value, min, max) => {
|
|
117
193
|
if (value < min) return min;
|
|
118
194
|
if (value > max) return max;
|
|
119
195
|
return value;
|
|
120
196
|
},
|
|
121
|
-
/**
|
|
122
|
-
* Calculates the distance between a point (x1, y1) to another (x2, y2).
|
|
123
|
-
*
|
|
124
|
-
* @param {number} x1
|
|
125
|
-
* @param {number} y1
|
|
126
|
-
* @param {number} x2
|
|
127
|
-
* @param {number} y2
|
|
128
|
-
* @returns {number}
|
|
129
|
-
*/
|
|
130
197
|
dist: (x1, y1, x2, y2) => {
|
|
131
198
|
return math.hypot(x2 - x1, y2 - y1);
|
|
132
199
|
},
|
|
133
|
-
/**
|
|
134
|
-
* Wraps a number between `min` (inclusive) and `max` (exclusive).
|
|
135
|
-
*
|
|
136
|
-
* @param {number} value
|
|
137
|
-
* @param {number} min
|
|
138
|
-
* @param {number} max
|
|
139
|
-
* @returns {number}
|
|
140
|
-
*/
|
|
141
200
|
wrap: (value, min, max) => {
|
|
142
201
|
return value - (max - min) * math.floor((value - min) / (max - min));
|
|
143
202
|
},
|
|
144
|
-
/**
|
|
145
|
-
* Re-maps a number from one range to another.
|
|
146
|
-
*
|
|
147
|
-
* @param {number} value the value to be remapped.
|
|
148
|
-
* @param {number} start1 lower bound of the value's current range.
|
|
149
|
-
* @param {number} stop1 upper bound of the value's current range.
|
|
150
|
-
* @param {number} start2 lower bound of the value's target range.
|
|
151
|
-
* @param {number} stop2 upper bound of the value's target range.
|
|
152
|
-
* @param {boolean} [withinBounds=false] constrain the value to the newly mapped range
|
|
153
|
-
* @returns {number} the remapped number
|
|
154
|
-
*/
|
|
155
203
|
map(value, start1, stop1, start2, stop2, withinBounds) {
|
|
156
|
-
const result =
|
|
204
|
+
const result =
|
|
205
|
+
((value - start1) / (stop1 - start1)) * (stop2 - start2) + start2;
|
|
157
206
|
return withinBounds ? instance.clamp(result, start2, stop2) : result;
|
|
158
207
|
},
|
|
159
|
-
/**
|
|
160
|
-
* Maps a number from one range to a value between 0 and 1.
|
|
161
|
-
* Identical to `map(value, min, max, 0, 1)`.
|
|
162
|
-
* Note: Numbers outside the range are not clamped to 0 and 1.
|
|
163
|
-
*
|
|
164
|
-
* @param {number} value
|
|
165
|
-
* @param {number} start
|
|
166
|
-
* @param {number} stop
|
|
167
|
-
* @returns {number} the normalized number.
|
|
168
|
-
*/
|
|
169
208
|
norm: (value, start, stop) => {
|
|
170
209
|
return instance.map(value, start, stop, 0, 1);
|
|
171
210
|
},
|
|
172
|
-
/** RNG API */
|
|
173
|
-
/**
|
|
174
|
-
* Generates a pseudorandom float between min (inclusive) and max (exclusive)
|
|
175
|
-
* using the Linear Congruential Generator (LCG) algorithm.
|
|
176
|
-
*
|
|
177
|
-
* @param {number} [min=0.0]
|
|
178
|
-
* @param {number} [max=1.0]
|
|
179
|
-
* @returns {number} the random number
|
|
180
|
-
*/
|
|
181
211
|
rand: (min = 0, max = 1) => {
|
|
182
212
|
const a = 1664525;
|
|
183
213
|
const c = 1013904223;
|
|
184
214
|
const m = 4294967296;
|
|
185
215
|
_rngSeed = (a * _rngSeed + c) % m;
|
|
186
|
-
return _rngSeed / m * (max - min) + min;
|
|
216
|
+
return (_rngSeed / m) * (max - min) + min;
|
|
187
217
|
},
|
|
188
|
-
/**
|
|
189
|
-
* Generates a pseudorandom integer between min (inclusive) and max (inclusive)
|
|
190
|
-
*
|
|
191
|
-
* @param {number} [min=0]
|
|
192
|
-
* @param {number} [max=1]
|
|
193
|
-
* @returns {number} the random number
|
|
194
|
-
*/
|
|
195
218
|
randi: (min = 0, max = 1) => {
|
|
196
|
-
return
|
|
219
|
+
return ~~instance.rand(min, max + 1);
|
|
197
220
|
},
|
|
198
|
-
/**
|
|
199
|
-
* Initializes the random number generator with an explicit seed value.
|
|
200
|
-
*
|
|
201
|
-
* Note: The seed should be a integer number greater than or equal to zero.
|
|
202
|
-
*
|
|
203
|
-
* @param {number} value
|
|
204
|
-
*/
|
|
205
221
|
rseed(value) {
|
|
206
222
|
_rngSeed = ~~value;
|
|
207
223
|
},
|
|
208
|
-
/** BASIC GRAPHICS API */
|
|
209
|
-
/**
|
|
210
|
-
* Clear the game screen with an optional color
|
|
211
|
-
*
|
|
212
|
-
* @param {number} [color] The background color (index) or null/undefined (for transparent)
|
|
213
|
-
*/
|
|
214
224
|
cls(color) {
|
|
215
225
|
if (null == color) {
|
|
216
|
-
_ctx.clearRect(0, 0,
|
|
226
|
+
_ctx.clearRect(0, 0, instance.W, instance.H);
|
|
217
227
|
} else {
|
|
218
|
-
instance.rectfill(0, 0,
|
|
228
|
+
instance.rectfill(0, 0, instance.W, instance.H, color);
|
|
219
229
|
}
|
|
220
230
|
},
|
|
221
|
-
/**
|
|
222
|
-
* Draw a rectangle outline
|
|
223
|
-
*
|
|
224
|
-
* @param {number} x
|
|
225
|
-
* @param {number} y
|
|
226
|
-
* @param {number} width
|
|
227
|
-
* @param {number} height
|
|
228
|
-
* @param {number} [color=0] the color index
|
|
229
|
-
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
230
|
-
*
|
|
231
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/roundRect
|
|
232
|
-
*/
|
|
233
231
|
rect(x, y, width, height, color, radii) {
|
|
234
232
|
beginPath(_ctx);
|
|
235
233
|
_ctx[radii ? "roundRect" : "rect"](
|
|
@@ -237,85 +235,35 @@
|
|
|
237
235
|
~~y - _outline_fix,
|
|
238
236
|
~~width + _outline_fix * 2,
|
|
239
237
|
~~height + _outline_fix * 2,
|
|
240
|
-
radii
|
|
238
|
+
radii,
|
|
241
239
|
);
|
|
242
240
|
instance.stroke(color);
|
|
243
241
|
},
|
|
244
|
-
/**
|
|
245
|
-
* Draw a color-filled rectangle
|
|
246
|
-
*
|
|
247
|
-
* @param {number} x
|
|
248
|
-
* @param {number} y
|
|
249
|
-
* @param {number} width
|
|
250
|
-
* @param {number} height
|
|
251
|
-
* @param {number} [color=0] the color index
|
|
252
|
-
* @param {number|number[]} [radii] A number or list specifying the radii used to draw a rounded-borders rectangle
|
|
253
|
-
*/
|
|
254
242
|
rectfill(x, y, width, height, color, radii) {
|
|
255
243
|
beginPath(_ctx);
|
|
256
244
|
_ctx[radii ? "roundRect" : "rect"](~~x, ~~y, ~~width, ~~height, radii);
|
|
257
245
|
instance.fill(color);
|
|
258
246
|
},
|
|
259
|
-
/**
|
|
260
|
-
* Draw a circle outline
|
|
261
|
-
*
|
|
262
|
-
* @param {number} x
|
|
263
|
-
* @param {number} y
|
|
264
|
-
* @param {number} radius
|
|
265
|
-
* @param {number} [color=0] the color index
|
|
266
|
-
*/
|
|
267
247
|
circ(x, y, radius, color) {
|
|
268
248
|
beginPath(_ctx);
|
|
269
249
|
_ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
|
|
270
250
|
instance.stroke(color);
|
|
271
251
|
},
|
|
272
|
-
/**
|
|
273
|
-
* Draw a color-filled circle
|
|
274
|
-
*
|
|
275
|
-
* @param {number} x
|
|
276
|
-
* @param {number} y
|
|
277
|
-
* @param {number} radius
|
|
278
|
-
* @param {number} [color=0] the color index
|
|
279
|
-
*/
|
|
280
252
|
circfill(x, y, radius, color) {
|
|
281
253
|
beginPath(_ctx);
|
|
282
254
|
_ctx.arc(~~x, ~~y, ~~radius, 0, TWO_PI);
|
|
283
255
|
instance.fill(color);
|
|
284
256
|
},
|
|
285
|
-
/**
|
|
286
|
-
* Draw a ellipse outline
|
|
287
|
-
*
|
|
288
|
-
* @param {number} x
|
|
289
|
-
* @param {number} y
|
|
290
|
-
* @param {number} radiusX
|
|
291
|
-
* @param {number} radiusY
|
|
292
|
-
* @param {number} [color=0] the color index
|
|
293
|
-
*/
|
|
294
257
|
oval(x, y, radiusX, radiusY, color) {
|
|
295
258
|
beginPath(_ctx);
|
|
296
259
|
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
|
|
297
260
|
instance.stroke(color);
|
|
298
261
|
},
|
|
299
|
-
/**
|
|
300
|
-
* Draw a color-filled ellipse
|
|
301
|
-
*
|
|
302
|
-
* @param {number} x
|
|
303
|
-
* @param {number} y
|
|
304
|
-
* @param {number} radiusX
|
|
305
|
-
* @param {number} radiusY
|
|
306
|
-
* @param {number} [color=0] the color index
|
|
307
|
-
*/
|
|
308
262
|
ovalfill(x, y, radiusX, radiusY, color) {
|
|
309
263
|
beginPath(_ctx);
|
|
310
264
|
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI);
|
|
311
265
|
instance.fill(color);
|
|
312
266
|
},
|
|
313
|
-
/**
|
|
314
|
-
* Make a custom shape in the canvas context.
|
|
315
|
-
* Then, just use `fill` or `stroke` to draw the shape.
|
|
316
|
-
*
|
|
317
|
-
* @param {number[]} points an array of Xs and Ys coordinates
|
|
318
|
-
*/
|
|
319
267
|
shape(points) {
|
|
320
268
|
beginPath(_ctx);
|
|
321
269
|
for (let i = 0; i < points.length; i += 2) {
|
|
@@ -327,15 +275,6 @@
|
|
|
327
275
|
}
|
|
328
276
|
_ctx.lineTo(~~points[0], ~~points[1]);
|
|
329
277
|
},
|
|
330
|
-
/**
|
|
331
|
-
* Draw a line
|
|
332
|
-
*
|
|
333
|
-
* @param {number} x1
|
|
334
|
-
* @param {number} y1
|
|
335
|
-
* @param {number} x2
|
|
336
|
-
* @param {number} y2
|
|
337
|
-
* @param {number} [color=0] the color index
|
|
338
|
-
*/
|
|
339
278
|
line(x1, y1, x2, y2, color) {
|
|
340
279
|
beginPath(_ctx);
|
|
341
280
|
let xfix = _outline_fix !== 0 && ~~x1 === ~~x2 ? 0.5 : 0;
|
|
@@ -344,102 +283,42 @@
|
|
|
344
283
|
_ctx.lineTo(~~x2 + xfix, ~~y2 + yfix);
|
|
345
284
|
instance.stroke(color);
|
|
346
285
|
},
|
|
347
|
-
/**
|
|
348
|
-
* Sets the thickness of the lines
|
|
349
|
-
*
|
|
350
|
-
* @param {number} value
|
|
351
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineWidth
|
|
352
|
-
*/
|
|
353
286
|
linewidth(value) {
|
|
354
287
|
_ctx.lineWidth = ~~value;
|
|
355
288
|
_outline_fix = 0 === ~~value % 2 ? 0 : 0.5;
|
|
356
289
|
},
|
|
357
|
-
/**
|
|
358
|
-
* Sets the line dash pattern used when drawing lines
|
|
359
|
-
*
|
|
360
|
-
* @param {number[]} segments the line dash pattern
|
|
361
|
-
* @param {number} [offset=0] the line dash offset, or "phase".
|
|
362
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
363
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
|
|
364
|
-
*/
|
|
365
290
|
linedash(segments, offset = 0) {
|
|
366
291
|
_ctx.setLineDash(segments);
|
|
367
292
|
_ctx.lineDashOffset = offset;
|
|
368
293
|
},
|
|
369
|
-
/** TEXT RENDERING API */
|
|
370
|
-
/**
|
|
371
|
-
* Draw text. You can use `\n` to break lines.
|
|
372
|
-
*
|
|
373
|
-
* @param {number} x
|
|
374
|
-
* @param {number} y
|
|
375
|
-
* @param {string} message the text message
|
|
376
|
-
* @param {number} [color] the color index
|
|
377
|
-
* @param {string} [fontStyle] can be "normal" (default), "italic" and/or "bold".
|
|
378
|
-
*/
|
|
379
294
|
text(x, y, message, color = _defaultTextColor, fontStyle = "normal") {
|
|
380
295
|
_ctx.font = `${fontStyle} ${_fontSize}px ${_fontFamily}`;
|
|
381
296
|
_ctx.fillStyle = getColor(color);
|
|
382
297
|
const messages = ("" + message).split("\n");
|
|
383
298
|
for (let i = 0; i < messages.length; i++) {
|
|
384
|
-
_ctx.fillText(
|
|
299
|
+
_ctx.fillText(
|
|
300
|
+
messages[i],
|
|
301
|
+
~~x,
|
|
302
|
+
~~y + _fontSize * _fontLineHeight * i,
|
|
303
|
+
);
|
|
385
304
|
}
|
|
386
305
|
},
|
|
387
|
-
/**
|
|
388
|
-
* Sets the height ratio of the text lines based on current text size.
|
|
389
|
-
*
|
|
390
|
-
* Default = `1.2`
|
|
391
|
-
*
|
|
392
|
-
* @param value
|
|
393
|
-
*/
|
|
394
306
|
textgap(value) {
|
|
395
307
|
_fontLineHeight = value;
|
|
396
308
|
},
|
|
397
|
-
/**
|
|
398
|
-
* Set the font family
|
|
399
|
-
*
|
|
400
|
-
* @param {string} family
|
|
401
|
-
*/
|
|
402
309
|
textfont(family) {
|
|
403
310
|
_fontFamily = family;
|
|
404
311
|
},
|
|
405
|
-
/**
|
|
406
|
-
* Set the font size
|
|
407
|
-
*
|
|
408
|
-
* @param {number} size
|
|
409
|
-
*/
|
|
410
312
|
textsize(size) {
|
|
411
313
|
_fontSize = size;
|
|
412
314
|
},
|
|
413
|
-
/**
|
|
414
|
-
* Sets the alignment used when drawing texts
|
|
415
|
-
*
|
|
416
|
-
* @param {CanvasTextAlign} align the horizontal alignment. Possible values: "left", "right", "center", "start" or "end"
|
|
417
|
-
* @param {CanvasTextBaseline} baseline the vertical alignment. Possible values: "top", "bottom", "middle", "hanging" or "ideographic"
|
|
418
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
|
|
419
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textAlign
|
|
420
|
-
*/
|
|
421
315
|
textalign(align, baseline) {
|
|
422
316
|
if (align) _ctx.textAlign = align;
|
|
423
317
|
if (baseline) _ctx.textBaseline = baseline;
|
|
424
318
|
},
|
|
425
|
-
/** IMAGE GRAPHICS API */
|
|
426
|
-
/**
|
|
427
|
-
* Draw an image
|
|
428
|
-
*
|
|
429
|
-
* @param {number} x
|
|
430
|
-
* @param {number} y
|
|
431
|
-
* @param {CanvasImageSource} source
|
|
432
|
-
*/
|
|
433
319
|
image(x, y, source2) {
|
|
434
320
|
_ctx.drawImage(source2, ~~x, ~~y);
|
|
435
321
|
},
|
|
436
|
-
/**
|
|
437
|
-
* 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.
|
|
438
|
-
*
|
|
439
|
-
* @param {number} x
|
|
440
|
-
* @param {number} y
|
|
441
|
-
* @param {string} pixels
|
|
442
|
-
*/
|
|
443
322
|
spr(x, y, pixels) {
|
|
444
323
|
const rows = pixels.trim().split("\n");
|
|
445
324
|
for (let row = 0; row < rows.length; row++) {
|
|
@@ -447,25 +326,21 @@
|
|
|
447
326
|
for (let col = 0; col < chars.length; col++) {
|
|
448
327
|
const char = chars[col];
|
|
449
328
|
if (char !== "." && char !== " ") {
|
|
450
|
-
instance.rectfill(
|
|
329
|
+
instance.rectfill(
|
|
330
|
+
x + col,
|
|
331
|
+
y + row,
|
|
332
|
+
1,
|
|
333
|
+
1,
|
|
334
|
+
parseInt(char, 36) || 0,
|
|
335
|
+
);
|
|
451
336
|
}
|
|
452
337
|
}
|
|
453
338
|
}
|
|
454
339
|
},
|
|
455
|
-
/**
|
|
456
|
-
* Draw in an OffscreenCanvas and returns its image.
|
|
457
|
-
*
|
|
458
|
-
* @param {number} width
|
|
459
|
-
* @param {number} height
|
|
460
|
-
* @param {drawCallback} callback
|
|
461
|
-
* @param {object} [options]
|
|
462
|
-
* @param {number} [options.scale=1]
|
|
463
|
-
* @param {OffscreenCanvas} [options.canvas]
|
|
464
|
-
* @returns {ImageBitmap}
|
|
465
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
|
|
466
|
-
*/
|
|
467
340
|
paint(width, height, callback, options = {}) {
|
|
468
|
-
const canvas = options.canvas || new OffscreenCanvas(1, 1),
|
|
341
|
+
const canvas = options.canvas || new OffscreenCanvas(1, 1),
|
|
342
|
+
scale = options.scale || 1,
|
|
343
|
+
currentContext = _ctx;
|
|
469
344
|
canvas.width = width * scale;
|
|
470
345
|
canvas.height = height * scale;
|
|
471
346
|
_ctx = canvas.getContext("2d");
|
|
@@ -474,114 +349,48 @@
|
|
|
474
349
|
_ctx = currentContext;
|
|
475
350
|
return canvas.transferToImageBitmap();
|
|
476
351
|
},
|
|
477
|
-
/** ADVANCED GRAPHICS API */
|
|
478
|
-
/**
|
|
479
|
-
* Get or set the canvas context 2D
|
|
480
|
-
*
|
|
481
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
482
|
-
* @returns {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
|
|
483
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
|
|
484
|
-
*/
|
|
485
352
|
ctx(context) {
|
|
486
353
|
if (context) {
|
|
487
354
|
_ctx = context;
|
|
488
355
|
}
|
|
489
356
|
return _ctx;
|
|
490
357
|
},
|
|
491
|
-
/**
|
|
492
|
-
* saves the current drawing style settings and transformations
|
|
493
|
-
*
|
|
494
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
|
|
495
|
-
*/
|
|
496
358
|
push() {
|
|
497
359
|
_ctx.save();
|
|
498
360
|
},
|
|
499
|
-
/**
|
|
500
|
-
* restores the drawing style settings and transformations
|
|
501
|
-
*
|
|
502
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore
|
|
503
|
-
*/
|
|
504
361
|
pop() {
|
|
505
362
|
_ctx.restore();
|
|
506
363
|
},
|
|
507
|
-
/**
|
|
508
|
-
* Adds a translation to the transformation matrix.
|
|
509
|
-
*
|
|
510
|
-
* @param {number} x
|
|
511
|
-
* @param {number} y
|
|
512
|
-
*/
|
|
513
364
|
translate(x, y) {
|
|
514
365
|
_ctx.translate(~~x, ~~y);
|
|
515
366
|
},
|
|
516
|
-
/**
|
|
517
|
-
* Adds a scaling transformation to the canvas units horizontally and/or vertically.
|
|
518
|
-
*
|
|
519
|
-
* @param {number} x
|
|
520
|
-
* @param {number} [y]
|
|
521
|
-
*/
|
|
522
367
|
scale(x, y) {
|
|
523
368
|
_ctx.scale(x, y || x);
|
|
524
369
|
},
|
|
525
|
-
/**
|
|
526
|
-
* Adds a rotation to the transformation matrix.
|
|
527
|
-
*
|
|
528
|
-
* @param {number} radians
|
|
529
|
-
*/
|
|
530
370
|
rotate(radians) {
|
|
531
371
|
_ctx.rotate(radians);
|
|
532
372
|
},
|
|
533
|
-
/**
|
|
534
|
-
* Sets the alpha (opacity) value to apply when drawing new shapes and images
|
|
535
|
-
*
|
|
536
|
-
* @param {number} value float from 0 to 1 (e.g: 0.5 = 50% transparent)
|
|
537
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha
|
|
538
|
-
*/
|
|
539
373
|
alpha(value) {
|
|
540
374
|
_ctx.globalAlpha = instance.clamp(value, 0, 1);
|
|
541
375
|
},
|
|
542
|
-
/**
|
|
543
|
-
* Fills the current path with a given color.
|
|
544
|
-
*
|
|
545
|
-
* @param {number} [color=0]
|
|
546
|
-
*/
|
|
547
376
|
fill(color) {
|
|
548
377
|
_ctx.fillStyle = getColor(color);
|
|
549
378
|
_ctx.fill();
|
|
550
379
|
},
|
|
551
|
-
/**
|
|
552
|
-
* Outlines the current path with a given color.
|
|
553
|
-
*
|
|
554
|
-
* @param {number} [color=0]
|
|
555
|
-
*/
|
|
556
380
|
stroke(color) {
|
|
557
381
|
_ctx.strokeStyle = getColor(color);
|
|
558
382
|
_ctx.stroke();
|
|
559
383
|
},
|
|
560
|
-
/**
|
|
561
|
-
* Turns a path (in the callback) into the current clipping region.
|
|
562
|
-
*
|
|
563
|
-
* @param {clipCallback} callback
|
|
564
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
|
|
565
|
-
*/
|
|
566
384
|
clip(callback) {
|
|
567
385
|
beginPath(_ctx);
|
|
568
386
|
callback(_ctx);
|
|
569
387
|
_ctx.clip();
|
|
570
388
|
},
|
|
571
|
-
/** SOUND API */
|
|
572
|
-
/**
|
|
573
|
-
* Play a sound effects using ZzFX library.
|
|
574
|
-
* If the first argument is omitted, plays an default sound.
|
|
575
|
-
*
|
|
576
|
-
* @param {number[]} [zzfxParams] a ZzFX array of params
|
|
577
|
-
* @param {number} [pitchSlide] a value to increment/decrement the pitch
|
|
578
|
-
* @param {number} [volumeFactor] the volume factor
|
|
579
|
-
* @returns {number[] | boolean} The sound that was played or `false`
|
|
580
|
-
*
|
|
581
|
-
* @see https://github.com/KilledByAPixel/ZzFX
|
|
582
|
-
*/
|
|
583
389
|
sfx(zzfxParams, pitchSlide = 0, volumeFactor = 1) {
|
|
584
|
-
if (
|
|
390
|
+
if (
|
|
391
|
+
!root.zzfxV ||
|
|
392
|
+
(navigator.userActivation && !navigator.userActivation.hasBeenActive)
|
|
393
|
+
) {
|
|
585
394
|
return false;
|
|
586
395
|
}
|
|
587
396
|
zzfxParams = zzfxParams || _defaultSound;
|
|
@@ -593,52 +402,19 @@
|
|
|
593
402
|
zzfx.apply(0, zzfxParams);
|
|
594
403
|
return zzfxParams;
|
|
595
404
|
},
|
|
596
|
-
/**
|
|
597
|
-
* Set the ZzFX's global volume factor.
|
|
598
|
-
* Note: use 0 to mute all sound effects.
|
|
599
|
-
*
|
|
600
|
-
* @param {number} value
|
|
601
|
-
*/
|
|
602
405
|
volume(value) {
|
|
603
406
|
root.zzfxV = value;
|
|
604
407
|
},
|
|
605
|
-
/** PLUGINS API */
|
|
606
|
-
/**
|
|
607
|
-
* Returns the canvas
|
|
608
|
-
*
|
|
609
|
-
* @returns {HTMLCanvasElement}
|
|
610
|
-
*/
|
|
611
408
|
canvas: () => _canvas,
|
|
612
|
-
/**
|
|
613
|
-
* Prepares a plugin to be loaded
|
|
614
|
-
*
|
|
615
|
-
* @param {pluginCallback} callback
|
|
616
|
-
*/
|
|
617
409
|
use(callback, config = {}) {
|
|
618
410
|
loadPlugin(callback, config);
|
|
619
411
|
},
|
|
620
|
-
/**
|
|
621
|
-
* Add a game event listener
|
|
622
|
-
*
|
|
623
|
-
* @param {string} eventName the event type name
|
|
624
|
-
* @param {Function} callback the function that is called when the event occurs
|
|
625
|
-
* @returns {Function} a function to remove the listener
|
|
626
|
-
*/
|
|
627
412
|
listen(eventName, callback) {
|
|
628
413
|
eventName = lowerCase(eventName);
|
|
629
|
-
_eventListeners[eventName] = _eventListeners[eventName] ||
|
|
414
|
+
_eventListeners[eventName] = _eventListeners[eventName] || new Set();
|
|
630
415
|
_eventListeners[eventName].add(callback);
|
|
631
416
|
return () => _eventListeners[eventName]?.delete(callback);
|
|
632
417
|
},
|
|
633
|
-
/**
|
|
634
|
-
* Call all listeners attached to a game event
|
|
635
|
-
*
|
|
636
|
-
* @param {string} eventName The event type name
|
|
637
|
-
* @param {*} [arg1] any data to be passed over the listeners
|
|
638
|
-
* @param {*} [arg2] any data to be passed over the listeners
|
|
639
|
-
* @param {*} [arg3] any data to be passed over the listeners
|
|
640
|
-
* @param {*} [arg4] any data to be passed over the listeners
|
|
641
|
-
*/
|
|
642
418
|
emit(eventName, arg1, arg2, arg3, arg4) {
|
|
643
419
|
if (_initialized) {
|
|
644
420
|
eventName = lowerCase(eventName);
|
|
@@ -647,27 +423,11 @@
|
|
|
647
423
|
triggerEvent("after:" + eventName, arg1, arg2, arg3, arg4);
|
|
648
424
|
}
|
|
649
425
|
},
|
|
650
|
-
/**
|
|
651
|
-
* Set new palette colors or restore the default palette.
|
|
652
|
-
*
|
|
653
|
-
* @param {string[]} [colors] an array of colors
|
|
654
|
-
* @param {number} [textColor] the default text color this palette
|
|
655
|
-
*/
|
|
656
426
|
pal(colors, textColor = 3) {
|
|
657
427
|
_colorPalette = colors || defaultPalette;
|
|
658
428
|
_colorPaletteState = [];
|
|
659
429
|
_defaultTextColor = textColor;
|
|
660
430
|
},
|
|
661
|
-
/**
|
|
662
|
-
* Replace the color "a" with color "b".
|
|
663
|
-
*
|
|
664
|
-
* If called without arguments, reset the current palette.
|
|
665
|
-
*
|
|
666
|
-
* Note: `palc()` don't affect drawings made with `image()`.
|
|
667
|
-
*
|
|
668
|
-
* @param {number?} a
|
|
669
|
-
* @param {number?} b
|
|
670
|
-
*/
|
|
671
431
|
palc(a, b) {
|
|
672
432
|
if (a == null) {
|
|
673
433
|
_colorPaletteState = [];
|
|
@@ -675,106 +435,54 @@
|
|
|
675
435
|
_colorPaletteState[a] = b;
|
|
676
436
|
}
|
|
677
437
|
},
|
|
678
|
-
/**
|
|
679
|
-
* Define or update a instance property.
|
|
680
|
-
*
|
|
681
|
-
* @param {string} key
|
|
682
|
-
* @param {*} value
|
|
683
|
-
*/
|
|
684
438
|
def(key, value) {
|
|
685
439
|
instance[key] = value;
|
|
686
440
|
if (settings.global) {
|
|
687
441
|
root[key] = value;
|
|
688
442
|
}
|
|
689
443
|
},
|
|
690
|
-
/**
|
|
691
|
-
* The scale of the game's delta time (dt).
|
|
692
|
-
* Values higher than 1 increase the speed of time, while values smaller than 1 decrease it.
|
|
693
|
-
* A value of 0 freezes time and is effectively equivalent to pausing.
|
|
694
|
-
*
|
|
695
|
-
* @param {number} value
|
|
696
|
-
*/
|
|
697
444
|
timescale(value) {
|
|
698
445
|
_timeScale = value;
|
|
699
446
|
},
|
|
700
|
-
/**
|
|
701
|
-
* Set the target FPS (frames per second).
|
|
702
|
-
*
|
|
703
|
-
* @param {number} value
|
|
704
|
-
*/
|
|
705
447
|
framerate(value) {
|
|
706
448
|
_fpsInterval = 1e3 / ~~value;
|
|
707
449
|
},
|
|
708
|
-
/**
|
|
709
|
-
* Returns information about the engine instance.
|
|
710
|
-
*
|
|
711
|
-
* @param {number|string} index
|
|
712
|
-
* @returns {any}
|
|
713
|
-
*/
|
|
714
450
|
stat(index) {
|
|
715
451
|
const internals = [
|
|
716
|
-
// 0
|
|
717
452
|
settings,
|
|
718
|
-
// 1
|
|
719
453
|
_initialized,
|
|
720
|
-
// 2
|
|
721
454
|
_fpsInterval / 1e3,
|
|
722
|
-
// 3
|
|
723
455
|
_canvasScale,
|
|
724
|
-
// 4
|
|
725
456
|
_eventListeners,
|
|
726
|
-
// 5
|
|
727
457
|
_colorPalette,
|
|
728
|
-
// 6
|
|
729
458
|
_defaultSound,
|
|
730
|
-
// 7
|
|
731
459
|
_timeScale,
|
|
732
|
-
// 8
|
|
733
460
|
root.zzfxV,
|
|
734
|
-
// 9
|
|
735
461
|
_rngSeed,
|
|
736
|
-
// 10
|
|
737
462
|
_fontSize,
|
|
738
|
-
// 11
|
|
739
463
|
_fontFamily,
|
|
740
|
-
// 12
|
|
741
464
|
_colorPaletteState,
|
|
742
|
-
|
|
743
|
-
_fontLineHeight
|
|
465
|
+
_fontLineHeight,
|
|
744
466
|
];
|
|
745
467
|
const data = { index, value: internals[index] };
|
|
746
468
|
instance.emit("stat", data);
|
|
747
469
|
return data.value;
|
|
748
470
|
},
|
|
749
|
-
/**
|
|
750
|
-
* Pauses the engine loop (update & draw).
|
|
751
|
-
*/
|
|
752
471
|
pause() {
|
|
753
472
|
_paused = true;
|
|
754
473
|
cancelAnimationFrame(_rafid);
|
|
755
474
|
},
|
|
756
|
-
/**
|
|
757
|
-
* Resumes (if paused) the engine loop.
|
|
758
|
-
*/
|
|
759
475
|
resume() {
|
|
760
476
|
if (_initialized && _paused) {
|
|
761
477
|
_paused = false;
|
|
762
478
|
_accumulated = _fpsInterval;
|
|
763
|
-
_lastFrameTime =
|
|
479
|
+
_lastFrameTime = perf.now();
|
|
764
480
|
_rafid = raf(drawFrame);
|
|
765
481
|
}
|
|
766
482
|
},
|
|
767
|
-
/**
|
|
768
|
-
* Returns `true` if the engine loop is paused.
|
|
769
|
-
*
|
|
770
|
-
* @returns {boolean}
|
|
771
|
-
*/
|
|
772
483
|
paused() {
|
|
773
484
|
return _paused;
|
|
774
485
|
},
|
|
775
|
-
/**
|
|
776
|
-
* Shutdown the litecanvas instance and remove all event listeners.
|
|
777
|
-
*/
|
|
778
486
|
quit() {
|
|
779
487
|
instance.emit("quit");
|
|
780
488
|
instance.pause();
|
|
@@ -789,7 +497,7 @@
|
|
|
789
497
|
}
|
|
790
498
|
delete root.ENGINE;
|
|
791
499
|
}
|
|
792
|
-
}
|
|
500
|
+
},
|
|
793
501
|
};
|
|
794
502
|
for (const k of _mathFunctions.split(",")) {
|
|
795
503
|
instance[k] = math[k];
|
|
@@ -799,138 +507,72 @@
|
|
|
799
507
|
on(root, "resize", resizeCanvas);
|
|
800
508
|
}
|
|
801
509
|
if (settings.tapEvents) {
|
|
802
|
-
const _getXY = (
|
|
803
|
-
/**
|
|
804
|
-
* @param {MouseEvent | Touch} ev
|
|
805
|
-
*/
|
|
806
|
-
(ev) => [
|
|
510
|
+
const _getXY = (ev) => [
|
|
807
511
|
(ev.pageX - _canvas.offsetLeft) / _canvasScale,
|
|
808
|
-
(ev.pageY - _canvas.offsetTop) / _canvasScale
|
|
809
|
-
]
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
* @param {number} [x]
|
|
814
|
-
* @param {number} [y]
|
|
815
|
-
*/
|
|
816
|
-
(id, x, y) => {
|
|
817
|
-
const tap = {
|
|
818
|
-
// current x
|
|
819
|
-
x,
|
|
820
|
-
// current y
|
|
821
|
-
y,
|
|
822
|
-
// initial x
|
|
823
|
-
xi: x,
|
|
824
|
-
// initial y
|
|
825
|
-
yi: y,
|
|
826
|
-
// timestamp
|
|
827
|
-
t: Date.now()
|
|
828
|
-
};
|
|
512
|
+
(ev.pageY - _canvas.offsetTop) / _canvasScale,
|
|
513
|
+
],
|
|
514
|
+
_taps = new Map(),
|
|
515
|
+
_registerTap = (id, x, y) => {
|
|
516
|
+
const tap = { x, y, xi: x, yi: y, t: perf.now() };
|
|
829
517
|
_taps.set(id, tap);
|
|
830
518
|
return tap;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
/**
|
|
834
|
-
* @param {number} id
|
|
835
|
-
* @param {number} x
|
|
836
|
-
* @param {number} y
|
|
837
|
-
*/
|
|
838
|
-
(id, x, y) => {
|
|
519
|
+
},
|
|
520
|
+
_updateTap = (id, x, y) => {
|
|
839
521
|
const tap = _taps.get(id) || _registerTap(id);
|
|
840
522
|
tap.x = x;
|
|
841
523
|
tap.y = y;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
/**
|
|
845
|
-
* @param {{t: number}} tap
|
|
846
|
-
*/
|
|
847
|
-
(tap) => tap && Date.now() - tap.t <= 300
|
|
848
|
-
);
|
|
524
|
+
},
|
|
525
|
+
_checkTapped = (tap) => tap && perf.now() - tap.t <= 300;
|
|
849
526
|
let _pressingMouse = false;
|
|
850
|
-
on(
|
|
851
|
-
|
|
852
|
-
"mousedown",
|
|
853
|
-
/**
|
|
854
|
-
* @param {MouseEvent} ev
|
|
855
|
-
*/
|
|
856
|
-
(ev) => {
|
|
857
|
-
if (ev.button === 0) {
|
|
858
|
-
preventDefault(ev);
|
|
859
|
-
const [x, y] = _getXY(ev);
|
|
860
|
-
instance.emit("tap", x, y, 0);
|
|
861
|
-
_registerTap(0, x, y);
|
|
862
|
-
_pressingMouse = true;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
);
|
|
866
|
-
on(
|
|
867
|
-
_canvas,
|
|
868
|
-
"mouseup",
|
|
869
|
-
/**
|
|
870
|
-
* @param {MouseEvent} ev
|
|
871
|
-
*/
|
|
872
|
-
(ev) => {
|
|
873
|
-
if (ev.button === 0) {
|
|
874
|
-
preventDefault(ev);
|
|
875
|
-
const tap = _taps.get(0);
|
|
876
|
-
const [x, y] = _getXY(ev);
|
|
877
|
-
if (_checkTapped(tap)) {
|
|
878
|
-
instance.emit("tapped", tap.xi, tap.yi, 0);
|
|
879
|
-
}
|
|
880
|
-
instance.emit("untap", x, y, 0);
|
|
881
|
-
_taps.delete(0);
|
|
882
|
-
_pressingMouse = false;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
);
|
|
886
|
-
on(
|
|
887
|
-
root,
|
|
888
|
-
"mousemove",
|
|
889
|
-
/**
|
|
890
|
-
* @param {MouseEvent} ev
|
|
891
|
-
*/
|
|
892
|
-
(ev) => {
|
|
527
|
+
on(_canvas, "mousedown", (ev) => {
|
|
528
|
+
if (ev.button === 0) {
|
|
893
529
|
preventDefault(ev);
|
|
894
530
|
const [x, y] = _getXY(ev);
|
|
895
|
-
instance.
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
instance.emit("tapping", x, y, 0);
|
|
899
|
-
_updateTap(0, x, y);
|
|
531
|
+
instance.emit("tap", x, y, 0);
|
|
532
|
+
_registerTap(0, x, y);
|
|
533
|
+
_pressingMouse = true;
|
|
900
534
|
}
|
|
901
|
-
);
|
|
902
|
-
on(
|
|
903
|
-
|
|
904
|
-
"touchstart",
|
|
905
|
-
/**
|
|
906
|
-
* @param {TouchEvent} ev
|
|
907
|
-
*/
|
|
908
|
-
(ev) => {
|
|
535
|
+
});
|
|
536
|
+
on(_canvas, "mouseup", (ev) => {
|
|
537
|
+
if (ev.button === 0) {
|
|
909
538
|
preventDefault(ev);
|
|
910
|
-
const
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
instance.emit("
|
|
914
|
-
_registerTap(touch.identifier + 1, x, y);
|
|
539
|
+
const tap = _taps.get(0);
|
|
540
|
+
const [x, y] = _getXY(ev);
|
|
541
|
+
if (_checkTapped(tap)) {
|
|
542
|
+
instance.emit("tapped", tap.xi, tap.yi, 0);
|
|
915
543
|
}
|
|
544
|
+
instance.emit("untap", x, y, 0);
|
|
545
|
+
_taps.delete(0);
|
|
546
|
+
_pressingMouse = false;
|
|
916
547
|
}
|
|
917
|
-
);
|
|
918
|
-
on(
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
(
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
548
|
+
});
|
|
549
|
+
on(root, "mousemove", (ev) => {
|
|
550
|
+
preventDefault(ev);
|
|
551
|
+
const [x, y] = _getXY(ev);
|
|
552
|
+
instance.def("MX", x);
|
|
553
|
+
instance.def("MY", y);
|
|
554
|
+
if (!_pressingMouse) return;
|
|
555
|
+
instance.emit("tapping", x, y, 0);
|
|
556
|
+
_updateTap(0, x, y);
|
|
557
|
+
});
|
|
558
|
+
on(_canvas, "touchstart", (ev) => {
|
|
559
|
+
preventDefault(ev);
|
|
560
|
+
const touches = ev.changedTouches;
|
|
561
|
+
for (const touch of touches) {
|
|
562
|
+
const [x, y] = _getXY(touch);
|
|
563
|
+
instance.emit("tap", x, y, touch.identifier + 1);
|
|
564
|
+
_registerTap(touch.identifier + 1, x, y);
|
|
932
565
|
}
|
|
933
|
-
);
|
|
566
|
+
});
|
|
567
|
+
on(_canvas, "touchmove", (ev) => {
|
|
568
|
+
preventDefault(ev);
|
|
569
|
+
const touches = ev.changedTouches;
|
|
570
|
+
for (const touch of touches) {
|
|
571
|
+
const [x, y] = _getXY(touch);
|
|
572
|
+
instance.emit("tapping", x, y, touch.identifier + 1);
|
|
573
|
+
_updateTap(touch.identifier + 1, x, y);
|
|
574
|
+
}
|
|
575
|
+
});
|
|
934
576
|
const _touchEndHandler = (ev) => {
|
|
935
577
|
preventDefault(ev);
|
|
936
578
|
const existing = [];
|
|
@@ -959,11 +601,13 @@
|
|
|
959
601
|
});
|
|
960
602
|
}
|
|
961
603
|
if (settings.keyboardEvents) {
|
|
962
|
-
const _keysDown =
|
|
963
|
-
const _keysPress =
|
|
604
|
+
const _keysDown = new Set();
|
|
605
|
+
const _keysPress = new Set();
|
|
964
606
|
const keyCheck = (keySet, key = "") => {
|
|
965
607
|
key = lowerCase(key);
|
|
966
|
-
return !key
|
|
608
|
+
return !key
|
|
609
|
+
? keySet.size > 0
|
|
610
|
+
: keySet.has("space" === key ? " " : key);
|
|
967
611
|
};
|
|
968
612
|
let _lastKey = "";
|
|
969
613
|
on(root, "keydown", (event) => {
|
|
@@ -979,33 +623,13 @@
|
|
|
979
623
|
});
|
|
980
624
|
on(root, "blur", () => _keysDown.clear());
|
|
981
625
|
instance.listen("after:update", () => _keysPress.clear());
|
|
982
|
-
instance.def(
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
return keyCheck(_keysDown, key);
|
|
990
|
-
}
|
|
991
|
-
);
|
|
992
|
-
instance.def(
|
|
993
|
-
"iskeypressed",
|
|
994
|
-
/**
|
|
995
|
-
* @param {string} [key]
|
|
996
|
-
* @returns {boolean}
|
|
997
|
-
*/
|
|
998
|
-
(key) => {
|
|
999
|
-
return keyCheck(_keysPress, key);
|
|
1000
|
-
}
|
|
1001
|
-
);
|
|
1002
|
-
instance.def(
|
|
1003
|
-
"lastkey",
|
|
1004
|
-
/**
|
|
1005
|
-
* @returns {string}
|
|
1006
|
-
*/
|
|
1007
|
-
() => _lastKey
|
|
1008
|
-
);
|
|
626
|
+
instance.def("iskeydown", (key) => {
|
|
627
|
+
return keyCheck(_keysDown, key);
|
|
628
|
+
});
|
|
629
|
+
instance.def("iskeypressed", (key) => {
|
|
630
|
+
return keyCheck(_keysPress, key);
|
|
631
|
+
});
|
|
632
|
+
instance.def("lastkey", () => _lastKey);
|
|
1009
633
|
}
|
|
1010
634
|
_initialized = true;
|
|
1011
635
|
instance.resume();
|
|
@@ -1013,7 +637,7 @@
|
|
|
1013
637
|
}
|
|
1014
638
|
function drawFrame() {
|
|
1015
639
|
_rafid = raf(drawFrame);
|
|
1016
|
-
let now =
|
|
640
|
+
let now = perf.now();
|
|
1017
641
|
let updated = 0;
|
|
1018
642
|
let frameTime = now - _lastFrameTime;
|
|
1019
643
|
_lastFrameTime = now;
|
|
@@ -1021,7 +645,7 @@
|
|
|
1021
645
|
while (_accumulated >= _fpsInterval) {
|
|
1022
646
|
updated++;
|
|
1023
647
|
_accumulated -= _fpsInterval;
|
|
1024
|
-
let dt = _fpsInterval / 1e3 * _timeScale;
|
|
648
|
+
let dt = (_fpsInterval / 1e3) * _timeScale;
|
|
1025
649
|
instance.emit("update", dt, updated);
|
|
1026
650
|
instance.def("T", instance.T + dt);
|
|
1027
651
|
}
|
|
@@ -1049,7 +673,9 @@
|
|
|
1049
673
|
_canvas.oncontextmenu = () => false;
|
|
1050
674
|
}
|
|
1051
675
|
function resizeCanvas() {
|
|
1052
|
-
const width = settings.width > 0 ? settings.width : innerWidth,
|
|
676
|
+
const width = settings.width > 0 ? settings.width : innerWidth,
|
|
677
|
+
height =
|
|
678
|
+
settings.width > 0 ? settings.height || settings.width : innerHeight;
|
|
1053
679
|
instance.def("W", width);
|
|
1054
680
|
instance.def("H", height);
|
|
1055
681
|
_canvas.width = width;
|
|
@@ -1061,7 +687,8 @@
|
|
|
1061
687
|
_canvas.style.margin = "auto";
|
|
1062
688
|
}
|
|
1063
689
|
_canvasScale = math.min(innerWidth / width, innerHeight / height);
|
|
1064
|
-
_canvasScale =
|
|
690
|
+
_canvasScale =
|
|
691
|
+
maxScale > 1 && _canvasScale > maxScale ? maxScale : _canvasScale;
|
|
1065
692
|
_canvas.style.width = width * _canvasScale + "px";
|
|
1066
693
|
_canvas.style.height = height * _canvasScale + "px";
|
|
1067
694
|
}
|
|
@@ -1104,7 +731,5 @@
|
|
|
1104
731
|
}
|
|
1105
732
|
return instance;
|
|
1106
733
|
}
|
|
1107
|
-
|
|
1108
|
-
// src/web.js
|
|
1109
734
|
window.litecanvas = litecanvas;
|
|
1110
735
|
})();
|