littlejsengine 1.13.1 → 1.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +15 -11
  2. package/copyToGithub.bat +28 -0
  3. package/dist/littlejs.d.ts +430 -304
  4. package/dist/littlejs.esm.js +1745 -982
  5. package/dist/littlejs.esm.min.js +1 -1
  6. package/dist/littlejs.js +1716 -965
  7. package/dist/littlejs.min.js +1 -1
  8. package/dist/littlejs.release.js +1673 -922
  9. package/examples/box2d/game.js +2 -2
  10. package/examples/box2d/gameObjects.js +2 -2
  11. package/examples/box2d/scenes.js +1 -1
  12. package/examples/breakout/game.js +30 -25
  13. package/examples/breakoutTutorial/README.md +44 -41
  14. package/examples/breakoutTutorial/game.js +2 -2
  15. package/examples/electron/build.bat +7 -0
  16. package/examples/electron/build.js +124 -0
  17. package/examples/electron/electron.js +35 -0
  18. package/examples/electron/game.js +140 -0
  19. package/examples/electron/index.html +13 -0
  20. package/examples/electron/package.json +12 -0
  21. package/examples/electron/tiles.png +0 -0
  22. package/examples/empty/game.js +1 -0
  23. package/examples/htmlMenu/game.js +1 -1
  24. package/examples/index.html +332 -160
  25. package/examples/module/game.js +5 -2
  26. package/examples/particles/index.html +12 -3
  27. package/examples/platformer/gameEffects.js +20 -19
  28. package/examples/platformer/gameLevel.js +6 -1
  29. package/examples/shorts/base.html +1 -1
  30. package/examples/shorts/blending.js +9 -5
  31. package/examples/shorts/box2d.js +1 -1
  32. package/examples/shorts/box2dCar.js +1 -1
  33. package/examples/shorts/clock.js +1 -1
  34. package/examples/shorts/colors.js +2 -2
  35. package/examples/shorts/flappyGame.js +2 -1
  36. package/examples/shorts/helloWorld.js +1 -1
  37. package/examples/shorts/maze.js +1 -1
  38. package/examples/shorts/music.js +106 -0
  39. package/examples/shorts/nineSlice.js +9 -9
  40. package/examples/shorts/parallax.js +71 -0
  41. package/examples/shorts/piano.js +9 -10
  42. package/examples/shorts/postProcess.js +25 -8
  43. package/examples/shorts/raycasting.js +2 -2
  44. package/examples/shorts/shapes.js +7 -15
  45. package/examples/shorts/slidingPuzzle.js +2 -2
  46. package/examples/shorts/song.mp3 +0 -0
  47. package/examples/shorts/starfield.js +5 -7
  48. package/examples/shorts/systemFont.js +1 -1
  49. package/examples/shorts/uiSystem.js +16 -8
  50. package/examples/starter/build.js +9 -8
  51. package/examples/starter/game.js +5 -2
  52. package/examples/starter/index.html +2 -2
  53. package/examples/stress/index.html +13 -8
  54. package/examples/style.css +19 -6
  55. package/examples/typescript/build.js +1 -1
  56. package/examples/typescript/game.js +2 -2
  57. package/examples/typescript/game.ts +5 -2
  58. package/examples/uiSystem/game.js +13 -12
  59. package/package.json +2 -2
  60. package/plugins/box2d.js +24 -97
  61. package/plugins/drawUtilities.js +29 -23
  62. package/plugins/newgrounds.js +6 -6
  63. package/plugins/pluginExport.js +1 -1
  64. package/plugins/postProcess.js +7 -0
  65. package/plugins/uiSystem.js +106 -82
  66. package/plugins/zzfxm.js +10 -10
  67. package/reference.md +90 -54
  68. package/src/engine.js +28 -23
  69. package/src/engineAudio.js +285 -110
  70. package/src/engineBuild.js +9 -9
  71. package/src/engineDebug.js +28 -28
  72. package/src/engineDraw.js +346 -202
  73. package/src/engineExport.js +28 -16
  74. package/src/engineInput.js +58 -68
  75. package/src/engineMedals.js +29 -29
  76. package/src/engineObject.js +28 -25
  77. package/src/engineParticles.js +67 -60
  78. package/src/engineRelease.js +1 -1
  79. package/src/engineSettings.js +70 -16
  80. package/src/engineTileLayer.js +34 -34
  81. package/src/engineUtilities.js +69 -62
  82. package/src/engineWebGL.js +467 -65
  83. /package/examples/shorts/{playSound.js → sound.js} +0 -0
