littlejsengine 1.9.0 → 1.9.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 (63) hide show
  1. package/README.md +7 -7
  2. package/{build → dist}/littlejs.d.ts +84 -77
  3. package/{build → dist}/littlejs.esm.js +245 -143
  4. package/dist/littlejs.esm.min.js +1 -0
  5. package/{build → dist}/littlejs.js +245 -143
  6. package/dist/littlejs.min.js +1 -0
  7. package/{build → dist}/littlejs.release.js +239 -141
  8. package/examples/breakout/game.js +2 -2
  9. package/examples/breakout/gameObjects.js +3 -3
  10. package/examples/breakout/index.html +3 -3
  11. package/examples/breakoutTutorial/index.html +2 -2
  12. package/examples/electron/build.js +1 -1
  13. package/examples/electron/game.js +49 -38
  14. package/examples/electron/index.html +2 -2
  15. package/examples/electron/tiles.png +0 -0
  16. package/examples/empty/index.html +1 -1
  17. package/examples/js13k/build.js +2 -2
  18. package/examples/js13k/game.js +10 -9
  19. package/examples/js13k/index.html +13 -13
  20. package/examples/js13k/tiles.png +0 -0
  21. package/examples/module/game.js +45 -41
  22. package/examples/module/index.html +1 -1
  23. package/examples/module/tiles.png +0 -0
  24. package/examples/particles/index.html +1 -1
  25. package/examples/platformer/data/gameTileData.tmx +143 -0
  26. package/examples/platformer/data/gameTileData.tsx +4 -0
  27. package/examples/platformer/game.js +0 -1
  28. package/examples/platformer/gameCharacter.js +1 -1
  29. package/examples/platformer/gameEffects.js +42 -110
  30. package/examples/platformer/gameLevel.js +149 -183
  31. package/examples/platformer/gameObjects.js +61 -16
  32. package/examples/platformer/gamePlayer.js +3 -2
  33. package/examples/platformer/gameTileData.js +181 -0
  34. package/examples/platformer/index.html +8 -7
  35. package/examples/platformer/tiles.png +0 -0
  36. package/examples/platformer/tilesLevel.png +0 -0
  37. package/examples/puzzle/game.js +12 -12
  38. package/examples/puzzle/index.html +2 -2
  39. package/examples/starter/build.js +2 -2
  40. package/examples/starter/game.js +6 -6
  41. package/examples/starter/index.html +13 -13
  42. package/examples/starter/tiles.png +0 -0
  43. package/examples/stress/index.html +2 -2
  44. package/examples/typescript/build.bat +4 -1
  45. package/examples/typescript/game.js +34 -31
  46. package/examples/typescript/game.ts +40 -36
  47. package/examples/typescript/index.html +1 -1
  48. package/examples/typescript/tiles.png +0 -0
  49. package/package.json +3 -3
  50. package/src/engine.js +1 -1
  51. package/src/engineAudio.js +4 -10
  52. package/src/engineBuild.js +9 -2
  53. package/src/engineDebug.js +6 -2
  54. package/src/engineDraw.js +27 -27
  55. package/src/engineInput.js +7 -7
  56. package/src/engineMedals.js +2 -2
  57. package/src/engineObject.js +7 -7
  58. package/src/engineParticles.js +9 -9
  59. package/src/engineTileLayer.js +38 -33
  60. package/src/engineUtilities.js +136 -35
  61. package/src/engineWebGL.js +8 -10
  62. package/build/littlejs.esm.min.js +0 -1
  63. package/build/littlejs.min.js +0 -1
@@ -156,13 +156,13 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
156
156
  function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
157
157
 
158
158
  /** Returns true if two axis aligned bounding boxes are overlapping
159
- * @param {Vector2} pointA - Center of box A
160
- * @param {Vector2} sizeA - Size of box A
161
- * @param {Vector2} pointB - Center of box B
162
- * @param {Vector2} sizeB - Size of box B
163
- * @return {Boolean} - True if overlapping
159
+ * @param {Vector2} pointA - Center of box A
160
+ * @param {Vector2} sizeA - Size of box A
161
+ * @param {Vector2} pointB - Center of box B
162
+ * @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
163
+ * @return {Boolean} - True if overlapping
164
164
  * @memberof Utilities */
