littlejsengine 1.0.14 → 1.1.8

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.
Files changed (99) hide show
  1. package/build.bat +5 -1
  2. package/docs/Audio.html +2268 -0
  3. package/docs/Color.html +2989 -0
  4. package/docs/Debug.html +2933 -0
  5. package/docs/Draw.html +4092 -0
  6. package/docs/EngineObject.html +4458 -0
  7. package/docs/Input.html +2482 -0
  8. package/docs/Medal.html +1007 -0
  9. package/docs/Medals.html +628 -0
  10. package/docs/Music.html +584 -0
  11. package/docs/Newgrounds.html +1399 -0
  12. package/docs/Particle.html +4535 -0
  13. package/docs/ParticleEmitter.html +7770 -0
  14. package/docs/Random.html +1774 -0
  15. package/docs/Settings.html +2679 -0
  16. package/docs/Sound.html +1249 -0
  17. package/docs/TileCollision.html +1409 -0
  18. package/docs/TileLayer.html +6948 -0
  19. package/docs/TileLayerData.html +1052 -0
  20. package/docs/Timer.html +1183 -0
  21. package/docs/Utilities.html +3281 -0
  22. package/docs/Vector2.html +4207 -0
  23. package/docs/WebGL.html +2327 -0
  24. package/docs/engine.js.html +429 -0
  25. package/docs/engineAudio.js.html +609 -0
  26. package/docs/engineDebug.js.html +725 -0
  27. package/docs/engineDraw.js.html +419 -0
  28. package/docs/engineInput.js.html +401 -0
  29. package/docs/engineMedals.js.html +461 -0
  30. package/docs/engineObject.js.html +518 -0
  31. package/docs/engineParticles.js.html +441 -0
  32. package/docs/engineSettings.js.html +349 -0
  33. package/docs/engineTileLayer.js.html +513 -0
  34. package/docs/engineUtilities.js.html +647 -0
  35. package/docs/engineWebGL.js.html +522 -0
  36. package/docs/fonts/MavenPro-Regular.ttf +0 -0
  37. package/docs/fonts/Montserrat-Regular.ttf +0 -0
  38. package/docs/fonts/Muli-Black.ttf +0 -0
  39. package/docs/fonts/OFL-hind.txt +93 -0
  40. package/docs/fonts/OFL-montserrat.txt +93 -0
  41. package/docs/global.html +1691 -0
  42. package/docs/index.css +6 -0
  43. package/docs/index.html +247 -0
  44. package/docs/scripts/fix-code-block.js +53 -0
  45. package/docs/scripts/fix-navbar.js +25 -0
  46. package/docs/scripts/linenumber.js +25 -0
  47. package/docs/scripts/misc.js +217 -0
  48. package/docs/scripts/resize.js +85 -0
  49. package/docs/scripts/search.js +83 -0
  50. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  51. package/docs/scripts/third-party/fuse.js +9 -0
  52. package/docs/scripts/third-party/lang-css.js +2 -0
  53. package/docs/scripts/third-party/prettify.js +28 -0
  54. package/docs/static/favicon.png +0 -0
  55. package/docs/static/index.css +4 -0
  56. package/docs/styles/clean-jsdoc-theme-base.css +393 -0
  57. package/docs/styles/clean-jsdoc-theme-dark.css +324 -0
  58. package/docs/styles/clean-jsdoc-theme-light.css +319 -0
  59. package/docs/styles/reset.css +346 -0
  60. package/docs/styles/third-party/ionicons.min.css +11 -0
  61. package/docs/styles/third-party/prettify-jsdoc.css +111 -0
  62. package/docs/styles/third-party/prettify-tomorrow.css +5 -0
  63. package/engine/engine.all.js +1997 -744
  64. package/engine/engine.all.min.js +1 -1
  65. package/engine/engine.all.release.js +1743 -569
  66. package/engine/engine.js +107 -39
  67. package/engine/engineAudio.js +152 -34
  68. package/engine/{build.bat → engineBuild.bat} +10 -10
  69. package/engine/{buildSetup.bat → engineBuildSetup.bat} +0 -0
  70. package/engine/engineDebug.js +105 -32
  71. package/engine/engineDraw.js +137 -32
  72. package/engine/engineInput.js +111 -37
  73. package/engine/{engineMedal.js → engineMedals.js} +129 -56
  74. package/engine/engineObject.js +117 -67
  75. package/engine/engineParticles.js +282 -0
  76. package/engine/engineRelease.js +3 -9
  77. package/engine/engineSettings.js +190 -0
  78. package/engine/engineTileLayer.js +147 -44
  79. package/engine/engineUtilities.js +488 -0
  80. package/engine/engineWebGL.js +113 -74
  81. package/examples/breakout/game.js +1 -1
  82. package/examples/breakout/gameObjects.js +3 -3
  83. package/examples/breakout/index.html +3 -3
  84. package/examples/platformer/game.js +5 -7
  85. package/examples/platformer/gameEffects.js +7 -7
  86. package/examples/platformer/gameLevel.js +2 -2
  87. package/examples/platformer/gameObjects.js +4 -5
  88. package/examples/platformer/gamePlayer.js +3 -3
  89. package/examples/platformer/index.html +6 -6
  90. package/examples/puzzle/game.js +1 -2
  91. package/examples/puzzle/index.html +2 -2
  92. package/examples/stress/index.html +2 -8
  93. package/game.js +5 -11
  94. package/index.html +13 -13
  95. package/package.json +4 -4
  96. package/tiles.png +0 -0
  97. package/engine/engineConfig.js +0 -64
  98. package/engine/engineParticle.js +0 -199
  99. package/engine/engineUtil.js +0 -147