@@ -1,4 +1,4 @@
1
- /**
1
+ /**
2
2
  * LittleJS Tile Layer System
3
3
  * - Caches arrays of tiles to off screen canvas for fast rendering
4
4
  * - Unlimited numbers of layers, allocates canvases as needed
@@ -14,9 +14,9 @@
14
14
  // Tile Layer System
15
15
 
16
16
  /** Keep track of all tile layers with collision
17
- * @type {Array<TileCollisionLayer>}
17
+ * @type {Array<TileCollisionLayer>}
18
18
  * @memberof TileCollision */
19
- let tileCollisionLayers = [];
19
+ const tileCollisionLayers = [];
20
20
 
21
21
  /** Get tile collision data for a given cell in the grid
22
22
  * @param {Vector2} pos
@@ -70,7 +70,7 @@ function tileCollisionRaycast(posStart, posEnd, object, solidOnly=true)
70
70
  }
71
71
 
72
72
  ///////////////////////////////////////////////////////////////////////////////
73
- /**
73
+ /**
74
74
  * Load tile layers from exported data
75
75
  * @param {Object} tileMapData - Level data from exported data
76
76
  * @param {TileInfo} [tileInfo] - Default tile info (used for size and texture)
@@ -103,13 +103,13 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
103
103
  {
104
104
  const dataLayer = tileMapData.layers[layerIndex];
105
105
  ASSERT(dataLayer.data && dataLayer.data.length);
106
- ASSERT(levelSize.area() == dataLayer.data.length);
106
+ ASSERT(levelSize.area() === dataLayer.data.length);
107
107
 
108
108
  const layerRenderOrder = renderOrder - (layerCount - 1 - layerIndex);
109
109
  const tileLayer = new TileCollisionLayer(vec2(), levelSize, tileInfo, layerRenderOrder);
110
110
  tileLayers[layerIndex] = tileLayer;
111
111
 
112
- for (let x=levelSize.x; x--;)
112
+ for (let x=levelSize.x; x--;)
113
113
  for (let y=levelSize.y; y--;)
114
114
  {
115
115
  const pos = vec2(x, levelSize.y-1-y);
@@ -168,7 +168,7 @@ class TileLayerData
168
168
  /**
169
169
  * Canvas Layer - cached off screen rendering system
170
170
  * - Contains an offscreen canvas that can be rendered to
171
- * - Webgl rendering is optional, call useWebGL to enable
171
+ * - WebGL rendering is optional, call useWebGL to enable
172
172
  * @extends EngineObject
173
173
  * @example
174
174
  * const canvasLayer = new CanvasLayer(vec2(), vec2(200,100));
@@ -190,18 +190,18 @@ class CanvasLayer extends EngineObject
190
190
  this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
191
191
  /** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
192
192
  this.context = headlessMode ? undefined : this.canvas.getContext('2d');
193
- /** @property {WebGLTexture} - Texture if using webgl for this layer, call useWebGL to enable */
193
+ /** @property {WebGLTexture} - Texture if using WebGL for this layer, call useWebGL to enable */
194
194
  this.glTexture = undefined;
195
195
  this.gravityScale = 0; // disable gravity by default for canvas layers
196
196
  }
197
-
197
+
198
198
  /** Destroy this canvas layer */
199
199
  destroy()