165
- function isOverlapping(pointA, sizeA, pointB, sizeB)
165
+ function isOverlapping(pointA, sizeA, pointB, sizeB=vec2())
166
166
  {
167
167
  return abs(pointA.x - pointB.x)*2 < sizeA.x + sizeB.x
168
168
  && abs(pointA.y - pointB.y)*2 < sizeA.y + sizeB.y;
@@ -222,8 +222,8 @@ function randInCircle(radius=1, minRadius=0)
222
222
  { return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
223
223
 
224
224
  /** Returns a random color between the two passed in colors, combine components if linear
225
- * @param {Color} [colorA=Color()]
226
- * @param {Color} [colorB=Color(0,0,0,1)]
225
+ * @param {Color} [colorA=(1,1,1,1)]
226
+ * @param {Color} [colorB=(0,0,0,1)]
227
227
  * @param {Boolean} [linear]
228
228
  * @return {Color}
229
229
  * @memberof Random */
@@ -294,7 +294,11 @@ class RandomGenerator
294
294
  * @memberof Utilities
295
295
  */
296
296
  function vec2(x=0, y)
297
- { return typeof x === 'number'? new Vector2(x, y == undefined? x : y) : new Vector2(x.x, x.y); }
297
+ {
298
+ return typeof x === 'number' ?
299
+ new Vector2(x, y == undefined? x : y) :
300
+ new Vector2(x.x, x.y);
301
+ }
298
302
 
299
303
  /**
300
304
  * Check if object is a valid Vector2
@@ -302,7 +306,7 @@ function vec2(x=0, y)
302
306
  * @return {Boolean}
303
307
  * @memberof Utilities
304
308
  */
305
- function isVector2(v) { return typeof v === 'object' && typeof v.x === 'number' && typeof v.y === 'number'; }
309
+ function isVector2(v) { return v instanceof Vector2; }
306
310
 
307
311
  /**
308
312
  * 2D Vector object with vector math library
@@ -333,27 +337,47 @@ class Vector2
333
337
  /** Returns a copy of this vector plus the vector passed in
334
338
  * @param {Vector2} v - other vector
335
339
  * @return {Vector2} */
336
- add(v) { ASSERT(isVector2(v)); return new Vector2(this.x + v.x, this.y + v.y); }
340
+ add(v)
341
+ {
342
+ ASSERT(isVector2(v));
343
+ return new Vector2(this.x + v.x, this.y + v.y);
344
+ }
337
345
 
338
346
  /** Returns a copy of this vector minus the vector passed in
339
347
  * @param {Vector2} v - other vector
340
348
  * @return {Vector2} */
341
- subtract(v) { ASSERT(isVector2(v)); return new Vector2(this.x - v.x, this.y - v.y); }
349
+ subtract(v)
350
+ {
351
+ ASSERT(isVector2(v));
352
+ return new Vector2(this.x - v.x, this.y - v.y);
353
+ }
342
354
 
343
355
  /** Returns a copy of this vector times the vector passed in
344
356
  * @param {Vector2} v - other vector
345
357
  * @return {Vector2} */
346
- multiply(v) { ASSERT(isVector2(v)); return new Vector2(this.x * v.x, this.y * v.y); }
358
+ multiply(v)
359
+ {
360
+ ASSERT(isVector2(v));
361
+ return new Vector2(this.x * v.x, this.y * v.y);
362
+ }
347
363
 
348
364
  /** Returns a copy of this vector divided by the vector passed in
349
365
  * @param {Vector2} v - other vector
350
366
  * @return {Vector2} */
351
- divide(v) { ASSERT(isVector2(v)); return new Vector2(this.x / v.x, this.y / v.y); }
367
+ divide(v)
368
+ {
369
+ ASSERT(isVector2(v));
370
+ return new Vector2(this.x / v.x, this.y / v.y);
371
+ }
352
372
 
353
373
  /** Returns a copy of this vector scaled by the vector passed in
354
374
  * @param {Number} s - scale
355
375
  * @return {Vector2} */
356
- scale(s) { ASSERT(!isVector2(s)); return new Vector2(this.x * s, this.y * s); }
376
+ scale(s)
377
+ {
378
+ ASSERT(!isVector2(s));
379
+ return new Vector2(this.x * s, this.y * s);
380
+ }
357
381
 
358
382
  /** Returns the length of this vector
359
383
  * @return {Number} */
@@ -366,32 +390,56 @@ class Vector2
366
390
  /** Returns the distance from this vector to vector passed in
367
391
  * @param {Vector2} v - other vector
368
392
  * @return {Number} */
369
- distance(v) { return this.distanceSquared(v)**.5; }
393
+ distance(v)
394
+ {
395
+ ASSERT(isVector2(v));
396
+ return this.distanceSquared(v)**.5;
397
+ }
370
398
 
371
399
  /** Returns the distance squared from this vector to vector passed in
372
400
  * @param {Vector2} v - other vector
373
401
  * @return {Number} */
374
- distanceSquared(v) { return (this.x - v.x)**2 + (this.y - v.y)**2; }
402
+ distanceSquared(v)
403
+ {
404
+ ASSERT(isVector2(v));
405
+ return (this.x - v.x)**2 + (this.y - v.y)**2;
406
+ }
375
407
 
376
408
  /** Returns a new vector in same direction as this one with the length passed in
377
409
  * @param {Number} [length]
378
410
  * @return {Vector2} */
379
- normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(0, length); }
411
+ normalize(length=1)
412
+ {
413
+ const l = this.length();
414
+ return l ? this.scale(length/l) : new Vector2(0, length);
415
+ }
380
416
 
381
417
  /** Returns a new vector clamped to length passed in
382
418
  * @param {Number} [length]
383
419
  * @return {Vector2} */
384
- clampLength(length=1) { const l = this.length(); return l > length ? this.scale(length/l) : this; }
420
+ clampLength(length=1)
421
+ {
422
+ const l = this.length();
423
+ return l > length ? this.scale(length/l) : this;
424
+ }
385
425
 
386
426
  /** Returns the dot product of this and the vector passed in
387
427
  * @param {Vector2} v - other vector
388
428
  * @return {Number} */
389
- dot(v) { ASSERT(isVector2(v)); return this.x*v.x + this.y*v.y; }
429
+ dot(v)
430
+ {
431
+ ASSERT(isVector2(v));
432
+ return this.x*v.x + this.y*v.y;
433
+ }
390
434
 
391
435
  /** Returns the cross product of this and the vector passed in
392
436
  * @param {Vector2} v - other vector
393
437
  * @return {Number} */
394
- cross(v) { ASSERT(isVector2(v)); return this.x*v.y - this.y*v.x; }
438
+ cross(v)
439
+ {
440
+ ASSERT(isVector2(v));
441
+ return this.x*v.y - this.y*v.x;
442
+ }
395
443
 
396
444
  /** Returns the angle of this vector, up is angle 0
397
445
  * @return {Number} */
@@ -402,7 +450,11 @@ class Vector2
402
450
  * @param {Number} [length]
403
451
  * @return {Vector2} */
404
452
  setAngle(angle=0, length=1)
405
- { this.x = length*Math.sin(angle); this.y = length*Math.cos(angle); return this; }
453
+ {
454
+ this.x = length*Math.sin(angle);
455
+ this.y = length*Math.cos(angle);
456
+ return this;
457
+ }
406
458
 
407
459
  /** Returns copy of this vector rotated by the angle passed in
408
460
  * @param {Number} angle
@@ -413,9 +465,20 @@ class Vector2
413
465
  return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
414
466
  }
415
467
 
468
+ /** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
469
+ * @param {Number} [direction]
470
+ * @param {Number} [length] */
471
+ setDirection(direction, length=1)
472
+ {
473
+ ASSERT(direction==0 || direction==1 || direction==2 || direction==3);
474
+ return vec2(direction%2 ? direction-1 ? -length : length : 0,
475
+ direction%2 ? 0 : direction ? -length : length);
476
+ }
477
+
416
478
  /** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
417
479
  * @return {Number} */
418
- direction() { return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
480
+ direction()
481
+ { return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
419
482
 
420
483
  /** Returns a copy of this vector that has been inverted
421
484
  * @return {Vector2} */
@@ -434,24 +497,34 @@ class Vector2
434
497
  * @param {Number} percent
435
498
  * @return {Vector2} */
436
499
  lerp(v, percent)
437
- { ASSERT(isVector2(v)); return this.add(v.subtract(this).scale(clamp(percent))); }
500
+ {
501
+ ASSERT(isVector2(v));
502
+ return this.add(v.subtract(this).scale(clamp(percent)));
503
+ }
438
504
 
439
505
  /** Returns true if this vector is within the bounds of an array size passed in
440
506
  * @param {Vector2} arraySize
441
507
  * @return {Boolean} */
442
- arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
508
+ arrayCheck(arraySize)
509
+ {
510
+ ASSERT(isVector2(arraySize));
511
+ return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y;
512
+ }
443
513
 
444
514
  /** Returns this vector expressed as a string
445
515
  * @param {Number} digits - precision to display
446
516
  * @return {String} */
447
517
  toString(digits=3)
448
- { if (debug) { return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`; }}
518
+ {
519
+ if (debug)
520
+ return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
521
+ }
449
522
  }
450
523
 
451
524
  ///////////////////////////////////////////////////////////////////////////////
452
525
 
453
526
  /**
454
- * Create a color object with RGBA values
527
+ * Create a color object with RGBA values, white by default
455
528
  * @param {Number} [r=1] - red
456
529
  * @param {Number} [g=1] - green
457
530
  * @param {Number} [b=1] - blue
@@ -462,7 +535,7 @@ class Vector2
462
535
  function rgb(r, g, b, a) { return new Color(r, g, b, a); }
463
536
 
464
537
  /**
465
- * Create a color object with HSLA values
538
+ * Create a color object with HSLA values, white by default
466
539
  * @param {Number} [h=0] - hue
467
540
  * @param {Number} [s=0] - saturation
468
541
  * @param {Number} [l=1] - lightness
@@ -472,14 +545,22 @@ function rgb(r, g, b, a) { return new Color(r, g, b, a); }
472
545
  */
473
546
  function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
474
547
 
548
+ /**
549
+ * Check if object is a valid Color
550
+ * @param {any} c
551
+ * @return {Boolean}
552
+ * @memberof Utilities
553
+ */
554
+ function isColor(c) { return c instanceof Color; }
555
+
475
556
  /**
476
557
  * Color object (red, green, blue, alpha) with some helpful functions
477
558
  * @example
478
559
  * let a = new Color; // white
479
560
  * let b = new Color(1, 0, 0); // red
480
561
  * let c = new Color(0, 0, 0, 0); // transparent black
481
- * let d = RGB(0, 0, 1); // blue using rgb color
482
- * let e = HSL(.3, 1, .5); // green using hsl color
562
+ * let d = rgb(0, 0, 1); // blue using rgb color
563
+ * let e = hsl(.3, 1, .5); // green using hsl color
483
564
  */
484
565
  class Color
485
566
  {
@@ -507,22 +588,38 @@ class Color
507
588
  /** Returns a copy of this color plus the color passed in
508
589
  * @param {Color} c - other color
509
590
  * @return {Color} */
510
- add(c) { return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a); }
591
+ add(c)
592
+ {
593
+ ASSERT(isColor(c));
594
+ return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a);
595
+ }
511
596
 
512
597
  /** Returns a copy of this color minus the color passed in
513
598
  * @param {Color} c - other color
514
599
  * @return {Color} */
515
- subtract(c) { return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a); }
600
+ subtract(c)
601
+ {
602
+ ASSERT(isColor(c));
603
+ return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a);
604
+ }
516
605
 
517
606
  /** Returns a copy of this color times the color passed in
518
607
  * @param {Color} c - other color
519
608
  * @return {Color} */
520
- multiply(c) { return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a); }
609
+ multiply(c)
610
+ {
611
+ ASSERT(isColor(c));
612
+ return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a);
613
+ }
521
614
 
522
615
  /** Returns a copy of this color divided by the color passed in
523
616
  * @param {Color} c - other color
524
617
  * @return {Color} */
525
- divide(c) { return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a); }
618
+ divide(c)
619
+ {
620
+ ASSERT(isColor(c));
621
+ return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a);
622
+ }
526
623
 
527
624
  /** Returns a copy of this color scaled by the value passed in, alpha can be scaled separately
528
625
  * @param {Number} scale
@@ -539,7 +636,11 @@ class Color
539
636
  * @param {Color} c - other color
540
637
  * @param {Number} percent
541
638
  * @return {Color} */
542
- lerp(c, percent) { return this.add(c.subtract(this).scale(clamp(percent))); }
639
+ lerp(c, percent)
640
+ {
641
+ ASSERT(isColor(c));
642
+ return this.add(c.subtract(this).scale(clamp(percent)));
643
+ }
543
644
 
544
645
  /** Sets this color given a hue, saturation, lightness, and alpha
545
646
  * @param {Number} [h] - hue
@@ -1179,12 +1280,12 @@ function setDebugKey(key) { debugKey = key; }
1179
1280
  class EngineObject
1180
1281
  {
1181
1282
  /** Create an engine object and adds it to the list of objects
1182
- * @param {Vector2} [pos=Vector2()] - World space position of the object
1183
- * @param {Vector2} [size=Vector2(1,1)] - World space size of the object
1184
- * @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
1185
- * @param {Number} [angle] - Angle the object is rotated by
1186
- * @param {Color} [color=Color()] - Color to apply to tile when rendered
1187
- * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
1283
+ * @param {Vector2} [pos=(0,0)] - World space position of the object
1284
+ * @param {Vector2} [size=(1,1)] - World space size of the object
1285
+ * @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
1286
+ * @param {Number} [angle] - Angle the object is rotated by
1287
+ * @param {Color} [color=(1,1,1,1)] - Color to apply to tile when rendered
1288
+ * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
1188
1289
  */
1189
1290
  constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
1190
1291
  {
@@ -1484,7 +1585,7 @@ class EngineObject
1484
1585
 
1485
1586
  /** Attaches a child to this with a given local transform
1486
1587
  * @param {EngineObject} child
1487
- * @param {Vector2} [localPos=Vector2()]
1588
+ * @param {Vector2} [localPos=(0,0)]
1488
1589
  * @param {Number} [localAngle] */
1489
1590
  addChild(child, localPos=vec2(), localAngle=0)
1490
1591
  {
@@ -1601,7 +1702,7 @@ let drawCount;
1601
1702
  * Create a tile info object
1602
1703
  * - This can take vecs or floats for easier use and conversion
1603
1704
  * - If an index is passed in, the tile size and index will determine the position
1604
- * @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
1705
+ * @param {(Number|Vector2)} [pos=(0,0)] - Top left corner of tile in pixels or index
1605
1706
  * @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
1606
1707
  * @param {Number} [textureIndex] - Texture index to use
1607
1708
  * @return {TileInfo}
@@ -1644,7 +1745,7 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
1644
1745
  class TileInfo
1645
1746
  {
1646
1747
  /** Create a tile info object
1647
- * @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
1748
+ * @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
1648
1749
  * @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
1649
1750
  * @param {Number} [textureIndex] - Texture index to use
1650
1751
  */
@@ -1721,16 +1822,16 @@ function worldToScreen(worldPos)
1721
1822
  }
1722
1823
 
1723
1824
  /** Draw textured tile centered in world space, with color applied if using WebGL
1724
- * @param {Vector2} pos - Center of the tile in world space
1725
- * @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
1726
- * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
1727
- * @param {Color} [color=Color()] - Color to modulate with
1728
- * @param {Number} [angle] - Angle to rotate by
1729
- * @param {Boolean} [mirror] - If true image is flipped along the Y axis
1730
- * @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
1731
- * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
1732
- * @param {Boolean} [screenSpace] - If true the pos and size are in screen space
1733
- * @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
1825
+ * @param {Vector2} pos - Center of the tile in world space
1826
+ * @param {Vector2} [size=(1,1)] - Size of the tile in world space
1827
+ * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
1828
+ * @param {Color} [color=(1,1,1,1)] - Color to modulate with
1829
+ * @param {Number} [angle] - Angle to rotate by
1830
+ * @param {Boolean} [mirror] - If true image is flipped along the Y axis
1831
+ * @param {Color} [additiveColor=(0,0,0,0)] - Additive color to be applied
1832
+ * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
1833
+ * @param {Boolean} [screenSpace=false] - If true the pos and size are in screen space
1834
+ * @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
1734
1835
  * @memberof Draw */
1735
1836
  function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
1736
1837
  angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
@@ -1798,11 +1899,11 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
1798
1899
 
1799
1900
  /** Draw colored rect centered on pos
1800
1901
  * @param {Vector2} pos
1801
- * @param {Vector2} [size=Vector2(1,1)]
1802
- * @param {Color} [color=Color()]
1902
+ * @param {Vector2} [size=(1,1)]
1903
+ * @param {Color} [color=(1,1,1,1)]
1803
1904
  * @param {Number} [angle]
1804
1905
  * @param {Boolean} [useWebGL=glEnable]
1805
- * @param {Boolean} [screenSpace]
1906
+ * @param {Boolean} [screenSpace=false]
1806
1907
  * @param {CanvasRenderingContext2D} [context]
1807
1908
  * @memberof Draw */
1808
1909
  function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
@@ -1812,8 +1913,8 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
1812
1913
 
1813
1914
  /** Draw colored polygon using passed in points
1814
1915
  * @param {Array} points - Array of Vector2 points
1815
- * @param {Color} [color=Color()]
1816
- * @param {Boolean} [screenSpace]
1916
+ * @param {Color} [color=(1,1,1,1)]
1917
+ * @param {Boolean} [screenSpace=false]
1817
1918
  * @param {CanvasRenderingContext2D} [context=mainContext]
1818
1919
  * @memberof Draw */
1819
1920
  function drawPoly(points, color=new Color, screenSpace, context=mainContext)
@@ -1829,9 +1930,9 @@ function drawPoly(points, color=new Color, screenSpace, context=mainContext)
1829
1930
  * @param {Vector2} posA
1830
1931
  * @param {Vector2} posB
1831
1932
  * @param {Number} [thickness]
1832
- * @param {Color} [color=Color()]
1933
+ * @param {Color} [color=(1,1,1,1)]
1833
1934
  * @param {Boolean} [useWebGL=glEnable]
1834
- * @param {Boolean} [screenSpace]
1935
+ * @param {Boolean} [screenSpace=false]
1835
1936
  * @param {CanvasRenderingContext2D} [context]
1836
1937
  * @memberof Draw */
1837
1938
  function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
@@ -1847,7 +1948,7 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, contex
1847
1948
  * @param {Number} angle
1848
1949
  * @param {Boolean} mirror
1849
1950
  * @param {Function} drawFunction
1850
- * @param {Boolean} [screenSpace]
1951
+ * @param {Boolean} [screenSpace=false]
1851
1952
  * @param {CanvasRenderingContext2D} [context=mainContext]
1852
1953
  * @memberof Draw */
1853
1954
  function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
@@ -1889,9 +1990,9 @@ function setBlendMode(additive, useWebGL=glEnable, context)
1889
1990
  * @param {String} text
1890
1991
  * @param {Vector2} pos
1891
1992
  * @param {Number} [size]
1892
- * @param {Color} [color=Color()]
1993
+ * @param {Color} [color=(1,1,1,1)]
1893
1994
  * @param {Number} [lineWidth]
1894
- * @param {Color} [lineColor=Color(0,0,0)]
1995
+ * @param {Color} [lineColor=(0,0,0,1)]
1895
1996
  * @param {CanvasTextAlign} [textAlign='center']
1896
1997
  * @param {String} [font=fontDefault]
1897
1998
  * @param {CanvasRenderingContext2D} [context=overlayContext]
@@ -1906,9 +2007,9 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
1906
2007
  * @param {String} text
1907
2008
  * @param {Vector2} pos
1908
2009
  * @param {Number} [size]
1909
- * @param {Color} [color=Color()]
2010
+ * @param {Color} [color=(1,1,1,1)]
1910
2011
  * @param {Number} [lineWidth]
1911
- * @param {Color} [lineColor=Color(0,0,0)]
2012
+ * @param {Color} [lineColor=(0,0,0,1)]
1912
2013
  * @param {CanvasTextAlign} [textAlign]
1913
2014
  * @param {String} [font=fontDefault]
1914
2015
  * @param {CanvasRenderingContext2D} [context=overlayContext]
@@ -1951,9 +2052,9 @@ let engineFontImage;
1951
2052
  class FontImage
1952
2053
  {
1953
2054
  /** Create an image font
1954
- * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
1955
- * @param {Vector2} [tileSize=Vector2(8)] - Size of the font source tiles
1956
- * @param {Vector2} [paddingSize=Vector2(0,1)] - How much extra space to add between characters
2055
+ * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
2056
+ * @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
2057
+ * @param {Vector2} [paddingSize=(0,1)] - How much extra space to add between characters
1957
2058
  * @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
1958
2059
  */
1959
2060
  constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
@@ -2231,10 +2332,10 @@ function inputUpdatePost()
2231
2332
  ///////////////////////////////////////////////////////////////////////////////
2232
2333
  // Mouse event handlers
2233
2334
 
2234
- onmousedown = (e)=> {isUsingGamepad = false; inputData[0][e.button] = 3; window.onmousemove(e); e.button && e.preventDefault();}
2335
+ onmousedown = (e)=> {isUsingGamepad = false; inputData[0][e.button] = 3; mousePosScreen = mouseToScreen(e); e.button && e.preventDefault();}
2235
2336
  onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
2236
2337
  onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
2237
- onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
2338
+ onwheel = (e)=> mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
2238
2339
  oncontextmenu = (e)=> false; // prevent right click menu
2239
2340
 
2240
2341
  // convert a mouse or touch event position to screen space
@@ -2328,7 +2429,7 @@ function gamepadsUpdate()
2328
2429
  ///////////////////////////////////////////////////////////////////////////////
2329
2430
 
2330
2431
  /** Pulse the vibration hardware if it exists
2331
- * @param {Number} [pattern] - a single value in miliseconds or vibration interval array
2432
+ * @param {Number|Array} [pattern] - single value in ms or vibration interval array
2332
2433
  * @memberof Input */
2333
2434
  function vibrate(pattern=100)
2334
2435
  { vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern); }
@@ -2354,9 +2455,9 @@ if (isTouchDevice)
2354
2455
  // handle all touch events the same way
2355
2456
  ontouchstart = ontouchmove = ontouchend = (e)=>
2356
2457
  {
2357
- // fix stalled audio on mobile
2358
- if (soundEnable)
2359
- audioContext ? audioContext.resume() : zzfx(0);
2458
+ // fix stalled audio requiring user interaction
2459
+ if (soundEnable && audioContext && audioContext.state != 'running')
2460
+ zzfx(0);
2360
2461
 
2361
2462
  // check if touching and pass to mouse events
2362
2463
  const touching = e.touches.length;
@@ -2502,7 +2603,7 @@ function touchGamepadRender()
2502
2603
  const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
2503
2604
  for (let i=4; i--;)
2504
2605
  {
2505
- const pos = rightCenter.add(vec2().setAngle(i*PI/2, touchGamepadSize/2));
2606
+ const pos = rightCenter.add(vec2().setDirection(i, touchGamepadSize/2));
2506
2607
  overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
2507
2608
  overlayContext.beginPath();
2508
2609
  overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
@@ -2661,22 +2762,19 @@ class SoundWave extends Sound
2661
2762
  this.randomness = randomness;
2662
2763
 
2663
2764
  if (!soundEnable) return;
2664
- if (!soundDecoderContext)
2665
- soundDecoderContext = new AudioContext;
2666
2765
 
2667
2766
  fetch(filename)
2668
2767
  .then(response => response.arrayBuffer())
2669
- .then(arrayBuffer => soundDecoderContext.decodeAudioData(arrayBuffer))
2768
+ .then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
2670
2769
  .then(audioBuffer =>
2671
2770
  {
2672
2771
  this.sampleChannels = [];
2673
2772
  for (let i = audioBuffer.numberOfChannels; i--;)
2674
- this.sampleChannels[i] = audioBuffer.getChannelData(i);
2773
+ this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
2675
2774
  this.sampleRate = audioBuffer.sampleRate;
2676
2775
  });
2677
2776
  }
2678
2777
  }
2679
- let soundDecoderContext; // audio context used only to decode audio files
2680
2778
 
2681
2779
  /**
2682
2780
  * Music Object - Stores a zzfx music track for later use
@@ -2790,8 +2888,9 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
2790
2888
  ///////////////////////////////////////////////////////////////////////////////
2791
2889
 
2792
2890
  /** Audio context used by the engine
2891
+ * @type {AudioContext}
2793
2892
  * @memberof Audio */
2794
- let audioContext;
2893
+ let audioContext = new AudioContext;
2795
2894
 
2796
2895
  /** Play cached audio samples with given settings
2797
2896
  * @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
@@ -2806,10 +2905,6 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
2806
2905
  {
2807
2906
  if (!soundEnable) return;
2808
2907
 
2809
- // create audio context if needed
2810
- if (!audioContext)
2811
- audioContext = new AudioContext;
2812
-
2813
2908
  // prevent sounds from building up if they can't be played
2814
2909
  if (audioContext.state != 'running')
2815
2910
  {
@@ -3135,7 +3230,7 @@ function getTileCollisionData(pos)
3135
3230
 
3136
3231
  /** Check if collision with another object should occur
3137
3232
  * @param {Vector2} pos
3138
- * @param {Vector2} [size=Vector2(1,1)]
3233
+ * @param {Vector2} [size=(1,1)]
3139
3234
  * @param {EngineObject} [object]
3140
3235
  * @return {Boolean}
3141
3236
  * @memberof TileCollision */
@@ -3220,7 +3315,7 @@ class TileLayerData
3220
3315
  * @param {Number} [direction] - Integer direction of tile, in 90 degree increments
3221
3316
  * @param {Boolean} [mirror] - If the tile should be mirrored along the x axis
3222
3317
  * @param {Color} [color] - Color of the tile */
3223
- constructor(tile, direction=0, mirror=false, color=new Color())
3318
+ constructor(tile, direction=0, mirror=false, color=new Color)
3224
3319
  {
3225
3320
  /** @property {Number} - The tile to use, untextured if undefined */
3226
3321
  this.tile = tile;
@@ -3251,11 +3346,11 @@ class TileLayerData
3251
3346
  class TileLayer extends EngineObject
3252
3347
  {
3253
3348
  /** Create a tile layer object
3254
- * @param {Vector2} [position=Vector2()] - World space position
3349
+ * @param {Vector2} [position=(0,0)] - World space position
3255
3350
  * @param {Vector2} [size=tileCollisionSize] - World space size
3256
- * @param {TileInfo} [tileInfo] - Tile info for layer
3257
- * @param {Vector2} [scale=Vector2(1,1)] - How much to scale this layer when rendered
3258
- * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
3351
+ * @param {TileInfo} [tileInfo] - Tile info for layer
3352
+ * @param {Vector2} [scale=(1,1)] - How much to scale this layer when rendered
3353
+ * @param {Number} [renderOrder] - Objects are sorted by renderOrder
3259
3354
  */
3260
3355
  constructor(position, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderOrder=0)
3261
3356
  {
@@ -3316,16 +3411,18 @@ class TileLayer extends EngineObject
3316
3411
  }
3317
3412
 
3318
3413
  /** Draw all the tile data to an offscreen canvas
3319
- * - This may be slow in some browsers
3320
- */
3414
+ * - This may be slow in some browsers but only needs to be done once */
3321
3415
  redraw()
3322
3416
  {
3323
3417
  this.redrawStart(true);
3324
- this.drawAllTileData();
3418
+ for (let x = this.size.x; x--;)
3419
+ for (let y = this.size.y; y--;)
3420
+ this.drawTileData(vec2(x,y), false);
3325
3421
  this.redrawEnd();
3326
3422
  }
3327
3423
 
3328
3424
  /** Call to start the redraw process
3425
+ * - This can be used to manually update small parts of the level
3329
3426
  * @param {Boolean} [clear] - Should it clear the canvas before drawing */
3330
3427
  redrawStart(clear=false)
3331
3428
  {
@@ -3333,17 +3430,19 @@ class TileLayer extends EngineObject
3333
3430
  /** @type {[HTMLCanvasElement, CanvasRenderingContext2D, Vector2, Vector2, number]} */
3334
3431
  this.savedRenderSettings = [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale];
3335
3432
 
3336
- // hack: use normal rendering system to render the tiles
3433
+ // use webgl rendering system to render the tiles if enabled
3434
+ // this works by temporally taking control of the rendering system
3337
3435
  mainCanvas = this.canvas;
3338
3436
  mainContext = this.context;
3437
+ mainCanvasSize = this.size.multiply(this.tileInfo.size);
3339
3438
  cameraPos = this.size.scale(.5);
3340
3439
  cameraScale = this.tileInfo.size.x;
3341
3440
 
3342
3441
  if (clear)
3343
3442
  {
3344
3443
  // clear and set size
3345
- mainCanvas.width = this.size.x * this.tileInfo.size.x;
3346
- mainCanvas.height = this.size.y * this.tileInfo.size.y;
3444
+ mainCanvas.width = mainCanvasSize.x;
3445
+ mainCanvas.height = mainCanvasSize.y;
3347
3446
  }
3348
3447
 
3349
3448
  // begin a new render for the tile canvas
@@ -3361,32 +3460,33 @@ class TileLayer extends EngineObject
3361
3460
  [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale] = this.savedRenderSettings;
3362
3461
  }
3363
3462
 
3364
- /** Draw the tile at a given position
3365
- * @param {Vector2} layerPos */
3366
- drawTileData(layerPos)
3463
+ /** Draw the tile at a given position in the tile grid
3464
+ * This can be used to clear out tiles when they are destroyed
3465
+ * Tiles can also be redrawn if isinde a redrawStart/End block
3466
+ * @param {Vector2} layerPos
3467
+ * @param {Boolean} [clear] - should the old tile be cleared out
3468
+ */
3469
+ drawTileData(layerPos, clear=true)
3367
3470
  {
3368
- // first clear out where the tile was
3369
- const pos = layerPos.floor().add(this.pos).add(vec2(.5));
3370
- this.drawCanvas2D(pos, vec2(1), 0, false, (context)=>context.clearRect(-.5, -.5, 1, 1));
3471
+ // clear out where the tile was, for full opaque tiles this can be skipped
3472
+ const s = this.tileInfo.size;
3473
+ if (clear)
3474
+ {
3475
+ const pos = layerPos.multiply(s);
3476
+ this.context.clearRect(pos.x, this.canvas.height-pos.y, s.x, -s.y);
3477
+ }
3371
3478
 
3372
3479
  // draw the tile if not undefined
3373
3480
  const d = this.getData(layerPos);
3374
3481
  if (d.tile != undefined)
3375
3482
  {
3483
+ const pos = this.pos.add(layerPos).add(vec2(.5));
3376
3484
  ASSERT(mainContext == this.context, 'must call redrawStart() before drawing tiles');
3377
- const tileInfo = tile(d.tile, this.tileInfo.size, this.tileInfo.textureIndex);
3485
+ const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex);
3378
3486
  drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
3379
3487
  }
3380
3488
  }
3381
3489
 
3382
- /** Draw all the tiles in this layer */
3383
- drawAllTileData()
3384
- {
3385
- for (let x = this.size.x; x--;)
3386
- for (let y = this.size.y; y--;)
3387
- this.drawTileData(vec2(x,y));
3388
- }
3389
-
3390
3490
  /** Draw directly to the 2D canvas in world space (bipass webgl)
3391
3491
  * @param {Vector2} pos
3392
3492
  * @param {Vector2} size
@@ -3406,11 +3506,11 @@ class TileLayer extends EngineObject
3406
3506
  context.restore();
3407
3507
  }
3408
3508
 
3409
- /** Draw a tile directly onto the layer canvas
3509
+ /** Draw a tile directly onto the layer canvas in world space
3410
3510
  * @param {Vector2} pos
3411
- * @param {Vector2} [size=Vector2(1,1)]
3511
+ * @param {Vector2} [size=(1,1)]
3412
3512
  * @param {TileInfo} [tileInfo]
3413
- * @param {Color} [color=Color()]
3513
+ * @param {Color} [color=(1,1,1,1)]
3414
3514
  * @param {Number} [angle=0]
3415
3515
  * @param {Boolean} [mirror=0] */
3416
3516
  drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
@@ -3435,10 +3535,10 @@ class TileLayer extends EngineObject
3435
3535
  });
3436
3536
  }
3437
3537
 
3438
- /** Draw a rectangle directly onto the layer canvas
3538
+ /** Draw a rectangle directly onto the layer canvas in world space
3439
3539
  * @param {Vector2} pos
3440
- * @param {Vector2} [size=Vector2(1,1)]
3441
- * @param {Color} [color=Color()]
3540
+ * @param {Vector2} [size=(1,1)]
3541
+ * @param {Color} [color=(1,1,1,1)]
3442
3542
  * @param {Number} [angle=0] */
3443
3543
  drawRect(pos, size, color, angle)
3444
3544
  { this.drawTile(pos, size, undefined, color, angle); }
@@ -3455,12 +3555,12 @@ class TileLayer extends EngineObject
3455
3555
  * @example
3456
3556
  * // create a particle emitter
3457
3557
  * let pos = vec2(2,3);
3458
- * let particleEmiter = new ParticleEmitter
3558
+ * let particleEmitter = new ParticleEmitter
3459
3559
  * (
3460
- * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
3461
- * tile(0, 16), // tileInfo
3462
- * new Color(1,1,1), new Color(0,0,0), // colorStartA, colorStartB
3463
- * new Color(1,1,1,0), new Color(0,0,0,0), // colorEndA, colorEndB
3560
+ * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
3561
+ * tile(0, 16), // tileInfo
3562
+ * rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
3563
+ * rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
3464
3564
  * 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
3465
3565
  * .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
3466
3566
  * .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
@@ -3476,10 +3576,10 @@ class ParticleEmitter extends EngineObject
3476
3576
  * @param {Number} [emitRate] - How many particles per second to spawn, does not emit if 0
3477
3577
  * @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
3478
3578
  * @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
3479
- * @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
3480
- * @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
3481
- * @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
3482
- * @param {Color} [colorEndB=Color(1,1,1,0)] - Color at end of life 2, randomized between end colors
3579
+ * @param {Color} [colorStartA=(1,1,1,1)] - Color at start of life 1, randomized between start colors
3580
+ * @param {Color} [colorStartB=(1,1,1,1)] - Color at start of life 2, randomized between start colors
3581
+ * @param {Color} [colorEndA=(1,1,1,0)] - Color at end of life 1, randomized between end colors
3582
+ * @param {Color} [colorEndB=(1,1,1,0)] - Color at end of life 2, randomized between end colors
3483
3583
  * @param {Number} [particleTime] - How long particles live
3484
3584
  * @param {Number} [sizeStart] - How big are particles at start
3485
3585
  * @param {Number} [sizeEnd] - How big are particles at end
@@ -3867,8 +3967,8 @@ class Medal
3867
3967
  // draw containing rect and clip to that region
3868
3968
  context.save();
3869
3969
  context.beginPath();
3870
- context.fillStyle = rgb(.9,.9,.9).toString();
3871
- context.strokeStyle = rgb(0,0,0).toString();
3970
+ context.fillStyle = new Color(.9,.9,.9).toString();
3971
+ context.strokeStyle = new Color(0,0,0).toString();
3872
3972
  context.lineWidth = 3;
3873
3973
  context.rect(x, y, width, medalDisplaySize.y);
3874
3974
  context.fill();
@@ -4317,8 +4417,10 @@ function glCopyToContext(context, forceDraw=false)
4317
4417
  * @memberof WebGL */
4318
4418
  function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdditive=0)
4319
4419
  {
4420
+ ASSERT(typeof rgba == 'number' && typeof rgbaAdditive == 'number', 'invalid color');
4421
+
4320
4422
  // flush if there is not enough room or if different blend mode
4321
- if (glInstanceCount >= gl_MAX_INSTANCES-1 || glBatchAdditive != glAdditive)
4423
+ if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
4322
4424
  glFlush();
4323
4425
 
4324
4426
  let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
@@ -4345,7 +4447,7 @@ let glPostShader, glPostArrayBuffer, glPostTexture, glPostIncludeOverlay;
4345
4447
  * @param {String} shaderCode
4346
4448
  * @param {Boolean} includeOverlay
4347
4449
  * @memberof WebGL */
4348
- function glInitPostProcess(shaderCode, includeOverlay)
4450
+ function glInitPostProcess(shaderCode, includeOverlay=false)
4349
4451
  {
4350
4452
  ASSERT(!glPostShader, 'can only have 1 post effects shader');
4351
4453
 
@@ -4381,6 +4483,8 @@ function glInitPostProcess(shaderCode, includeOverlay)
4381
4483
 
4382
4484
  // hide the original 2d canvas
4383
4485
  mainCanvas.style.visibility = 'hidden';
4486
+ if (glPostIncludeOverlay)
4487
+ overlayCanvas.style.visibility = 'hidden';
4384
4488
  }
4385
4489
 
4386
4490
  // Render the post processing shader, called automatically by the engine
@@ -4401,14 +4505,8 @@ function glRenderPostProcess()
4401
4505
  glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
4402
4506
  }
4403
4507
 
4404
- if (glPostIncludeOverlay)
4405
- {
4406
- // copy overlay canvas so it will be included in post processing
4407
- mainContext.drawImage(overlayCanvas, 0, 0);
4408
-
4409
- // clear overlay canvas
4410
- overlayCanvas.width = mainCanvas.width;
4411
- }
4508
+ // copy overlay canvas so it will be included in post processing
4509
+ glPostIncludeOverlay && mainContext.drawImage(overlayCanvas, 0, 0);
4412
4510
 
4413
4511
  // setup shader program to draw one triangle
4414
4512
  glContext.useProgram(glPostShader);
@@ -4502,7 +4600,7 @@ const engineName = 'LittleJS';
4502
4600
  * @type {String}
4503
4601
  * @default
4504
4602
  * @memberof Engine */
4505
- const engineVersion = '1.9.0';
4603
+ const engineVersion = '1.9.2';
4506
4604
 
4507
4605
  /** Frames per second to update objects
4508
4606
  * @type {Number}