littlejsengine 1.6.6 → 1.7.1
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 +76 -53
- package/build/littlejs.d.ts +154 -136
- package/build/littlejs.esm.js +461 -305
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +452 -291
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +2317 -2168
- package/examples/breakout/game.js +5 -1
- package/examples/breakout/index.html +5 -5
- package/examples/breakoutTutorial/README.md +6 -6
- package/examples/breakoutTutorial/game.js +3 -0
- package/examples/breakoutTutorial/index.html +3 -3
- package/examples/electron/build.js +105 -0
- package/examples/electron/game.js +4 -2
- package/examples/electron/index.html +13 -2
- package/examples/electron/package.json +5 -3
- package/examples/empty/game.js +3 -1
- package/examples/empty/index.html +1 -1
- package/examples/js13k/build.bat +2 -0
- package/examples/js13k/build.js +110 -0
- package/examples/js13k/game.js +109 -0
- package/examples/js13k/index.html +18 -0
- package/examples/js13k/tiles.png +0 -0
- package/examples/module/game.js +9 -3
- package/examples/module/index.html +2 -2
- package/examples/particles/index.html +7 -13
- package/examples/platformer/game.js +5 -2
- package/examples/platformer/gameEffects.js +12 -12
- package/examples/platformer/gamePlayer.js +2 -2
- package/examples/platformer/index.html +8 -8
- package/examples/puzzle/game.js +5 -3
- package/examples/puzzle/index.html +4 -4
- package/examples/starter/build.bat +2 -78
- package/examples/starter/build.js +109 -0
- package/examples/starter/game.js +4 -1
- package/examples/starter/index.html +15 -18
- package/examples/stress/index.html +5 -7
- package/examples/typescript/build.bat +2 -14
- package/examples/typescript/build.js +31 -0
- package/examples/typescript/game.js +94 -89
- package/examples/typescript/game.ts +9 -3
- package/examples/typescript/index.html +2 -2
- package/package.json +2 -2
- package/src/engine.js +3 -3
- package/src/engineAudio.js +44 -16
- package/src/engineBuild.bat +2 -132
- package/src/engineBuild.js +156 -0
- package/src/engineDebug.js +25 -15
- package/src/engineDraw.js +62 -53
- package/src/engineExport.js +7 -12
- package/src/engineInput.js +27 -35
- package/src/engineObject.js +15 -13
- package/src/engineParticles.js +6 -6
- package/src/engineRelease.js +1 -3
- package/src/engineSettings.js +1 -0
- package/src/engineTileLayer.js +31 -18
- package/src/engineUtilities.js +161 -93
- package/src/engineWebGL.js +63 -27
- package/examples/electron/build.bat +0 -52
package/src/engineUtilities.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* - Vector2 - fast, simple, easy 2D vector class
|
|
5
5
|
* - Color - holds a rgba color with some math functions
|
|
6
6
|
* - Timer - tracks time automatically
|
|
7
|
+
* - RandomGenerator - seeded random number generator
|
|
7
8
|
* @namespace Utilities
|
|
8
9
|
*/
|
|
9
10
|
|
|
@@ -19,34 +20,34 @@ const PI = Math.PI;
|
|
|
19
20
|
* @param {Number} value
|
|
20
21
|
* @return {Number}
|
|
21
22
|
* @memberof Utilities */
|
|
22
|
-
function abs(
|
|
23
|
+
function abs(value) { return Math.abs(value); }
|
|
23
24
|
|
|
24
25
|
/** Returns lowest of two values passed in
|
|
25
26
|
* @param {Number} valueA
|
|
26
27
|
* @param {Number} valueB
|
|
27
28
|
* @return {Number}
|
|
28
29
|
* @memberof Utilities */
|
|
29
|
-
function min(
|
|
30
|
+
function min(valueA, valueB) { return Math.min(valueA, valueB); }
|
|
30
31
|
|
|
31
32
|
/** Returns highest of two values passed in
|
|
32
33
|
* @param {Number} valueA
|
|
33
34
|
* @param {Number} valueB
|
|
34
35
|
* @return {Number}
|
|
35
36
|
* @memberof Utilities */
|
|
36
|
-
function max(
|
|
37
|
+
function max(valueA, valueB) { return Math.max(valueA, valueB); }
|
|
37
38
|
|
|
38
39
|
/** Returns the sign of value passed in (also returns 1 if 0)
|
|
39
40
|
* @param {Number} value
|
|
40
41
|
* @return {Number}
|
|
41
42
|
* @memberof Utilities */
|
|
42
|
-
function sign(
|
|
43
|
+
function sign(value) { return Math.sign(value); }
|
|
43
44
|
|
|
44
45
|
/** Returns first parm modulo the second param, but adjusted so negative numbers work as expected
|
|
45
46
|
* @param {Number} dividend
|
|
46
47
|
* @param {Number} [divisor=1]
|
|
47
48
|
* @return {Number}
|
|
48
49
|
* @memberof Utilities */
|
|
49
|
-
function mod(
|
|
50
|
+
function mod(dividend, divisor=1) { return ((dividend % divisor) + divisor) % divisor; }
|
|
50
51
|
|
|
51
52
|
/** Clamps the value beween max and min
|
|
52
53
|
* @param {Number} value
|
|
@@ -54,47 +55,83 @@ function mod(a, b=1) { return ((a % b) + b) % b; }
|
|
|
54
55
|
* @param {Number} [max=1]
|
|
55
56
|
* @return {Number}
|
|
56
57
|
* @memberof Utilities */
|
|
57
|
-
function clamp(
|
|
58
|
-
{ return v < min ? min : v > max ? max : v; }
|
|
58
|
+
function clamp(value, min=0, max=1) { return value < min ? min : value > max ? max : value; }
|
|
59
59
|
|
|
60
|
-
/** Returns what percentage the value is between
|
|
60
|
+
/** Returns what percentage the value is between valueA and valueB
|
|
61
61
|
* @param {Number} value
|
|
62
|
-
* @param {Number}
|
|
63
|
-
* @param {Number}
|
|
62
|
+
* @param {Number} valueA
|
|
63
|
+
* @param {Number} valueB
|
|
64
64
|
* @return {Number}
|
|
65
65
|
* @memberof Utilities */
|
|
66
|
-
function percent(
|
|
67
|
-
{ return
|
|
66
|
+
function percent(value, valueA, valueB)
|
|
67
|
+
{ return valueB-valueA ? clamp((value-valueA) / (valueB-valueA)) : 0; }
|
|
68
68
|
|
|
69
|
-
/** Linearly interpolates
|
|
69
|
+
/** Linearly interpolates between values passed in using percent
|
|
70
70
|
* @param {Number} percent
|
|
71
|
-
* @param {Number}
|
|
72
|
-
* @param {Number}
|
|
71
|
+
* @param {Number} valueA
|
|
72
|
+
* @param {Number} valueB
|
|
73
73
|
* @return {Number}
|
|
74
74
|
* @memberof Utilities */
|
|
75
|
-
function lerp(
|
|
75
|
+
function lerp(percent, valueA, valueB) { return valueA + clamp(percent) * (valueB-valueA); }
|
|
76
|
+
|
|
77
|
+
/** Returns signed wrapped distance between the two values passed in
|
|
78
|
+
* @param {Number} valueA
|
|
79
|
+
* @param {Number} valueB
|
|
80
|
+
* @param {Number} [wrapSize=1]
|
|
81
|
+
* @returns {Number}
|
|
82
|
+
* @memberof Utilities */
|
|
83
|
+
function distanceWrap(valueA, valueB, wrapSize=1)
|
|
84
|
+
{ const d = (valueA - valueB) % wrapSize; return d*2 % wrapSize - d; }
|
|
85
|
+
|
|
86
|
+
/** Linearly interpolates between values passed in with wrappping
|
|
87
|
+
* @param {Number} percent
|
|
88
|
+
* @param {Number} valueA
|
|
89
|
+
* @param {Number} valueB
|
|
90
|
+
* @param {Number} [wrapSize=1]
|
|
91
|
+
* @returns {Number}
|
|
92
|
+
* @memberof Utilities */
|
|
93
|
+
function lerpWrap(percent, valueA, valueB, wrapSize=1)
|
|
94
|
+
{ return valueB + clamp(percent) * distanceWrap(valueA, valueB, wrapSize); }
|
|
95
|
+
|
|
96
|
+
/** Returns signed wrapped distance between the two angles passed in
|
|
97
|
+
* @param {Number} angleA
|
|
98
|
+
* @param {Number} angleB
|
|
99
|
+
* @returns {Number}
|
|
100
|
+
* @memberof Utilities */
|
|
101
|
+
function distanceAngle(angleA, angleB) { distanceWrap(angleA, angleB, 2*PI); }
|
|
102
|
+
|
|
103
|
+
/** Linearly interpolates between the angles passed in with wrappping
|
|
104
|
+
* @param {Number} percent
|
|
105
|
+
* @param {Number} angleA
|
|
106
|
+
* @param {Number} angleB
|
|
107
|
+
* @returns {Number}
|
|
108
|
+
* @memberof Utilities */
|
|
109
|
+
function lerpAngle(percent, angleA, angleB) { return lerpWrap(percent, angleA, angleB, 2*PI); }
|
|
76
110
|
|
|
77
111
|
/** Applies smoothstep function to the percentage value
|
|
78
|
-
* @param {Number}
|
|
112
|
+
* @param {Number} percent
|
|
79
113
|
* @return {Number}
|
|
80
114
|
* @memberof Utilities */
|
|
81
|
-
function smoothStep(
|
|
115
|
+
function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
82
116
|
|
|
83
117
|
/** Returns the nearest power of two not less then the value
|
|
84
118
|
* @param {Number} value
|
|
85
119
|
* @return {Number}
|
|
86
120
|
* @memberof Utilities */
|
|
87
|
-
function nearestPowerOfTwo(
|
|
121
|
+
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
88
122
|
|
|
89
123
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
90
124
|
* @param {Vector2} pointA - Center of box A
|
|
91
125
|
* @param {Vector2} sizeA - Size of box A
|
|
92
126
|
* @param {Vector2} pointB - Center of box B
|
|
93
|
-
* @param {Vector2}
|
|
127
|
+
* @param {Vector2} sizeB - Size of box B
|
|
94
128
|
* @return {Boolean} - True if overlapping
|
|
95
129
|
* @memberof Utilities */
|
|
96
|
-
function isOverlapping(
|
|
97
|
-
{
|
|
130
|
+
function isOverlapping(pointA, sizeA, pointB, sizeB)
|
|
131
|
+
{
|
|
132
|
+
return abs(pointA.x - pointB.x)*2 < sizeA.x + sizeB.x
|
|
133
|
+
&& abs(pointA.y - pointB.y)*2 < sizeA.y + sizeB.y;
|
|
134
|
+
}
|
|
98
135
|
|
|
99
136
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
100
137
|
* @param {Number} [frequency=1] - Frequency of the wave in Hz
|
|
@@ -121,20 +158,26 @@ function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
|
|
|
121
158
|
* @param {Number} [valueB=0]
|
|
122
159
|
* @return {Number}
|
|
123
160
|
* @memberof Random */
|
|
124
|
-
function rand(
|
|
161
|
+
function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valueB); }
|
|
125
162
|
|
|
126
163
|
/** Returns a floored random value the two values passed in
|
|
127
|
-
* @param {Number}
|
|
164
|
+
* @param {Number} valueA
|
|
128
165
|
* @param {Number} [valueB=0]
|
|
129
166
|
* @return {Number}
|
|
130
167
|
* @memberof Random */
|
|
131
|
-
function randInt(
|
|
168
|
+
function randInt(valueA, valueB=0) { return Math.floor(rand(valueA,valueB)); }
|
|
132
169
|
|
|
133
170
|
/** Randomly returns either -1 or 1
|
|
134
171
|
* @return {Number}
|
|
135
172
|
* @memberof Random */
|
|
136
173
|
function randSign() { return randInt(2) * 2 - 1; }
|
|
137
174
|
|
|
175
|
+
/** Returns a random Vector2 with the passed in length
|
|
176
|
+
* @param {Number} [length=1]
|
|
177
|
+
* @return {Vector2}
|
|
178
|
+
* @memberof Random */
|
|
179
|
+
function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length); }
|
|
180
|
+
|
|
138
181
|
/** Returns a random Vector2 within a circular shape
|
|
139
182
|
* @param {Number} [radius=1]
|
|
140
183
|
* @param {Number} [minRadius=0]
|
|
@@ -143,44 +186,62 @@ function randSign() { return randInt(2) * 2 - 1; }
|
|
|
143
186
|
function randInCircle(radius=1, minRadius=0)
|
|
144
187
|
{ return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
|
|
145
188
|
|
|
146
|
-
/** Returns a random Vector2 with the passed in length
|
|
147
|
-
* @param {Number} [length=1]
|
|
148
|
-
* @return {Vector2}
|
|
149
|
-
* @memberof Random */
|
|
150
|
-
function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length); }
|
|
151
|
-
|
|
152
189
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
153
190
|
* @param {Color} [colorA=Color()]
|
|
154
191
|
* @param {Color} [colorB=Color(0,0,0,1)]
|
|
155
192
|
* @param {Boolean} [linear]
|
|
156
193
|
* @return {Color}
|
|
157
194
|
* @memberof Random */
|
|
158
|
-
function randColor(
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
* @default
|
|
164
|
-
* @memberof Random */
|
|
165
|
-
let randSeed = 1;
|
|
195
|
+
function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear)
|
|
196
|
+
{
|
|
197
|
+
return linear ? colorA.lerp(colorB, rand()) :
|
|
198
|
+
new Color(rand(colorA.r,colorB.r), rand(colorA.g,colorB.g), rand(colorA.b,colorB.b), rand(colorA.a,colorB.a));
|
|
199
|
+
}
|
|
166
200
|
|
|
167
|
-
|
|
168
|
-
* @param {Number} seed
|
|
169
|
-
* @memberof Random */
|
|
170
|
-
function setRandSeed(seed) { randSeed = seed; }
|
|
201
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
171
202
|
|
|
172
|
-
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Seeded random number generator
|
|
205
|
+
* - Can be used to create a deterministic random number sequence
|
|
206
|
+
* @example
|
|
207
|
+
* let r = new RandomGenerator(123); // random number generator with seed 123
|
|
208
|
+
* let a = r.rand(); // random value between 0 and 1
|
|
209
|
+
* let b = r.randInt(10); // random integer between 0 and 9
|
|
210
|
+
* r.seed = 123; // reset the seed
|
|
211
|
+
* let c = r.rand(); // the same value as a
|
|
212
|
+
*/
|
|
213
|
+
class RandomGenerator
|
|
178
214
|
{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
215
|
+
/** Create a random number generator with the seed passed in
|
|
216
|
+
* @param {Number} seed - Starting seed */
|
|
217
|
+
constructor(seed)
|
|
218
|
+
{
|
|
219
|
+
/** @property {Number} - random seed */
|
|
220
|
+
this.seed = seed;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Returns a seeded random value between the two values passed in
|
|
224
|
+
* @param {Number} [valueA=1]
|
|
225
|
+
* @param {Number} [valueB=0]
|
|
226
|
+
* @return {Number} */
|
|
227
|
+
float(valueA=1, valueB=0)
|
|
228
|
+
{
|
|
229
|
+
// xorshift algorithm
|
|
230
|
+
this.seed ^= this.seed << 13;
|
|
231
|
+
this.seed ^= this.seed >>> 17;
|
|
232
|
+
this.seed ^= this.seed << 5;
|
|
233
|
+
return valueB + (valueA - valueB) * abs(this.seed % 1e9) / 1e9;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Returns a floored seeded random value the two values passed in
|
|
237
|
+
* @param {Number} valueA
|
|
238
|
+
* @param {Number} [valueB=0]
|
|
239
|
+
* @return {Number} */
|
|
240
|
+
int(valueA, valueB=0) { return Math.floor(this.rand(valueA, valueB)); }
|
|
241
|
+
|
|
242
|
+
/** Randomly returns either -1 or 1 deterministically
|
|
243
|
+
* @return {Number} */
|
|
244
|
+
sign() { return this.randInt(2) * 2 - 1; }
|
|
184
245
|
}
|
|
185
246
|
|
|
186
247
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -202,7 +263,7 @@ function vec2(x=0, y)
|
|
|
202
263
|
|
|
203
264
|
/**
|
|
204
265
|
* Check if object is a valid Vector2
|
|
205
|
-
* @param {Vector2}
|
|
266
|
+
* @param {Vector2} v
|
|
206
267
|
* @return {Boolean}
|
|
207
268
|
* @memberof Utilities
|
|
208
269
|
*/
|
|
@@ -235,27 +296,27 @@ class Vector2
|
|
|
235
296
|
copy() { return new Vector2(this.x, this.y); }
|
|
236
297
|
|
|
237
298
|
/** Returns a copy of this vector plus the vector passed in
|
|
238
|
-
* @param {Vector2} vector
|
|
299
|
+
* @param {Vector2} v - other vector
|
|
239
300
|
* @return {Vector2} */
|
|
240
301
|
add(v) { ASSERT(isVector2(v)); return new Vector2(this.x + v.x, this.y + v.y); }
|
|
241
302
|
|
|
242
303
|
/** Returns a copy of this vector minus the vector passed in
|
|
243
|
-
* @param {Vector2} vector
|
|
304
|
+
* @param {Vector2} v - other vector
|
|
244
305
|
* @return {Vector2} */
|
|
245
306
|
subtract(v) { ASSERT(isVector2(v)); return new Vector2(this.x - v.x, this.y - v.y); }
|
|
246
307
|
|
|
247
308
|
/** Returns a copy of this vector times the vector passed in
|
|
248
|
-
* @param {Vector2} vector
|
|
309
|
+
* @param {Vector2} v - other vector
|
|
249
310
|
* @return {Vector2} */
|
|
250
311
|
multiply(v) { ASSERT(isVector2(v)); return new Vector2(this.x * v.x, this.y * v.y); }
|
|
251
312
|
|
|
252
313
|
/** Returns a copy of this vector divided by the vector passed in
|
|
253
|
-
* @param {Vector2} vector
|
|
314
|
+
* @param {Vector2} v - other vector
|
|
254
315
|
* @return {Vector2} */
|
|
255
316
|
divide(v) { ASSERT(isVector2(v)); return new Vector2(this.x / v.x, this.y / v.y); }
|
|
256
317
|
|
|
257
318
|
/** Returns a copy of this vector scaled by the vector passed in
|
|
258
|
-
* @param {Number} scale
|
|
319
|
+
* @param {Number} s - scale
|
|
259
320
|
* @return {Vector2} */
|
|
260
321
|
scale(s) { ASSERT(!isVector2(s)); return new Vector2(this.x * s, this.y * s); }
|
|
261
322
|
|
|
@@ -268,12 +329,12 @@ class Vector2
|
|
|
268
329
|
lengthSquared() { return this.x**2 + this.y**2; }
|
|
269
330
|
|
|
270
331
|
/** Returns the distance from this vector to vector passed in
|
|
271
|
-
* @param {Vector2} vector
|
|
332
|
+
* @param {Vector2} v - other vector
|
|
272
333
|
* @return {Number} */
|
|
273
334
|
distance(v) { return this.distanceSquared(v)**.5; }
|
|
274
335
|
|
|
275
336
|
/** Returns the distance squared from this vector to vector passed in
|
|
276
|
-
* @param {Vector2} vector
|
|
337
|
+
* @param {Vector2} v - other vector
|
|
277
338
|
* @return {Number} */
|
|
278
339
|
distanceSquared(v) { return (this.x - v.x)**2 + (this.y - v.y)**2; }
|
|
279
340
|
|
|
@@ -288,12 +349,12 @@ class Vector2
|
|
|
288
349
|
clampLength(length=1) { const l = this.length(); return l > length ? this.scale(length/l) : this; }
|
|
289
350
|
|
|
290
351
|
/** Returns the dot product of this and the vector passed in
|
|
291
|
-
* @param {Vector2} vector
|
|
352
|
+
* @param {Vector2} v - other vector
|
|
292
353
|
* @return {Number} */
|
|
293
354
|
dot(v) { ASSERT(isVector2(v)); return this.x*v.x + this.y*v.y; }
|
|
294
355
|
|
|
295
356
|
/** Returns the cross product of this and the vector passed in
|
|
296
|
-
* @param {Vector2} vector
|
|
357
|
+
* @param {Vector2} v - other vector
|
|
297
358
|
* @return {Number} */
|
|
298
359
|
cross(v) { ASSERT(isVector2(v)); return this.x*v.y - this.y*v.x; }
|
|
299
360
|
|
|
@@ -305,12 +366,17 @@ class Vector2
|
|
|
305
366
|
* @param {Number} [angle=0]
|
|
306
367
|
* @param {Number} [length=1]
|
|
307
368
|
* @return {Vector2} */
|
|
308
|
-
setAngle(
|
|
369
|
+
setAngle(angle=0, length=1)
|
|
370
|
+
{ this.x = length*Math.sin(angle); this.y = length*Math.cos(angle); return this; }
|
|
309
371
|
|
|
310
372
|
/** Returns copy of this vector rotated by the angle passed in
|
|
311
373
|
* @param {Number} angle
|
|
312
374
|
* @return {Vector2} */
|
|
313
|
-
rotate(
|
|
375
|
+
rotate(angle)
|
|
376
|
+
{
|
|
377
|
+
const c = Math.cos(angle), s = Math.sin(angle);
|
|
378
|
+
return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
|
|
379
|
+
}
|
|
314
380
|
|
|
315
381
|
/** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
316
382
|
* @return {Number} */
|
|
@@ -329,10 +395,11 @@ class Vector2
|
|
|
329
395
|
area() { return abs(this.x * this.y); }
|
|
330
396
|
|
|
331
397
|
/** Returns a new vector that is p percent between this and the vector passed in
|
|
332
|
-
* @param {Vector2} vector
|
|
398
|
+
* @param {Vector2} v - other vector
|
|
333
399
|
* @param {Number} percent
|
|
334
400
|
* @return {Vector2} */
|
|
335
|
-
lerp(v,
|
|
401
|
+
lerp(v, percent)
|
|
402
|
+
{ ASSERT(isVector2(v)); return this.add(v.subtract(this).scale(clamp(percent))); }
|
|
336
403
|
|
|
337
404
|
/** Returns true if this vector is within the bounds of an array size passed in
|
|
338
405
|
* @param {Vector2} arraySize
|
|
@@ -350,10 +417,10 @@ class Vector2
|
|
|
350
417
|
|
|
351
418
|
/**
|
|
352
419
|
* Create a color object with RGBA values
|
|
353
|
-
* @param {Number} [r=1]
|
|
354
|
-
* @param {Number} [g=1]
|
|
355
|
-
* @param {Number} [b=1]
|
|
356
|
-
* @param {Number} [a=1]
|
|
420
|
+
* @param {Number} [r=1] - red
|
|
421
|
+
* @param {Number} [g=1] - green
|
|
422
|
+
* @param {Number} [b=1] - blue
|
|
423
|
+
* @param {Number} [a=1] - alpha
|
|
357
424
|
* @return {Color}
|
|
358
425
|
* @memberof Utilities
|
|
359
426
|
*/
|
|
@@ -361,10 +428,10 @@ function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
|
361
428
|
|
|
362
429
|
/**
|
|
363
430
|
* Create a color object with HSLA values
|
|
364
|
-
* @param {Number} [h=0]
|
|
365
|
-
* @param {Number} [s=0]
|
|
366
|
-
* @param {Number} [l=1]
|
|
367
|
-
* @param {Number} [a=1]
|
|
431
|
+
* @param {Number} [h=0] - hue
|
|
432
|
+
* @param {Number} [s=0] - saturation
|
|
433
|
+
* @param {Number} [l=1] - lightness
|
|
434
|
+
* @param {Number} [a=1] - alpha
|
|
368
435
|
* @return {Color}
|
|
369
436
|
* @memberof Utilities
|
|
370
437
|
*/
|
|
@@ -381,11 +448,11 @@ function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
|
381
448
|
*/
|
|
382
449
|
class Color
|
|
383
450
|
{
|
|
384
|
-
/** Create a color with the components passed in, white by default
|
|
385
|
-
* @param {Number} [
|
|
386
|
-
* @param {Number} [
|
|
387
|
-
* @param {Number} [
|
|
388
|
-
* @param {Number} [
|
|
451
|
+
/** Create a color with the rgba components passed in, white by default
|
|
452
|
+
* @param {Number} [r=1] - red
|
|
453
|
+
* @param {Number} [g=1] - green
|
|
454
|
+
* @param {Number} [b=1] - blue
|
|
455
|
+
* @param {Number} [a=1] - alpha*/
|
|
389
456
|
constructor(r=1, g=1, b=1, a=1)
|
|
390
457
|
{
|
|
391
458
|
/** @property {Number} - Red */
|
|
@@ -403,22 +470,22 @@ class Color
|
|
|
403
470
|
copy() { return new Color(this.r, this.g, this.b, this.a); }
|
|
404
471
|
|
|
405
472
|
/** Returns a copy of this color plus the color passed in
|
|
406
|
-
* @param {Color} color
|
|
473
|
+
* @param {Color} c - other color
|
|
407
474
|
* @return {Color} */
|
|
408
475
|
add(c) { return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a); }
|
|
409
476
|
|
|
410
477
|
/** Returns a copy of this color minus the color passed in
|
|
411
|
-
* @param {Color} color
|
|
478
|
+
* @param {Color} c - other color
|
|
412
479
|
* @return {Color} */
|
|
413
480
|
subtract(c) { return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a); }
|
|
414
481
|
|
|
415
482
|
/** Returns a copy of this color times the color passed in
|
|
416
|
-
* @param {Color} color
|
|
483
|
+
* @param {Color} c - other color
|
|
417
484
|
* @return {Color} */
|
|
418
485
|
multiply(c) { return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a); }
|
|
419
486
|
|
|
420
487
|
/** Returns a copy of this color divided by the color passed in
|
|
421
|
-
* @param {Color} color
|
|
488
|
+
* @param {Color} c - other color
|
|
422
489
|
* @return {Color} */
|
|
423
490
|
divide(c) { return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a); }
|
|
424
491
|
|
|
@@ -426,23 +493,24 @@ class Color
|
|
|
426
493
|
* @param {Number} scale
|
|
427
494
|
* @param {Number} [alphaScale=scale]
|
|
428
495
|
* @return {Color} */
|
|
429
|
-
scale(
|
|
496
|
+
scale(scale, alphaScale=scale)
|
|
497
|
+
{ return new Color(this.r*scale, this.g*scale, this.b*scale, this.a*alphaScale); }
|
|
430
498
|
|
|
431
499
|
/** Returns a copy of this color clamped to the valid range between 0 and 1
|
|
432
500
|
* @return {Color} */
|
|
433
501
|
clamp() { return new Color(clamp(this.r), clamp(this.g), clamp(this.b), clamp(this.a)); }
|
|
434
502
|
|
|
435
503
|
/** Returns a new color that is p percent between this and the color passed in
|
|
436
|
-
* @param {Color} color
|
|
504
|
+
* @param {Color} c - other color
|
|
437
505
|
* @param {Number} percent
|
|
438
506
|
* @return {Color} */
|
|
439
|
-
lerp(c,
|
|
507
|
+
lerp(c, percent) { return this.add(c.subtract(this).scale(clamp(percent))); }
|
|
440
508
|
|
|
441
509
|
/** Sets this color given a hue, saturation, lightness, and alpha
|
|
442
|
-
* @param {Number} [
|
|
443
|
-
* @param {Number} [
|
|
444
|
-
* @param {Number} [
|
|
445
|
-
* @param {Number} [
|
|
510
|
+
* @param {Number} [h=0] - hue
|
|
511
|
+
* @param {Number} [s=0] - saturation
|
|
512
|
+
* @param {Number} [l=1] - lightness
|
|
513
|
+
* @param {Number} [a=1] - alpha
|
|
446
514
|
* @return {Color} */
|
|
447
515
|
setHSLA(h=0, s=0, l=1, a=1)
|
|
448
516
|
{
|
|
@@ -583,7 +651,7 @@ class Timer
|
|
|
583
651
|
|
|
584
652
|
/** Returns this timer expressed as a string
|
|
585
653
|
* @return {String} */
|
|
586
|
-
toString() { if (debug) { return this.
|
|
654
|
+
toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
|
|
587
655
|
|
|
588
656
|
/** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
|
|
589
657
|
* @return {Number} */
|
package/src/engineWebGL.js
CHANGED
|
@@ -203,8 +203,8 @@ function glFlush()
|
|
|
203
203
|
|
|
204
204
|
// draw all the sprites in the batch and reset the buffer
|
|
205
205
|
glContext.bufferSubData(gl_ARRAY_BUFFER, 0,
|
|
206
|
-
glPositionData.subarray(0, glBatchCount *
|
|
207
|
-
glContext.drawArrays(
|
|
206
|
+
glPositionData.subarray(0, glBatchCount * gl_INDICIES_PER_VERT));
|
|
207
|
+
glContext.drawArrays(gl_TRIANGLE_STRIP, 0, glBatchCount);
|
|
208
208
|
glBatchCount = 0;
|
|
209
209
|
glBatchAdditive = glAdditive;
|
|
210
210
|
}
|
|
@@ -225,39 +225,75 @@ function glCopyToContext(context, forceDraw)
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
/** Add a sprite to the gl draw list, used by all gl draw functions
|
|
228
|
-
* @param x
|
|
229
|
-
* @param y
|
|
230
|
-
* @param sizeX
|
|
231
|
-
* @param sizeY
|
|
232
|
-
* @param angle
|
|
233
|
-
* @param uv0X
|
|
234
|
-
* @param uv0Y
|
|
235
|
-
* @param uv1X
|
|
236
|
-
* @param uv1Y
|
|
237
|
-
* @param rgba
|
|
238
|
-
* @param [rgbaAdditive=0]
|
|
228
|
+
* @param {Number} x
|
|
229
|
+
* @param {Number} y
|
|
230
|
+
* @param {Number} sizeX
|
|
231
|
+
* @param {Number} sizeY
|
|
232
|
+
* @param {Number} angle
|
|
233
|
+
* @param {Number} uv0X
|
|
234
|
+
* @param {Number} uv0Y
|
|
235
|
+
* @param {Number} uv1X
|
|
236
|
+
* @param {Number} uv1Y
|
|
237
|
+
* @param {Number} rgba
|
|
238
|
+
* @param {Number} [rgbaAdditive=0]
|
|
239
239
|
* @memberof WebGL */
|
|
240
240
|
function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdditive=0)
|
|
241
241
|
{
|
|
242
|
-
// flush if there is
|
|
243
|
-
|
|
242
|
+
// flush if there is not enough room or if different blend mode
|
|
243
|
+
const vertCount = 6;
|
|
244
|
+
if (glBatchCount >= gl_MAX_BATCH-vertCount || glBatchAdditive != glAdditive)
|
|
244
245
|
glFlush();
|
|
245
246
|
|
|
246
247
|
// prepare to create the verts from size and angle
|
|
247
248
|
const c = Math.cos(angle)/2, s = Math.sin(angle)/2;
|
|
248
249
|
const cx = c*sizeX, cy = c*sizeY, sx = s*sizeX, sy = s*sizeY;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
const positionData =
|
|
251
|
+
[
|
|
252
|
+
x-cx+sy, y+cy+sx, uv0X, uv0Y,
|
|
253
|
+
x-cx-sy, y-cy+sx, uv0X, uv1Y,
|
|
254
|
+
x+cx+sy, y+cy-sx, uv1X, uv0Y,
|
|
255
|
+
x+cx-sy, y-cy-sx, uv1X, uv1Y,
|
|
256
|
+
];
|
|
257
|
+
|
|
258
|
+
// setup 2 triangle strip quad
|
|
259
|
+
for(let i = vertCount, offset = glBatchCount * gl_INDICIES_PER_VERT; i--;)
|
|
252
260
|
{
|
|
253
|
-
|
|
254
|
-
glPositionData[offset++] =
|
|
255
|
-
glPositionData[offset++] =
|
|
256
|
-
glPositionData[offset++] =
|
|
257
|
-
glPositionData[offset++] =
|
|
261
|
+
let j = clamp(i-1, 0, 3)*4; // degenerate tri at ends
|
|
262
|
+
glPositionData[offset++] = positionData[j++];
|
|
263
|
+
glPositionData[offset++] = positionData[j++];
|
|
264
|
+
glPositionData[offset++] = positionData[j++];
|
|
265
|
+
glPositionData[offset++] = positionData[j++];
|
|
258
266
|
glColorData[offset++] = rgba;
|
|
259
267
|
glColorData[offset++] = rgbaAdditive;
|
|
260
268
|
}
|
|
269
|
+
glBatchCount += vertCount;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Add a convex polygon to the gl draw list
|
|
273
|
+
* @param {Array} points - Array of Vector2 points
|
|
274
|
+
* @param {Number} rgba - Color of the polygon
|
|
275
|
+
* @memberof WebGL */
|
|
276
|
+
function glDrawPoints(points, rgba)
|
|
277
|
+
{
|
|
278
|
+
// flush if there is not enough room or if different blend mode
|
|
279
|
+
const vertCount = points.length + 2;
|
|
280
|
+
if (glBatchCount >= gl_MAX_BATCH-vertCount || glBatchAdditive != glAdditive)
|
|
281
|
+
glFlush();
|
|
282
|
+
|
|
283
|
+
// setup triangle strip from list of points
|
|
284
|
+
for(let i = vertCount, offset = glBatchCount * gl_INDICIES_PER_VERT; i--;)
|
|
285
|
+
{
|
|
286
|
+
const j = clamp(i-1, 0, vertCount-3); // degenerate tri at ends
|
|
287
|
+
const h = j>>1;
|
|
288
|
+
const point = points[j%2? h : vertCount-3-h];
|
|
289
|
+
glPositionData[offset++] = point.x;
|
|
290
|
+
glPositionData[offset++] = point.y;
|
|
291
|
+
glPositionData[offset++] = 0; // uvx
|
|
292
|
+
glPositionData[offset++] = 0; // uvy
|
|
293
|
+
glColorData[offset++] = 0; // nothing to tint
|
|
294
|
+
glColorData[offset++] = rgba; // apply rgba via additive
|
|
295
|
+
}
|
|
296
|
+
glBatchCount += vertCount;
|
|
261
297
|
}
|
|
262
298
|
|
|
263
299
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -351,14 +387,14 @@ function glRenderPostProcess()
|
|
|
351
387
|
glContext.uniform1i(uniformLocation('iChannel0'), 0);
|
|
352
388
|
glContext.uniform1f(uniformLocation('iTime'), time);
|
|
353
389
|
glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
|
|
354
|
-
glContext.drawArrays(
|
|
390
|
+
glContext.drawArrays(gl_TRIANGLE_STRIP, 0, 3);
|
|
355
391
|
}
|
|
356
392
|
|
|
357
393
|
///////////////////////////////////////////////////////////////////////////////
|
|
358
394
|
// store gl constants as integers so their name doesn't use space in minifed
|
|
359
395
|
const
|
|
360
396
|
gl_ONE = 1,
|
|
361
|
-
|
|
397
|
+
gl_TRIANGLE_STRIP = 5,
|
|
362
398
|
gl_SRC_ALPHA = 770,
|
|
363
399
|
gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
364
400
|
gl_BLEND = 3042,
|
|
@@ -389,6 +425,6 @@ gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
|
389
425
|
// constants for batch rendering
|
|
390
426
|
gl_VERTICES_PER_QUAD = 6,
|
|
391
427
|
gl_INDICIES_PER_VERT = 6,
|
|
392
|
-
gl_MAX_BATCH =
|
|
428
|
+
gl_MAX_BATCH = 1e5,
|
|
393
429
|
gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2, // vec2 * 2 + (char * 4) * 2
|
|
394
|
-
gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH *
|
|
430
|
+
gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH * gl_VERTEX_BYTE_STRIDE;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
rem Simple build script for LittleJS by Frank Force
|
|
2
|
-
rem Minfies and combines index.html and index.js and zips the result
|
|
3
|
-
|
|
4
|
-
set NAME=game
|
|
5
|
-
set BUILD_FOLDER=build
|
|
6
|
-
set BUILD_FILENAME=index.js
|
|
7
|
-
|
|
8
|
-
rem remove old files
|
|
9
|
-
rmdir /s /q %BUILD_FOLDER%
|
|
10
|
-
mkdir %BUILD_FOLDER%
|
|
11
|
-
pushd %BUILD_FOLDER%
|
|
12
|
-
|
|
13
|
-
rem copy engine release build
|
|
14
|
-
type ..\..\..\build\littlejs.release.js >> %BUILD_FILENAME%
|
|
15
|
-
echo. >> %BUILD_FILENAME%
|
|
16
|
-
|
|
17
|
-
rem add your game's files to include here
|
|
18
|
-
type ..\game.js >> %BUILD_FILENAME%
|
|
19
|
-
echo. >> %BUILD_FILENAME%
|
|
20
|
-
|
|
21
|
-
rem copy images to build folder
|
|
22
|
-
copy ..\tiles.png tiles.png
|
|
23
|
-
|
|
24
|
-
rem minify code with uglify
|
|
25
|
-
call npx uglifyjs -o %BUILD_FILENAME% --compress --mangle -- %BUILD_FILENAME%
|
|
26
|
-
if %ERRORLEVEL% NEQ 0 (
|
|
27
|
-
pause
|
|
28
|
-
exit /b %ERRORLEVEL%
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
rem build the html, you can add html header and footers here
|
|
32
|
-
rem type ..\header.html >> index.html
|
|
33
|
-
echo ^<body^>^<script^> >> index.html
|
|
34
|
-
type %BUILD_FILENAME% >> index.html
|
|
35
|
-
echo ^</script^> >> index.html
|
|
36
|
-
|
|
37
|
-
rem delete intermediate files
|
|
38
|
-
del %BUILD_FILENAME%
|
|
39
|
-
|
|
40
|
-
rem copy elecron files to build folder
|
|
41
|
-
copy ..\electron.js electron.js
|
|
42
|
-
copy ..\package.json package.json
|
|
43
|
-
|
|
44
|
-
popd
|
|
45
|
-
|
|
46
|
-
rem build with electron
|
|
47
|
-
call npx electron-packager ./%BUILD_FOLDER% --overwrite
|
|
48
|
-
if %ERRORLEVEL% NEQ 0 (
|
|
49
|
-
pause
|
|
50
|
-
exit /b %ERRORLEVEL%
|
|
51
|
-
)
|
|
52
|
-
pause
|