200
200
  {
201
201
  if (this.destroyed)
202
202
  return;
203
203
 
204
- // free up the webgl texture
204
+ // free up the WebGL texture
205
205
  if (this.glTexture)
206
206
  glDeleteTexture(this.glTexture);
207
207
  super.destroy();
@@ -226,12 +226,12 @@ class CanvasLayer extends EngineObject
226
226
  draw(pos, size, angle=0, color=WHITE, mirror=false, additiveColor, screenSpace=false, context)
227
227
  {
228
228
  // draw the canvas layer as a single tile that uses the whole texture
229
- const useWebgl = glEnable && this.glTexture != undefined;
229
+ const useWebGL = glEnable && this.glTexture !== undefined;
230
230
  const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
231
- drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebgl, screenSpace, context);
231
+ drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
232
232
  }
233
233
 
234
- /** Draw onto the layer canvas in world space (bypass webgl)
234
+ /** Draw onto the layer canvas in world space (bypass WebGL)
235
235
  * @param {Vector2} pos
236
236
  * @param {Vector2} size
237
237
  * @param {number} angle
@@ -265,8 +265,8 @@ class CanvasLayer extends EngineObject
265
265
  if (textureInfo)
266
266
  {
267
267
  context.globalAlpha = color.a; // only alpha is supported
268
- context.drawImage(textureInfo.image,
269
- tileInfo.pos.x, tileInfo.pos.y,
268
+ context.drawImage(textureInfo.image,
269
+ tileInfo.pos.x, tileInfo.pos.y,
270
270
  tileInfo.size.x, tileInfo.size.y, -.5, -.5, 1, 1);
271
271
  context.globalAlpha = 1;
272
272
  }
@@ -284,11 +284,11 @@ class CanvasLayer extends EngineObject
284
284
  * @param {Vector2} [size=(1,1)]
285
285
  * @param {Color} [color=(1,1,1,1)]
286
286
  * @param {number} [angle=0] */
287
- drawRect(pos, size, color, angle)
287
+ drawRect(pos, size, color, angle)
288
288
  { this.drawTile(pos, size, undefined, color, angle); }
289
289
 
290
- /** Create or update the webgl texture for this layer
291
- * @param {boolean} [enable] - enable webgl rendering and update the texture */
290
+ /** Create or update the WebGL texture for this layer
291
+ * @param {boolean} [enable] - enable WebGL rendering and update the texture */
292
292
  useWebGL(enable=true)
293
293
  {
294
294
  if (glEnable && enable)
@@ -334,7 +334,7 @@ class TileLayer extends CanvasLayer
334
334
  this.canvas = new OffscreenCanvas(canvasSize.x, canvasSize.y);
335
335
  /** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this tile layer */
336
336
  this.context = this.canvas.getContext('2d');
337
- /** @property {WebGLTexture} - Texture if using webgl for this layer */
337
+ /** @property {WebGLTexture} - Texture if using WebGL for this layer */
338
338
  this.glTexture = useWebGL ? glCreateTexture(this.canvas) : undefined;
339
339
  // set no friction by default, applied friction is max of both objects
340
340
  this.friction = 0;
@@ -359,7 +359,7 @@ class TileLayer extends CanvasLayer
359
359
  }
360
360
  }
361
361
 
362
- /** Set data at a given position in the array
362
+ /** Set data at a given position in the array
363
363
  * @param {Vector2} layerPos - Local position in array
364
364
  * @param {TileLayerData} data - Data to set
365
365
  * @param {boolean} [redraw] - Force the tile to redraw if true */
@@ -371,26 +371,26 @@ class TileLayer extends CanvasLayer
371
371
  redraw && this.drawTileData(layerPos);
372
372
  }
373
373
  }
374
-
375
- /** Get data at a given position in the array
374
+
375
+ /** Get data at a given position in the array
376
376
  * @param {Vector2} layerPos - Local position in array
377
377
  * @return {TileLayerData} */
378
378
  getData(layerPos)
379
379
  { return layerPos.arrayCheck(this.size) && this.data[(layerPos.y|0)*this.size.x+layerPos.x|0]; }