@@ -0,0 +1,488 @@
1
+ /**
2
+ * LittleJS Utility Classes and Functions
3
+ * <br> - General purpose math library
4
+ * <br> - Vector2 - fast, simple, easy 2D vector class
5
+ * <br> - Color - holds a rgba color with some math functions
6
+ * <br> - Timer - tracks time automatically
7
+ * @namespace Utilities
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ /** A shortcut to get Math.PI
13
+ * @const
14
+ * @memberof Utilities */
15
+ const PI = Math.PI;
16
+
17
+ /** True if running a Chromium based browser
18
+ * @const
19
+ * @memberof Utilities */
20
+ const isChrome = window['chrome'];
21
+
22
+ /** Returns absoulte value of value passed in
23
+ * @param {Number} value
24
+ * @return {Number}
25
+ * @memberof Utilities */
26
+ const abs = (a)=> a < 0 ? -a : a;
27
+
28
+ /** Returns the sign of value passed in
29
+ * @param {Number} value
30
+ * @return {Number}
31
+ * @memberof Utilities */
32
+ const sign = (a)=> a < 0 ? -1 : 1;
33
+
34
+ /** Returns lowest of two values passed in
35
+ * @param {Number} valueA
36
+ * @param {Number} valueB
37
+ * @return {Number}
38
+ * @memberof Utilities */
39
+ const min = (a, b)=> a < b ? a : b;
40
+
41
+ /** Returns highest of two values passed in
42
+ * @param {Number} valueA
43
+ * @param {Number} valueB
44
+ * @return {Number}
45
+ * @memberof Utilities */
46
+ const max = (a, b)=> a > b ? a : b;
47
+
48
+ /** Returns first parm modulo the second param, but adjusted so negative numbers work as expected
49
+ * @param {Number} dividend
50
+ * @param {Number} divisor
51
+ * @return {Number}
52
+ * @memberof Utilities */
53
+ const mod = (a, b)=> ((a % b) + b) % b;
54
+
55
+ /** Clamps the value beween max and min
56
+ * @param {Number} value
57
+ * @param {Number} [max=1]
58
+ * @param {Number} [min=0]
59
+ * @return {Number}
60
+ * @memberof Utilities */
61
+ const clamp = (v, max=1, min=0)=> (ASSERT(max > min), v < min ? min : v > max ? max : v);
62
+
63
+ /** Returns what percentage the value is between max and min
64
+ * @param {Number} value
65
+ * @param {Number} [max=1]
66
+ * @param {Number} [min=0]
67
+ * @return {Number}
68
+ * @memberof Utilities */
69
+ const percent = (v, max=1, min=0)=> max-min ? clamp((v-min) / (max-min)) : 0;
70
+
71
+ /** Linearly interpolates the percent value between max and min
72
+ * @param {Number} percent
73
+ * @param {Number} [max=1]
74
+ * @param {Number} [min=0]
75
+ * @return {Number}
76
+ * @memberof Utilities */
77
+ const lerp = (p, max=1, min=0)=> min + clamp(p) * (max-min);
78
+
79
+ /** Formats seconds to mm:ss style for display purposes
80
+ * @param {Number} t - time in seconds
81
+ * @return {String}
82
+ * @memberof Utilities */
83
+ const formatTime = (t)=> (t/60|0)+':'+(t%60<10?'0':'')+(t%60|0);
84
+
85
+ /** Returns the nearest power of two not less then the value
86
+ * @param {Number} value
87
+ * @return {Number}
88
+ * @memberof Utilities */
89
+ const nearestPowerOfTwo = (v)=> 2**Math.ceil(Math.log2(v));
90
+
91
+ /** Applies smoothstep function to the percentage value
92
+ * @param {Number} value
93
+ * @return {Number}
94
+ * @memberof Utilities */
95
+ const smoothStep = (p)=> p * p * (3 - 2 * p);
96
+
97
+ /** Returns true if two axis aligned bounding boxes are overlapping
98
+ * @param {Vector2} pointA - Center of box A
99
+ * @param {Vector2} sizeA - Size of box A
100
+ * @param {Vector2} pointB - Center of box B
101
+ * @param {Vector2} sizeB - Size of box B
102
+ * @return {Boolean} - True if overlapping
103
+ * @memberof Utilities */
104
+ const isOverlapping = (pA, sA, pB, sB)=> abs(pA.x - pB.x)*2 < sA.x + sB.x & abs(pA.y - pB.y)*2 < sA.y + sB.y;
105
+
106
+ /** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
107
+ * @param {Number} [frequency=1] - Frequency of the wave in Hz
108
+ * @param {Number} [amplitude=1] - Amplitude (max height) of the wave
109
+ * @param {Number} [t=time] - Value to use for time of the wave
110
+ * @return {Number} - Value waving between 0 and amplitude
111
+ * @memberof Utilities */
112
+ const wave = (frequency=1, amplitude=1, t=time)=> amplitude/2 * (1 - Math.cos(t*frequency*2*PI));
113
+
114
+ ///////////////////////////////////////////////////////////////////////////////
115
+
116
+ /** Random global functions
117
+ * @namespace Random */
118
+
119
+ /** Returns a random value between the two values passed in
120
+ * @param {Number} [valueA=1]
121
+ * @param {Number} [valueB=0]
122
+ * @return {Number}
123
+ * @memberof Random */
124
+ const rand = (a=1, b=0)=> b + (a-b)*Math.random();
125
+
126
+ /** Returns a floored random value the two values passed in
127
+ * @param {Number} [valueA=1]
128
+ * @param {Number} [valueB=0]
129
+ * @return {Number}
130
+ * @memberof Random */
131
+ const randInt = (a=1, b=0)=> rand(a,b)|0;
132
+
133
+ /** Randomly returns either -1 or 1
134
+ * @return {Number}
135
+ * @memberof Random */
136
+ const randSign = ()=> (rand(2)|0)*2-1;
137
+
138
+ /** Returns a random Vector2 within a circular shape
139
+ * @param {Number} [radius=1]
140
+ * @param {Number} [minRadius=0]
141
+ * @return {Vector2}
142
+ * @memberof Random */
143
+ const randInCircle = (radius=1, minRadius=0)=> radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2;
144
+
145
+ /** Returns a random Vector2 with the passed in length
146
+ * @param {Number} [length=1]
147
+ * @return {Vector2}
148
+ * @memberof Random */
149
+ const randVector = (length=1)=> new Vector2().setAngle(rand(2*PI), length);
150
+
151
+ /** Returns a random color between the two passed in colors, combine components if linear
152
+ * @param {Color} [colorA=new Color(1,1,1,1)]
153
+ * @param {Color} [colorB=new Color(0,0,0,1)]
154
+ * @param {Boolean} [linear]
155
+ * @return {Color}
156
+ * @memberof Random */
157
+ const randColor = (cA = new Color, cB = new Color(0,0,0,1), linear)=>
158
+ linear ? cA.lerp(cB, rand()) : new Color(rand(cA.r,cB.r),rand(cA.g,cB.g),rand(cA.b,cB.b),rand(cA.a,cB.a));
159
+
160
+ /** The seed used by the randSeeded function, should not be 0
161
+ * @memberof Random */
162
+ let randSeed = 1;
163
+
164
+ /** Returns a seeded random value between the two values passed in using randSeed
165
+ * @param {Number} [valueA=1]
166
+ * @param {Number} [valueB=0]
167
+ * @return {Number}
168
+ * @memberof Random */
169
+ const randSeeded = (a=1, b=0)=>
170
+ {
171
+ randSeed ^= randSeed << 13; randSeed ^= randSeed >>> 17; randSeed ^= randSeed << 5; // xorshift
172
+ return b + (a-b)*abs(randSeed % 1e9)/1e9;
173
+ }
174
+
175
+ ///////////////////////////////////////////////////////////////////////////////
176
+
177
+ /**
178
+ * Create a 2d vector, can take another Vector2 to copy, 2 scalars, or 1 scalar
179
+ * @param {Number} [x=0]
180
+ * @param {Number} [y=0]
181
+ * @return {Vector2}
182
+ * @example
183
+ * let a = vec2(0, 1); // vector with coordinates (0, 1)
184
+ * let b = vec2(a); // copy a into b
185
+ * a = vec2(5); // set a to (5, 5)
186
+ * b = vec2(); // set b to (0, 0)
187
+ * @memberof Utilities
188
+ */
189
+ const vec2 = (x=0, y)=> x.x == undefined ? new Vector2(x, y == undefined? x : y) : new Vector2(x.x, x.y);
190
+
191
+ /**
192
+ * 2D Vector object with vector math library
193
+ * @example
194
+ * let a = new Vector2(2, 3); // vector with coordinates (2, 3)
195
+ * let b = new Vector2; // vector with coordinates (0, 0)
196
+ * let c = vec2(4, 2); // use the vec2 function to make a Vector2
197
+ */
198
+ class Vector2
199
+ {
200
+ /** Create a 2D vector with the x and y passed in, can also be created with vec2()
201
+ * @param {Number} [x=0] - X axis location
202
+ * @param {Number} [y=0] - Y axis location */
203
+ constructor(x=0, y=0)
204
+ {
205
+ /** @property {Number} - X axis location */
206
+ this.x = x;
207
+ /** @property {Number} - Y axis location */
208
+ this.y = y;
209
+ }
210
+
211
+ /** Returns a new vector that is a copy of this
212
+ * @return {Vector2} */
213
+ copy() { return new Vector2(this.x, this.y); }
214
+
215
+ /** Returns a copy of this vector plus the vector passed in
216
+ * @param {Vector2} vector
217
+ * @return {Vector2} */
218
+ add(v) { ASSERT(v.x!=undefined); return new Vector2(this.x + v.x, this.y + v.y); }
219
+
220
+ /** Returns a copy of this vector minus the vector passed in
221
+ * @param {Vector2} vector
222
+ * @return {Vector2} */
223
+ subtract(v) { ASSERT(v.x!=undefined); return new Vector2(this.x - v.x, this.y - v.y); }
224
+
225
+ /** Returns a copy of this vector times the vector passed in
226
+ * @param {Vector2} vector
227
+ * @return {Vector2} */
228
+ multiply(v) { ASSERT(v.x!=undefined); return new Vector2(this.x * v.x, this.y * v.y); }
229
+
230
+ /** Returns a copy of this vector divided by the vector passed in
231
+ * @param {Vector2} vector
232
+ * @return {Vector2} */
233
+ divide(v) { ASSERT(v.x!=undefined); return new Vector2(this.x / v.x, this.y / v.y); }
234
+
235
+ /** Returns a copy of this vector scaled by the vector passed in
236
+ * @param {Number} scale
237
+ * @return {Vector2} */
238
+ scale(s) { ASSERT(s.x==undefined); return new Vector2(this.x * s, this.y * s); }
239
+
240
+ /** Returns the length of this vector
241
+ * @return {Number} */
242
+ length() { return this.lengthSquared()**.5; }
243
+
244
+ /** Returns the length of this vector squared
245
+ * @return {Number} */
246
+ lengthSquared() { return this.x**2 + this.y**2; }
247
+
248
+ /** Returns the distance from this vector to vector passed in
249
+ * @param {Vector2} vector
250
+ * @return {Number} */
251
+ distance(v) { return this.distanceSquared(v)**.5; }
252
+
253
+ /** Returns the distance squared from this vector to vector passed in
254
+ * @param {Vector2} vector
255
+ * @return {Number} */
256
+ distanceSquared(v) { return (this.x - v.x)**2 + (this.y - v.y)**2; }
257
+
258
+ /** Returns a new vector in same direction as this one with the length passed in
259
+ * @param {Number} [length=1]
260
+ * @return {Vector2} */
261
+ normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(length); }
262
+
263
+ /** Returns a new vector clamped to length passed in
264
+ * @param {Number} [length=1]
265
+ * @return {Vector2} */
266
+ clampLength(length=1) { const l = this.length(); return l > length ? this.scale(length/l) : this; }
267
+
268
+ /** Returns the dot product of this and the vector passed in
269
+ * @param {Vector2} vector
270
+ * @return {Number} */
271
+ dot(v) { ASSERT(v.x!=undefined); return this.x*v.x + this.y*v.y; }
272
+
273
+ /** Returns the cross product of this and the vector passed in
274
+ * @param {Vector2} vector
275
+ * @return {Number} */
276
+ cross(v) { ASSERT(v.x!=undefined); return this.x*v.y - this.y*v.x; }
277
+
278
+ /** Returns the angle of this vector, up is angle 0
279
+ * @return {Number} */
280
+ angle() { return Math.atan2(this.x, this.y); }
281
+
282
+ /** Sets this vector with angle and length passed in
283
+ * @param {Number} [angle=0]
284
+ * @param {Number} [length=1] */
285
+ setAngle(a=0, length=1) { this.x = length*Math.sin(a); this.y = length*Math.cos(a); return this; }
286
+
287
+ /** Returns copy of this vector rotated by the angle passed in
288
+ * @param {Number} angle
289
+ * @return {Vector2} */
290
+ rotate(a) { const c = Math.cos(a), s = Math.sin(a); return new Vector2(this.x*c-this.y*s, this.x*s+this.y*c); }
291
+
292
+ /** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
293
+ * @return {Number} */
294
+ direction() { return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
295
+
296
+ /** Returns a copy of this vector that has been inverted
297
+ * @return {Vector2} */
298
+ invert() { return new Vector2(this.y, -this.x); }
299
+
300
+ /** Returns a copy of this vector with the axies flipped
301
+ * @return {Vector2} */
302
+ flip() { return new Vector2(this.y, this.x); }
303
+
304
+ /** Returns a copy of this vector with each axis floored
305
+ * @return {Vector2} */
306
+ floor() { return new Vector2(Math.floor(this.x), Math.floor(this.y)); }
307
+
308
+ /** Returns the area this vector covers as a rectangle
309
+ * @return {Number} */
310
+ area() { return this.x * this.y; }
311
+
312
+ /** Returns a new vector that is p percent between this and the vector passed in
313
+ * @param {Vector2} vector
314
+ * @param {Number} percent
315
+ * @return {Vector2} */
316
+ lerp(v, p) { ASSERT(v.x!=undefined); return this.add(v.subtract(this).scale(clamp(p))); }
317
+
318
+ /** Returns true if this vector is within the bounds of an array size passed in
319
+ * @param {Vector2} arraySize
320
+ * @return {Boolean} */
321
+ arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
322
+ }
323
+
324
+ ///////////////////////////////////////////////////////////////////////////////
325
+
326
+ /**
327
+ * Color object (red, green, blue, alpha) with some helpful functions
328
+ * @example
329
+ * let a = new Color; // white
330
+ * let b = new Color(1, 0, 0); // red
331
+ * let c = new Color(0, 0, 0, 0); // transparent black
332
+ */
333
+ class Color
334
+ {
335
+ /** Create a color with the components passed in, white by default
336
+ * @param {Number} [red=1]
337
+ * @param {Number} [green=1]
338
+ * @param {Number} [blue=1]
339
+ * @param {Number} [alpha=1] */
340
+ constructor(r=1, g=1, b=1, a=1)
341
+ {
342
+ /** @property {Number} - Red */
343
+ this.r = r;
344
+ /** @property {Number} - Green */
345
+ this.g = g;
346
+ /** @property {Number} - Blue */
347
+ this.b = b;
348
+ /** @property {Number} - Alpha */
349
+ this.a = a;
350
+ }
351
+
352
+ /** Returns a new color that is a copy of this
353
+ * @return {Color} */
354
+ copy() { return new Color(this.r, this.g, this.b, this.a); }
355
+
356
+ /** Returns a copy of this color plus the color passed in
357
+ * @param {Color} color
358
+ * @return {Color} */
359
+ add(c) { return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a); }
360
+
361
+ /** Returns a copy of this color minus the color passed in
362
+ * @param {Color} color
363
+ * @return {Color} */
364
+ subtract(c) { return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a); }
365
+
366
+ /** Returns a copy of this color times the color passed in
367
+ * @param {Color} color
368
+ * @return {Color} */
369
+ multiply(c) { return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a); }
370
+
371
+ /** Returns a copy of this color divided by the color passed in
372
+ * @param {Color} color
373
+ * @return {Color} */
374
+ divide(c) { return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a); }
375
+
376
+ /** Returns a copy of this color scaled by the value passed in, alpha can be scaled separately
377
+ * @param {Number} scale
378
+ * @param {Number} [alphaScale=scale]
379
+ * @return {Color} */
380
+ scale(s, a=s) { return new Color(this.r*s, this.g*s, this.b*s, this.a*a); }
381
+
382
+ /** Returns a copy of this color clamped to the valid range between 0 and 1
383
+ * @return {Color} */
384
+ clamp() { return new Color(clamp(this.r), clamp(this.g), clamp(this.b), clamp(this.a)); }
385
+
386
+ /** Returns a new color that is p percent between this and the color passed in
387
+ * @param {Color} color
388
+ * @param {Number} percent
389
+ * @return {Color} */
390
+ lerp(c, p) { return this.add(c.subtract(this).scale(clamp(p))); }
391
+
392
+ /** Sets this color given a hue, saturation, lightness , and alpha
393
+ * @param {Number} [hue=0]
394
+ * @param {Number} [saturation=0]
395
+ * @param {Number} [lightness=1]
396
+ * @param {Number} [alpha=1]
397
+ * @return {Color} */
398
+ setHSLA(h=0, s=0, l=1, a=1)
399
+ {
400
+ const q = l < .5 ? l*(1+s) : l+s-l*s, p = 2*l-q,
401
+ f = (p, q, t)=>
402
+ (t = ((t%1)+1)%1) < 1/6 ? p+(q-p)*6*t :
403
+ t < 1/2 ? q :
404
+ t < 2/3 ? p+(q-p)*(2/3-t)*6 : p;
405
+
406
+ this.r = f(p, q, h + 1/3);
407
+ this.g = f(p, q, h);
408
+ this.b = f(p, q, h - 1/3);
409
+ this.a = a;
410
+ return this;
411
+ }
412
+
413
+ /** Returns a new color that has each component randomly adjusted
414
+ * @param {Number} [amount=.05]
415
+ * @param {Number} [alphaAmount=0]
416
+ * @return {Color} */
417
+ mutate(amount=.05, alphaAmount=0)
418
+ {
419
+ return new Color
420
+ (
421
+ this.r + rand(amount, -amount),
422
+ this.g + rand(amount, -amount),
423
+ this.b + rand(amount, -amount),
424
+ this.a + rand(alphaAmount, -alphaAmount)
425
+ ).clamp();
426
+ }
427
+
428
+ /** Returns this color expressed as an rgba string
429
+ * @return {String} */
430
+ rgba()
431
+ {
432
+ ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
433
+ return `rgb(${this.r*255|0},${this.g*255|0},${this.b*255|0},${this.a})`;
434
+ }
435
+
436
+ /** Returns this color expressed as 32 bit integer value
437
+ * @return {Number} */
438
+ rgbaInt()
439
+ {
440
+ ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
441
+ return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
442
+ }
443
+ }
444
+
445
+ ///////////////////////////////////////////////////////////////////////////////
446
+
447
+ /**
448
+ * Timer object tracks how long has passed since it was set
449
+ * @example
450
+ * let a = new Timer; // creates a timer that is not set
451
+ * a.set(3); // sets the timer to 3 seconds
452
+ *
453
+ * let b = new Timer(1); // creates a timer with 1 second left
454
+ * b.unset(); // unsets the timer
455
+ */
456
+ class Timer
457
+ {
458
+ /** Create a timer object set time passed in
459
+ * @param {Number} [timeLeft] - How much time left before the timer elapses in seconds */
460
+ constructor(timeLeft) { this.time = timeLeft == undefined ? undefined : time + timeLeft; this.setTime = timeLeft; }
461
+
462
+ /** Set the timer with seconds passed in
463
+ * @param {Number} [timeLeft=0] - How much time left before the timer is elapsed in seconds */
464
+ set(timeLeft=0) { this.time = time + timeLeft; this.setTime = timeLeft; }
465
+
466
+ /** Unset the timer */
467
+ unset() { this.time = undefined; }
468
+
469
+ /** Returns true if set
470
+ * @return {Boolean} */
471
+ isSet() { return this.time != undefined; }
472
+
473
+ /** Returns true if set and has not elapsed
474
+ * @return {Boolean} */
475
+ active() { return time <= this.time; }
476
+
477
+ /** Returns true if set and elapsed
478
+ * @return {Boolean} */
479
+ elapsed() { return time > this.time; }
480
+
481
+ /** Get how long since elapsed, returns 0 if not set
482
+ * @return {Number} */
483
+ get() { return this.isSet()? time - this.time : 0; }
484
+
485
+ /** Get percentage elapsed based on time it was set to, returns 0 if not set
486
+ * @return {Number} */
487
+ getPercent() { return this.isSet()? percent(this.time - time, 0, this.setTime) : 0; }
488
+ }