380
-
380
+
381
381
  // Render the tile layer, called automatically by the engine
382
382
  render()
383
383
  {
384
- ASSERT(drawContext != this.context, 'must call redrawEnd() after drawing tiles!');
385
-
384
+ ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
385
+
386
386
  // draw the tile layer as a single tile
387
387
  const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
388
388
  const pos = this.pos.add(this.size.scale(.5));
389
- const useWebgl = glEnable && this.glTexture != undefined;
390
- drawTile(pos, this.size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebgl);
389
+ const useWebGL = glEnable && this.glTexture !== undefined;
390
+ drawTile(pos, this.size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
391
391
  }
392
392
 
393
- /** Draw all the tile data to an offscreen canvas
393
+ /** Draw all the tile data to an offscreen canvas
394
394
  * - This may be slow in some browsers but only needs to be done once */
395
395
  redraw()
396
396
  {
@@ -400,7 +400,7 @@ class TileLayer extends CanvasLayer
400
400
  this.drawTileData(vec2(x,y), false);
401
401
  this.redrawEnd();
402
402
  if (this.glTexture)
403
- this.useWebGL(); // update webgl texture
403
+ this.useWebGL(); // update WebGL texture
404
404
  }
405
405
 
406
406
  /** Call to start the redraw process
@@ -436,7 +436,7 @@ class TileLayer extends CanvasLayer
436
436
  /** Call to end the redraw process */
437
437
  redrawEnd()
438
438
  {
439
- ASSERT(drawContext == this.context, 'must call redrawStart() before drawing tiles');
439
+ ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
440
440
  glCopyToContext(drawContext);
441
441
  //debugSaveCanvas(this.canvas);
442
442
 
@@ -447,7 +447,7 @@ class TileLayer extends CanvasLayer
447
447
  /** Draw the tile at a given position in the tile grid
448
448
  * This can be used to clear out tiles when they are destroyed
449
449
  * Tiles can also be redrawn if inside a redrawStart/End block
450
- * @param {Vector2} layerPos
450
+ * @param {Vector2} layerPos
451
451
  * @param {boolean} [clear] - should the old tile be cleared out
452
452
  */
453
453
  drawTileData(layerPos, clear=true)
@@ -462,9 +462,9 @@ class TileLayer extends CanvasLayer
462
462
 
463
463
  // draw the tile if it has layer data
464
464
  const d = this.getData(layerPos);
465
- if (d.tile != undefined)
465
+ if (d.tile !== undefined)
466
466
  {
467
- ASSERT(drawContext == this.context, 'must call redrawStart() before drawing tiles');
467
+ ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
468
468
  const pos = layerPos.add(vec2(.5));
469
469
  const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex, this.tileInfo.padding);
470
470
  drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
@@ -477,7 +477,7 @@ class TileLayer extends CanvasLayer
477
477
  * Tile Collision Layer - a tile layer with collision
478
478
  * - adds collision data and functions to TileLayer
479
479
  * - there can be multiple tile collision layers
480
- * - tile collison layers should not overlap each other
480
+ * - tile collision layers should not overlap each other
481
481
  * @extends TileLayer
482
482
  */
483
483
  class TileCollisionLayer extends TileLayer
@@ -75,7 +75,19 @@ function lerp(valueA, valueB, percent)
75
75
  if (valueA >= 0 && valueA <= 1 && ((valueB < 0 || valueB > 1) && (percent < 0 || percent > 1)))
76
76
  console.warn('lerp() parameter order changed! use lerp(start, end, p)');
77
77
  return valueA + clamp(percent) * (valueB-valueA);
78
- }
78
+ }
79
+
80
+ /** Gets percent between percentA and percentB and linearly interpolates between lerpA and lerpB
81
+ * A shortcut for lerp(lerpA, lerpB, percent(value, percentA, percentB))
82
+ * @param {number} value
83
+ * @param {number} percentA
84
+ * @param {number} percentB
85
+ * @param {number} lerpA
86
+ * @param {number} lerpB
87
+ * @return {number}
88
+ * @memberof Utilities */
89
+ function percentLerp(value, percentA, percentB, lerpA, lerpB)
90
+ { return lerp(lerpA, lerpB, percent(value, percentA, percentB)); }
79
91
 
80
92
  /** Returns signed wrapped distance between the two values passed in
81
93
  * @param {number} valueA
@@ -127,22 +139,23 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
127
139
  * @memberof Utilities */
128
140
  function isPowerOfTwo(value) { return !(value & (value - 1)); }
129
141
 
130
- /** Returns the nearest power of two not less then the value
142
+ /** Returns the nearest power of two not less than the value
131
143
  * @param {number} value
132
144
  * @return {number}
133
145
  * @memberof Utilities */
134
146
  function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
135
147
 
136
- /** Returns true if two axis aligned bounding boxes are overlapping
148
+ /** Returns true if two axis aligned bounding boxes are overlapping
149
+ * this can be used for simple collision detection between objects
137
150
  * @param {Vector2} posA - Center of box A
138
151
  * @param {Vector2} sizeA - Size of box A
139
152
  * @param {Vector2} posB - Center of box B
140
- * @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
153
+ * @param {Vector2} [sizeB=(0,0)] - Size of box B, uses a point if undefined
141
154
  * @return {boolean} - True if overlapping
142
155
  * @memberof Utilities */
143
156
  function isOverlapping(posA, sizeA, posB, sizeB=vec2())
144
- {
145
- return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
157
+ {
158
+ return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
146
159
  && abs(posA.y - posB.y)*2 < sizeA.y + sizeB.y;
147
160
  }
148
161
 
@@ -191,12 +204,13 @@ function isIntersecting(start, end, pos, size)
191
204
  * @param {number} [frequency] - Frequency of the wave in Hz
192
205
  * @param {number} [amplitude] - Amplitude (max height) of the wave
193
206
  * @param {number} [t=time] - Value to use for time of the wave
207
+ * @param {number} [offset] - Value to use for time offset of the wave
194
208
  * @return {number} - Value waving between 0 and amplitude
195
209
  * @memberof Utilities */
196
- function wave(frequency=1, amplitude=1, t=time)
197
- { return amplitude/2 * (1 - Math.cos(t*frequency*2*PI)); }
210
+ function wave(frequency=1, amplitude=1, t=time, offset=0)
211
+ { return amplitude/2 * (1 - Math.cos(offset + t*frequency*2*PI)); }
198
212
 
199
- /** Formats seconds to mm:ss style for display purposes
213
+ /** Formats seconds to mm:ss style for display purposes
200
214
  * @param {number} t - time in seconds
201
215
  * @return {string}
202
216
  * @memberof Utilities */
@@ -212,13 +226,12 @@ async function fetchJSON(url)
212
226
  return response.json();
213
227
  }
214
228
 
215
- /**
229
+ /**
216
230
  * Check if object is a valid number, not NaN or undefined, but it may be infinite
217
231
  * @param {any} n
218
232
  * @return {boolean}
219
- * @memberof Utilities
220
- */
221
- function isNumber(n) { return typeof n == 'number' && !isNaN(n); }
233
+ * @memberof Utilities */
234
+ function isNumber(n) { return typeof n === 'number' && !isNaN(n); }
222
235
 
223
236
  ///////////////////////////////////////////////////////////////////////////////
224
237
 
@@ -273,13 +286,13 @@ function randInCircle(radius=1, minRadius=0)
273
286
  * @memberof Random */
274
287
  function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear=false)
275
288
  {
276
- return linear ? colorA.lerp(colorB, rand()) :
289
+ return linear ? colorA.lerp(colorB, rand()) :
277
290
  new Color(rand(colorA.r,colorB.r), rand(colorA.g,colorB.g), rand(colorA.b,colorB.b), rand(colorA.a,colorB.a));
278
291
  }
279
292
 
280
293
  ///////////////////////////////////////////////////////////////////////////////
281
294
 
282
- /**
295
+ /**
283
296
  * Seeded random number generator
284
297
  * - Can be used to create a deterministic random number sequence
285
298
  * @example
@@ -306,8 +319,8 @@ class RandomGenerator
306
319
  float(valueA=1, valueB=0)
307
320
  {
308
321
  // xorshift algorithm
309
- this.seed ^= this.seed << 13;
310
- this.seed ^= this.seed >>> 17;
322
+ this.seed ^= this.seed << 13;
323
+ this.seed ^= this.seed >>> 17;
311
324
  this.seed ^= this.seed << 5;
312
325
  return valueB + (valueA - valueB) * ((this.seed >>> 0) / 2**32);
313
326
  }
@@ -356,16 +369,14 @@ class RandomGenerator
356
369
  * let a = vec2(0, 1); // vector with coordinates (0, 1)
357
370
  * a = vec2(5); // set a to (5, 5)
358
371
  * b = vec2(); // set b to (0, 0)
359
- * @memberof Utilities
360
- */
372
+ * @memberof Utilities */
361
373
  function vec2(x=0, y) { return new Vector2(x, y === undefined ? x : y); }
362
374
 
363
- /**
375
+ /**
364
376
  * Check if object is a valid Vector2
365
377
  * @param {any} v
366
378
  * @return {boolean}
367
- * @memberof Utilities
368
- */
379
+ * @memberof Utilities */
369
380
  function isVector2(v) { return v instanceof Vector2; }
370
381
 
371
382
  // vector2 asserts
@@ -374,10 +385,10 @@ function ASSERT_NUMBER_VALID(n) { ASSERT(isNumber(n), 'Number is invalid.', n);
374
385
  function ASSERT_VECTOR2_NORMAL(v)
375
386
  {
376
387
  ASSERT_VECTOR2_VALID(v);
377
- ASSERT(abs(v.lengthSquared()-1) < .01, 'Vector2 is not normal.', v);
388
+ ASSERT(abs(v.lengthSquared()-1) < .01, 'Vector2 is not normal.', v);
378
389
  }
379
390
 
380
- /**
391
+ /**
381
392
  * 2D Vector object with vector math library
382
393
  * - Functions do not change this so they can be chained together
383
394
  * @example
@@ -501,7 +512,7 @@ class Vector2
501
512
  * @param {number} [angle]
502
513
  * @param {number} [length]
503
514
  * @return {Vector2} */
504
- setAngle(angle=0, length=1)
515
+ setAngle(angle=0, length=1)
505
516
  {
506
517
  ASSERT_NUMBER_VALID(angle);
507
518
  ASSERT_NUMBER_VALID(length);
@@ -516,7 +527,7 @@ class Vector2
516
527
  rotate(angle)
517
528
  {
518
529
  ASSERT_NUMBER_VALID(angle);
519
- const c = Math.cos(-angle), s = Math.sin(-angle);
530
+ const c = Math.cos(-angle), s = Math.sin(-angle);
520
531
  return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
521
532
  }
522
533
 
@@ -528,9 +539,9 @@ class Vector2
528
539
  ASSERT_NUMBER_VALID(direction);
529
540
  ASSERT_NUMBER_VALID(length);
530
541
  direction = mod(direction, 4);
531
- ASSERT(direction==0 || direction==1 || direction==2 || direction==3,
542
+ ASSERT(direction===0 || direction===1 || direction===2 || direction===3,
532
543
  'Vector2.setDirection() direction must be an integer between 0 and 3.');
533
- return vec2(direction%2 ? direction-1 ? -length : length : 0,
544
+ return vec2(direction%2 ? direction-1 ? -length : length : 0,
534
545
  direction%2 ? 0 : direction ? -length : length);
535
546
  }
536
547
 
@@ -582,7 +593,7 @@ class Vector2
582
593
  /** Returns this vector expressed as a string
583
594
  * @param {number} digits - precision to display
584
595
  * @return {string} */
585
- toString(digits=3)
596
+ toString(digits=3)
586
597
  {
587
598
  ASSERT_NUMBER_VALID(digits);
588
599
  if (debug)
@@ -601,7 +612,7 @@ class Vector2
601
612
 
602
613
  ///////////////////////////////////////////////////////////////////////////////
603
614
 
604
- /**
615
+ /**
605
616
  * Create a color object with RGBA values, white by default
606
617
  * @param {number} [r=1] - red
607
618
  * @param {number} [g=1] - green
@@ -612,29 +623,27 @@ class Vector2
612
623
  */
613
624
  function rgb(r, g, b, a) { return new Color(r, g, b, a); }
614
625
 
615
- /**
626
+ /**
616
627
  * Create a color object with HSLA values, white by default
617
628
  * @param {number} [h=0] - hue
618
629
  * @param {number} [s=0] - saturation
619
630
  * @param {number} [l=1] - lightness
620
631
  * @param {number} [a=1] - alpha
621
632
  * @return {Color}
622
- * @memberof Utilities
623
- */
633
+ * @memberof Utilities */
624
634
  function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
625
635
 
626
- /**
636
+ /**
627
637
  * Check if object is a valid Color
628
638
  * @param {any} c
629
639
  * @return {boolean}
630
- * @memberof Utilities
631
- */
640
+ * @memberof Utilities */
632
641
  function isColor(c) { return c instanceof Color; }
633
642
 
634
643
  // color asserts
635
644
  function ASSERT_COLOR_VALID(c) { ASSERT(isColor(c) && c.isValid(), 'Color is invalid.', c); }
636
645
 
637
- /**
646
+ /**
638
647
  * Color object (red, green, blue, alpha) with some helpful functions
639
648
  * @example
640
649
  * let a = new Color; // white
@@ -706,7 +715,7 @@ class Color
706
715
  * @param {number} scale
707
716
  * @param {number} [alphaScale=scale]
708
717
  * @return {Color} */
709
- scale(scale, alphaScale=scale)
718
+ scale(scale, alphaScale=scale)
710
719
  { return new Color(this.r*scale, this.g*scale, this.b*scale, this.a*alphaScale); }
711
720
 
712
721
  /** Returns a copy of this color clamped to the valid range between 0 and 1
@@ -723,9 +732,9 @@ class Color
723
732
  ASSERT_NUMBER_VALID(percent);
724
733
  const p = clamp(percent);
725
734
  return new Color(
726
- c.r*p + this.r*(1-p),
727
- c.g*p + this.g*(1-p),
728
- c.b*p + this.b*(1-p),
735
+ c.r*p + this.r*(1-p),
736
+ c.g*p + this.g*(1-p),
737
+ c.b*p + this.b*(1-p),
729
738
  c.a*p + this.a*(1-p));
730
739
  }
731
740
 
@@ -765,15 +774,15 @@ class Color
765
774
  const minC = min(r, g, b);
766
775
  const l = (maxC + minC) / 2;
767
776
  let h = 0, s = 0;
768
- if (maxC != minC)
777
+ if (maxC !== minC)
769
778
  {
770
779
  let d = maxC - minC;
771
780
  s = l > .5 ? d / (2 - maxC - minC) : d / (maxC + minC);
772
- if (r == maxC)
781
+ if (r === maxC)
773
782
  h = (g - b) / d + (g < b ? 6 : 0);
774
- else if (g == maxC)
783
+ else if (g === maxC)
775
784
  h = (b - r) / d + 2;
776
- else if (b == maxC)
785
+ else if (b === maxC)
777
786
  h = (r - g) / d + 4;
778
787
  }
779
788
  return [h / 6, s, l, a];
@@ -783,7 +792,7 @@ class Color
783
792
  * @param {number} [amount]
784
793
  * @param {number} [alphaAmount]
785
794
  * @return {Color} */
786
- mutate(amount=.05, alphaAmount=0)
795
+ mutate(amount=.05, alphaAmount=0)
787
796
  {
788
797
  ASSERT_NUMBER_VALID(amount);
789
798
  ASSERT_NUMBER_VALID(alphaAmount);
@@ -799,47 +808,47 @@ class Color
799
808
  /** Returns this color expressed as a hex color code
800
809
  * @param {boolean} [useAlpha] - if alpha should be included in result
801
810
  * @return {string} */
802
- toString(useAlpha = true)
811
+ toString(useAlpha = true)
803
812
  {
804
- ASSERT(typeof useAlpha == 'boolean', 'Use alpha boolean is invalid.', useAlpha);
813
+ ASSERT(typeof useAlpha === 'boolean', 'Use alpha boolean is invalid.', useAlpha);
805
814
  if (debug && !this.isValid())
806
815
  return `#000`;
807
816
  const toHex = (c)=> ((c=clamp(c)*255|0)<16 ? '0' : '') + c.toString(16);
808
817
  return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
809
818
  }
810
-
819
+
811
820
  /** Set this color from a hex code
812
821
  * @param {string} hex - html hex code
813
822
  * @return {Color} */
814
823
  setHex(hex)
815
824
  {
816
- ASSERT(typeof hex == 'string' && hex[0] == '#', 'Color hex code must be a string starting with #');
825
+ ASSERT(typeof hex === 'string' && hex[0] === '#', 'Color hex code must be a string starting with #');
817
826
  ASSERT([4,5,7,9].includes(hex.length), 'Invalid hex');
818
827
 
819
828
  if (hex.length < 6)
820
829
  {
821
830
  const fromHex = (c)=> clamp(parseInt(hex[c],16)/15);
822
831
  this.r = fromHex(1);
823
- this.g = fromHex(2),
832
+ this.g = fromHex(2);
824
833
  this.b = fromHex(3);
825
- this.a = hex.length == 5 ? fromHex(4) : 1;
834
+ this.a = hex.length === 5 ? fromHex(4) : 1;
826
835
  }
827
836
  else
828
837
  {
829
838
  const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
830
839
  this.r = fromHex(1);
831
- this.g = fromHex(3),
840
+ this.g = fromHex(3);
832
841
  this.b = fromHex(5);
833
- this.a = hex.length == 9 ? fromHex(7) : 1;
842
+ this.a = hex.length === 9 ? fromHex(7) : 1;
834
843
  }
835
844
 
836
845
  ASSERT_COLOR_VALID(this);
837
846
  return this;
838
847
  }
839
-
848
+
840
849
  /** Returns this color expressed as 32 bit RGBA value
841
850
  * @return {number} */
842
- rgbaInt()
851
+ rgbaInt()
843
852
  {
844
853
  const r = clamp(this.r)*255|0;
845
854
  const g = clamp(this.g)*255<<8;
@@ -851,9 +860,7 @@ class Color
851
860
  /** Checks if this is a valid color
852
861
  * @return {boolean} */
853
862
  isValid()
854
- {
855
- return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a);
856
- }
863
+ { return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a); }
857
864
  }
858
865
 
859
866
  ///////////////////////////////////////////////////////////////////////////////
@@ -862,7 +869,7 @@ class Color
862
869
  /** Color - White #ffffff
863
870
  * @type {Color}
864
871
  * @memberof Utilities */
865
- const WHITE = rgb();
872
+ const WHITE = rgb();
866
873
 
867
874
  /** Color - Clear White #ffffff with 0 alpha
868
875
  * @type {Color}
@@ -977,11 +984,11 @@ class Timer
977
984
  /** Get percentage elapsed based on time it was set to, returns 0 if not set
978
985
  * @return {number} */
979
986
  getPercent() { return this.isSet()? 1-percent(this.time - time, 0, this.setTime) : 0; }
980
-
987
+
981
988
  /** Returns this timer expressed as a string
982
989
  * @return {string} */
983
990
  toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
984
-
991
+
985
992
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
986
993
  * @return {number} */
987
994
  valueOf() { return this.get(); }