littlejsengine 1.6.6 → 1.6.92

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 (57) hide show
  1. package/README.md +51 -35
  2. package/build/littlejs.d.ts +71 -80
  3. package/build/littlejs.esm.js +162 -139
  4. package/build/littlejs.esm.min.js +1 -1
  5. package/build/littlejs.js +159 -129
  6. package/build/littlejs.min.js +1 -1
  7. package/build/littlejs.release.js +1942 -1907
  8. package/examples/breakout/game.js +5 -1
  9. package/examples/breakout/index.html +5 -5
  10. package/examples/breakoutTutorial/README.md +6 -6
  11. package/examples/breakoutTutorial/game.js +3 -0
  12. package/examples/breakoutTutorial/index.html +3 -3
  13. package/examples/electron/build.js +105 -0
  14. package/examples/electron/game.js +4 -2
  15. package/examples/electron/index.html +13 -2
  16. package/examples/electron/package.json +5 -3
  17. package/examples/empty/game.js +3 -1
  18. package/examples/empty/index.html +1 -1
  19. package/examples/js13k/build.bat +2 -0
  20. package/examples/js13k/build.js +110 -0
  21. package/examples/js13k/game.js +109 -0
  22. package/examples/js13k/index.html +18 -0
  23. package/examples/js13k/tiles.png +0 -0
  24. package/examples/module/game.js +9 -3
  25. package/examples/module/index.html +2 -2
  26. package/examples/particles/index.html +7 -13
  27. package/examples/platformer/game.js +5 -2
  28. package/examples/platformer/gameEffects.js +1 -2
  29. package/examples/platformer/gamePlayer.js +2 -2
  30. package/examples/platformer/index.html +8 -8
  31. package/examples/puzzle/game.js +5 -3
  32. package/examples/puzzle/index.html +4 -4
  33. package/examples/starter/build.bat +2 -78
  34. package/examples/starter/build.js +109 -0
  35. package/examples/starter/game.js +4 -1
  36. package/examples/starter/index.html +15 -18
  37. package/examples/stress/index.html +2 -4
  38. package/examples/typescript/build.bat +2 -14
  39. package/examples/typescript/build.js +31 -0
  40. package/examples/typescript/game.js +94 -89
  41. package/examples/typescript/game.ts +9 -3
  42. package/examples/typescript/index.html +2 -2
  43. package/package.json +2 -2
  44. package/src/engine.js +3 -3
  45. package/src/engineAudio.js +2 -2
  46. package/src/engineBuild.bat +2 -132
  47. package/src/engineBuild.js +143 -0
  48. package/src/engineDebug.js +4 -10
  49. package/src/engineDraw.js +12 -4
  50. package/src/engineExport.js +1 -8
  51. package/src/engineInput.js +1 -1
  52. package/src/engineObject.js +13 -11
  53. package/src/engineParticles.js +6 -6
  54. package/src/engineRelease.js +0 -1
  55. package/src/engineTileLayer.js +31 -18
  56. package/src/engineUtilities.js +74 -61
  57. package/examples/electron/build.bat +0 -52
@@ -34,12 +34,6 @@ const debugPointSize = .5;
34
34
  * @memberof Debug */
35
35
  let showWatermark = 1;
36
36
 
37
- /** True if god mode is enabled, handle this however you want
38
- * @type {Boolean}
39
- * @default
40
- * @memberof Debug */
41
- let godMode = 0;
42
-
43
37
  /** Key code used to toggle debug mode, Esc by default
44
38
  * @type {Boolean}
45
39
  * @default
@@ -180,7 +174,7 @@ function debugUpdate()
180
174
  if (keyWasPressed(51)) // 3
181
175
  debugGamepads = !debugGamepads;
182
176
  if (keyWasPressed(52)) // 4
183
- godMode = !godMode;
177
+ debugRaycast = !debugRaycast;
184
178
  if (keyWasPressed(53)) // 5
185
179
  debugTakeScreenshot = 1;
186
180
  //if (keyWasPressed(54)) // 6
@@ -359,8 +353,8 @@ function debugRender()
359
353
  overlayContext.fillText('2: Debug Particles', x, y += h);
360
354
  overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
361
355
  overlayContext.fillText('3: Debug Gamepads', x, y += h);
362
- overlayContext.fillStyle = godMode ? '#f00' : '#fff';
363
- overlayContext.fillText('4: God Mode', x, y += h);
356
+ overlayContext.fillStyle = debugRaycast ? '#f00' : '#fff';
357
+ overlayContext.fillText('4: Debug Raycasts', x, y += h);
364
358
  overlayContext.fillStyle = '#fff';
365
359
  overlayContext.fillText('5: Save Screenshot', x, y += h);
366
360
 
@@ -385,13 +379,13 @@ function debugRender()
385
379
  {
386
380
  overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
387
381
  overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
388
- overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
382
+ overlayContext.fillText(debugRaycast ? 'Debug Raycasts' : '', x, y += h);
389
383
  overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
390
384
  }
391
385
 
392
386
  overlayContext.restore();
393
387
  }
394
- }
388
+ }
395
389
  /**
396
390
  * LittleJS Utility Classes and Functions
397
391
  * - General purpose math library
@@ -413,34 +407,34 @@ const PI = Math.PI;
413
407
  * @param {Number} value
414
408
  * @return {Number}
415
409
  * @memberof Utilities */
416
- function abs(a) { return a < 0 ? -a : a; }
410
+ function abs(value) { return Math.abs(value); }
417
411
 
418
412
  /** Returns lowest of two values passed in
419
413
  * @param {Number} valueA
420
414
  * @param {Number} valueB
421
415
  * @return {Number}
422
416
  * @memberof Utilities */
423
- function min(a, b) { return a < b ? a : b; }
417
+ function min(valueA, valueB) { return Math.min(valueA, valueB); }
424
418
 
425
419
  /** Returns highest of two values passed in
426
420
  * @param {Number} valueA
427
421
  * @param {Number} valueB
428
422
  * @return {Number}
429
423
  * @memberof Utilities */
430
- function max(a, b) { return a > b ? a : b; }
424
+ function max(valueA, valueB) { return Math.max(valueA, valueB); }
431
425
 
432
426
  /** Returns the sign of value passed in (also returns 1 if 0)
433
427
  * @param {Number} value
434
428
  * @return {Number}
435
429
  * @memberof Utilities */
436
- function sign(a) { return a < 0 ? -1 : 1; }
430
+ function sign(value) { return Math.sign(value); }
437
431
 
438
432
  /** Returns first parm modulo the second param, but adjusted so negative numbers work as expected
439
433
  * @param {Number} dividend
440
434
  * @param {Number} [divisor=1]
441
435
  * @return {Number}
442
436
  * @memberof Utilities */
443
- function mod(a, b=1) { return ((a % b) + b) % b; }
437
+ function mod(dividend, divisor=1) { return ((dividend % divisor) + divisor) % divisor; }
444
438
 
445
439
  /** Clamps the value beween max and min
446
440
  * @param {Number} value
@@ -448,8 +442,8 @@ function mod(a, b=1) { return ((a % b) + b) % b; }
448
442
  * @param {Number} [max=1]
449
443
  * @return {Number}
450
444
  * @memberof Utilities */
451
- function clamp(v, min=0, max=1)
452
- { return v < min ? min : v > max ? max : v; }
445
+ function clamp(value, min=0, max=1)
446
+ { return value < min ? min : value > max ? max : value; }
453
447
 
454
448
  /** Returns what percentage the value is between max and min
455
449
  * @param {Number} value
@@ -457,8 +451,8 @@ function clamp(v, min=0, max=1)
457
451
  * @param {Number} [max=1]
458
452
  * @return {Number}
459
453
  * @memberof Utilities */
460
- function percent(v, min=0, max=1)
461
- { return max-min ? clamp((v-min) / (max-min)) : 0; }
454
+ function percent(value, min=0, max=1)
455
+ { return max-min ? clamp((value-min) / (max-min)) : 0; }
462
456
 
463
457
  /** Linearly interpolates the percent value between max and min
464
458
  * @param {Number} percent
@@ -466,29 +460,32 @@ function percent(v, min=0, max=1)
466
460
  * @param {Number} [max=1]
467
461
  * @return {Number}
468
462
  * @memberof Utilities */
469
- function lerp(p, min=0, max=1){ return min + clamp(p) * (max-min); }
463
+ function lerp(percent, min=0, max=1){ return min + clamp(percent) * (max-min); }
470
464
 
471
465
  /** Applies smoothstep function to the percentage value
472
- * @param {Number} value
466
+ * @param {Number} percent
473
467
  * @return {Number}
474
468
  * @memberof Utilities */
475
- function smoothStep(p) { return p * p * (3 - 2 * p); }
469
+ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
476
470
 
477
471
  /** Returns the nearest power of two not less then the value
478
472
  * @param {Number} value
479
473
  * @return {Number}
480
474
  * @memberof Utilities */
481
- function nearestPowerOfTwo(v) { return 2**Math.ceil(Math.log2(v)); }
475
+ function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
482
476
 
483
477
  /** Returns true if two axis aligned bounding boxes are overlapping
484
478
  * @param {Vector2} pointA - Center of box A
485
479
  * @param {Vector2} sizeA - Size of box A
486
480
  * @param {Vector2} pointB - Center of box B
487
- * @param {Vector2} [sizeB] - Size of box B
481
+ * @param {Vector2} sizeB - Size of box B
488
482
  * @return {Boolean} - True if overlapping
489
483
  * @memberof Utilities */
490
- function isOverlapping(pA, sA, pB, sB)
491
- { return abs(pA.x - pB.x)*2 < sA.x + sB.x && abs(pA.y - pB.y)*2 < sA.y + sB.y; }
484
+ function isOverlapping(pointA, sizeA, pointB, sizeB)
485
+ {
486
+ return abs(pointA.x - pointB.x)*2 < sizeA.x + sizeB.x
487
+ && abs(pointA.y - pointB.y)*2 < sizeA.y + sizeB.y;
488
+ }
492
489
 
493
490
  /** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
494
491
  * @param {Number} [frequency=1] - Frequency of the wave in Hz
@@ -515,14 +512,14 @@ function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
515
512
  * @param {Number} [valueB=0]
516
513
  * @return {Number}
517
514
  * @memberof Random */
518
- function rand(a=1, b=0) { return b + (a-b)*Math.random(); }
515
+ function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valueB); }
519
516
 
520
517
  /** Returns a floored random value the two values passed in
521
518
  * @param {Number} [valueA=1]
522
519
  * @param {Number} [valueB=0]
523
520
  * @return {Number}
524
521
  * @memberof Random */
525
- function randInt(a=1, b=0) { return rand(a,b)|0; }
522
+ function randInt(valueA=1, valueB=0) { return Math.floor(rand(valueA,valueB)); }
526
523
 
527
524
  /** Randomly returns either -1 or 1
528
525
  * @return {Number}
@@ -549,8 +546,11 @@ function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length
549
546
  * @param {Boolean} [linear]
550
547
  * @return {Color}
551
548
  * @memberof Random */
552
- function randColor(cA = new Color, cB = new Color(0,0,0,1), linear)
553
- { return 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)); }
549
+ function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear)
550
+ {
551
+ return linear ? colorA.lerp(colorB, rand()) :
552
+ new Color(rand(colorA.r,colorB.r), rand(colorA.g,colorB.g), rand(colorA.b,colorB.b), rand(colorA.a,colorB.a));
553
+ }
554
554
 
555
555
  /** Seed used by the randSeeded function
556
556
  * @type {Number}
@@ -568,13 +568,13 @@ function setRandSeed(seed) { randSeed = seed; }
568
568
  * @param {Number} [valueB=0]
569
569
  * @return {Number}
570
570
  * @memberof Random */
571
- function randSeeded(a=1, b=0)
571
+ function randSeeded(valueA=1, valueB=0)
572
572
  {
573
573
  // xorshift algorithm
574
574
  randSeed ^= randSeed << 13;
575
575
  randSeed ^= randSeed >>> 17;
576
576
  randSeed ^= randSeed << 5;
577
- return b + (a-b) * abs(randSeed % 1e9) / 1e9;
577
+ return valueB + (valueA-valueB) * abs(randSeed % 1e9) / 1e9;
578
578
  }
579
579
 
580
580
  ///////////////////////////////////////////////////////////////////////////////
@@ -596,7 +596,7 @@ function vec2(x=0, y)
596
596
 
597
597
  /**
598
598
  * Check if object is a valid Vector2
599
- * @param {Vector2} vector
599
+ * @param {Vector2} v
600
600
  * @return {Boolean}
601
601
  * @memberof Utilities
602
602
  */
@@ -629,27 +629,27 @@ class Vector2
629
629
  copy() { return new Vector2(this.x, this.y); }
630
630
 
631
631
  /** Returns a copy of this vector plus the vector passed in
632
- * @param {Vector2} vector
632
+ * @param {Vector2} v - other vector
633
633
  * @return {Vector2} */
634
634
  add(v) { ASSERT(isVector2(v)); return new Vector2(this.x + v.x, this.y + v.y); }
635
635
 
636
636
  /** Returns a copy of this vector minus the vector passed in
637
- * @param {Vector2} vector
637
+ * @param {Vector2} v - other vector
638
638
  * @return {Vector2} */
639
639
  subtract(v) { ASSERT(isVector2(v)); return new Vector2(this.x - v.x, this.y - v.y); }
640
640
 
641
641
  /** Returns a copy of this vector times the vector passed in
642
- * @param {Vector2} vector
642
+ * @param {Vector2} v - other vector
643
643
  * @return {Vector2} */
644
644
  multiply(v) { ASSERT(isVector2(v)); return new Vector2(this.x * v.x, this.y * v.y); }
645
645
 
646
646
  /** Returns a copy of this vector divided by the vector passed in
647
- * @param {Vector2} vector
647
+ * @param {Vector2} v - other vector
648
648
  * @return {Vector2} */
649
649
  divide(v) { ASSERT(isVector2(v)); return new Vector2(this.x / v.x, this.y / v.y); }
650
650
 
651
651
  /** Returns a copy of this vector scaled by the vector passed in
652
- * @param {Number} scale
652
+ * @param {Number} s - scale
653
653
  * @return {Vector2} */
654
654
  scale(s) { ASSERT(!isVector2(s)); return new Vector2(this.x * s, this.y * s); }
655
655
 
@@ -662,12 +662,12 @@ class Vector2
662
662
  lengthSquared() { return this.x**2 + this.y**2; }
663
663
 
664
664
  /** Returns the distance from this vector to vector passed in
665
- * @param {Vector2} vector
665
+ * @param {Vector2} v - other vector
666
666
  * @return {Number} */
667
667
  distance(v) { return this.distanceSquared(v)**.5; }
668
668
 
669
669
  /** Returns the distance squared from this vector to vector passed in
670
- * @param {Vector2} vector
670
+ * @param {Vector2} v - other vector
671
671
  * @return {Number} */
672
672
  distanceSquared(v) { return (this.x - v.x)**2 + (this.y - v.y)**2; }
673
673
 
@@ -682,12 +682,12 @@ class Vector2
682
682
  clampLength(length=1) { const l = this.length(); return l > length ? this.scale(length/l) : this; }
683
683
 
684
684
  /** Returns the dot product of this and the vector passed in
685
- * @param {Vector2} vector
685
+ * @param {Vector2} v - other vector
686
686
  * @return {Number} */
687
687
  dot(v) { ASSERT(isVector2(v)); return this.x*v.x + this.y*v.y; }
688
688
 
689
689
  /** Returns the cross product of this and the vector passed in
690
- * @param {Vector2} vector
690
+ * @param {Vector2} v - other vector
691
691
  * @return {Number} */
692
692
  cross(v) { ASSERT(isVector2(v)); return this.x*v.y - this.y*v.x; }
693
693
 
@@ -699,12 +699,17 @@ class Vector2
699
699
  * @param {Number} [angle=0]
700
700
  * @param {Number} [length=1]
701
701
  * @return {Vector2} */
702
- setAngle(a=0, length=1) { this.x = length*Math.sin(a); this.y = length*Math.cos(a); return this; }
702
+ setAngle(angle=0, length=1)
703
+ { this.x = length*Math.sin(angle); this.y = length*Math.cos(angle); return this; }
703
704
 
704
705
  /** Returns copy of this vector rotated by the angle passed in
705
706
  * @param {Number} angle
706
707
  * @return {Vector2} */
707
- 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); }
708
+ rotate(angle)
709
+ {
710
+ const c = Math.cos(angle), s = Math.sin(angle);
711
+ return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
712
+ }
708
713
 
709
714
  /** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
710
715
  * @return {Number} */
@@ -723,10 +728,11 @@ class Vector2
723
728
  area() { return abs(this.x * this.y); }
724
729
 
725
730
  /** Returns a new vector that is p percent between this and the vector passed in
726
- * @param {Vector2} vector
731
+ * @param {Vector2} v - other vector
727
732
  * @param {Number} percent
728
733
  * @return {Vector2} */
729
- lerp(v, p) { ASSERT(isVector2(v)); return this.add(v.subtract(this).scale(clamp(p))); }
734
+ lerp(v, percent)
735
+ { ASSERT(isVector2(v)); return this.add(v.subtract(this).scale(clamp(percent))); }
730
736
 
731
737
  /** Returns true if this vector is within the bounds of an array size passed in
732
738
  * @param {Vector2} arraySize
@@ -744,10 +750,10 @@ class Vector2
744
750
 
745
751
  /**
746
752
  * Create a color object with RGBA values
747
- * @param {Number} [r=1]
748
- * @param {Number} [g=1]
749
- * @param {Number} [b=1]
750
- * @param {Number} [a=1]
753
+ * @param {Number} [r=1] - red
754
+ * @param {Number} [g=1] - green
755
+ * @param {Number} [b=1] - blue
756
+ * @param {Number} [a=1] - alpha
751
757
  * @return {Color}
752
758
  * @memberof Utilities
753
759
  */
@@ -755,10 +761,10 @@ function rgb(r, g, b, a) { return new Color(r, g, b, a); }
755
761
 
756
762
  /**
757
763
  * Create a color object with HSLA values
758
- * @param {Number} [h=0]
759
- * @param {Number} [s=0]
760
- * @param {Number} [l=1]
761
- * @param {Number} [a=1]
764
+ * @param {Number} [h=0] - hue
765
+ * @param {Number} [s=0] - saturation
766
+ * @param {Number} [l=1] - lightness
767
+ * @param {Number} [a=1] - alpha
762
768
  * @return {Color}
763
769
  * @memberof Utilities
764
770
  */
@@ -775,11 +781,11 @@ function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
775
781
  */
776
782
  class Color
777
783
  {
778
- /** Create a color with the components passed in, white by default
779
- * @param {Number} [red=1]
780
- * @param {Number} [green=1]
781
- * @param {Number} [blue=1]
782
- * @param {Number} [alpha=1] */
784
+ /** Create a color with the rgba components passed in, white by default
785
+ * @param {Number} [r=1] - red
786
+ * @param {Number} [g=1] - green
787
+ * @param {Number} [b=1] - blue
788
+ * @param {Number} [a=1] - alpha*/
783
789
  constructor(r=1, g=1, b=1, a=1)
784
790
  {
785
791
  /** @property {Number} - Red */
@@ -797,22 +803,22 @@ class Color
797
803
  copy() { return new Color(this.r, this.g, this.b, this.a); }
798
804
 
799
805
  /** Returns a copy of this color plus the color passed in
800
- * @param {Color} color
806
+ * @param {Color} c - other color
801
807
  * @return {Color} */
802
808
  add(c) { return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a); }
803
809
 
804
810
  /** Returns a copy of this color minus the color passed in
805
- * @param {Color} color
811
+ * @param {Color} c - other color
806
812
  * @return {Color} */
807
813
  subtract(c) { return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a); }
808
814
 
809
815
  /** Returns a copy of this color times the color passed in
810
- * @param {Color} color
816
+ * @param {Color} c - other color
811
817
  * @return {Color} */
812
818
  multiply(c) { return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a); }
813
819
 
814
820
  /** Returns a copy of this color divided by the color passed in
815
- * @param {Color} color
821
+ * @param {Color} c - other color
816
822
  * @return {Color} */
817
823
  divide(c) { return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a); }
818
824
 
@@ -820,23 +826,24 @@ class Color
820
826
  * @param {Number} scale
821
827
  * @param {Number} [alphaScale=scale]
822
828
  * @return {Color} */
823
- scale(s, a=s) { return new Color(this.r*s, this.g*s, this.b*s, this.a*a); }
829
+ scale(scale, alphaScale=scale)
830
+ { return new Color(this.r*scale, this.g*scale, this.b*scale, this.a*alphaScale); }
824
831
 
825
832
  /** Returns a copy of this color clamped to the valid range between 0 and 1
826
833
  * @return {Color} */
827
834
  clamp() { return new Color(clamp(this.r), clamp(this.g), clamp(this.b), clamp(this.a)); }
828
835
 
829
836
  /** Returns a new color that is p percent between this and the color passed in
830
- * @param {Color} color
837
+ * @param {Color} c - other color
831
838
  * @param {Number} percent
832
839
  * @return {Color} */
833
- lerp(c, p) { return this.add(c.subtract(this).scale(clamp(p))); }
840
+ lerp(c, percent) { return this.add(c.subtract(this).scale(clamp(percent))); }
834
841
 
835
842
  /** Sets this color given a hue, saturation, lightness, and alpha
836
- * @param {Number} [hue=0]
837
- * @param {Number} [saturation=0]
838
- * @param {Number} [lightness=1]
839
- * @param {Number} [alpha=1]
843
+ * @param {Number} [h=0] - hue
844
+ * @param {Number} [s=0] - saturation
845
+ * @param {Number} [l=1] - lightness
846
+ * @param {Number} [a=1] - alpha
840
847
  * @return {Color} */
841
848
  setHSLA(h=0, s=0, l=1, a=1)
842
849
  {
@@ -977,12 +984,12 @@ class Timer
977
984
 
978
985
  /** Returns this timer expressed as a string
979
986
  * @return {String} */
980
- toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); }}
987
+ toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
981
988
 
982
989
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
983
990
  * @return {Number} */
984
991
  valueOf() { return this.get(); }
985
- }
992
+ }
986
993
  /**
987
994
  * LittleJS Engine Settings
988
995
  * @namespace Settings
@@ -1231,7 +1238,7 @@ let medalDisplayIconSize = 50;
1231
1238
  * @type {Boolean}
1232
1239
  * @default 0
1233
1240
  * @memberof Settings */
1234
- let medalsPreventUnlock;
1241
+ let medalsPreventUnlock;
1235
1242
  /**
1236
1243
  * LittleJS Object System
1237
1244
  */
@@ -1312,7 +1319,7 @@ class EngineObject
1312
1319
  /** @property {Number} [renderOrder=0] - Objects are sorted by render order */
1313
1320
  this.renderOrder = renderOrder;
1314
1321
  /** @property {Vector2} [velocity=Vector2()] - Velocity of the object */
1315
- this.velocity = new Vector2();
1322
+ this.velocity = vec2();
1316
1323
  /** @property {Number} [angleVelocity=0] - Angular velocity of the object */
1317
1324
  this.angleVelocity = 0;
1318
1325
 
@@ -1372,15 +1379,17 @@ class EngineObject
1372
1379
  for (const o of engineObjectsCollide)
1373
1380
  {
1374
1381
  // non solid objects don't collide with eachother
1375
- if (!this.isSolid & !o.isSolid || o.destroyed || o.parent || o == this)
1382
+ if (!this.isSolid && !o.isSolid || o.destroyed || o.parent || o == this)
1376
1383
  continue;
1377
1384
 
1378
1385
  // check collision
1379
1386
  if (!isOverlapping(this.pos, this.size, o.pos, o.size))
1380
1387
  continue;
1381
1388
 
1382
- // pass collision to objects
1383
- if (!this.collideWithObject(o) | !o.collideWithObject(this))
1389
+ // notify objects of collision and check if should be resolved
1390
+ const collide1 = this.collideWithObject(o);
1391
+ const collide2 = o.collideWithObject(this);
1392
+ if (!collide1 || !collide2)
1384
1393
  continue;
1385
1394
 
1386
1395
  if (isOverlapping(oldPos, this.size, o.pos, o.size))
@@ -1405,7 +1414,7 @@ class EngineObject
1405
1414
  const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
1406
1415
  const elasticity = max(this.elasticity, o.elasticity);
1407
1416
 
1408
- if (smallStepUp | isBlockedY | !isBlockedX) // resolve y collision
1417
+ if (smallStepUp || isBlockedY || !isBlockedX) // resolve y collision
1409
1418
  {
1410
1419
  // push outside object collision
1411
1420
  this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
@@ -1434,7 +1443,7 @@ class EngineObject
1434
1443
  o.velocity.y = lerp(elasticity, inelastic, elastic1);
1435
1444
  }
1436
1445
  }
1437
- if (!smallStepUp & isBlockedX) // resolve x collision
1446
+ if (!smallStepUp && isBlockedX) // resolve x collision
1438
1447
  {
1439
1448
  // push outside collision
1440
1449
  this.pos.x = o.pos.x + (sizeBoth.x/2 + epsilon) * sign(oldPos.x - o.pos.x);
@@ -1469,9 +1478,9 @@ class EngineObject
1469
1478
  if (!tileCollisionTest(oldPos, this.size, this))
1470
1479
  {
1471
1480
  // test which side we bounced off (or both if a corner)
1472
- const isBlockedY = tileCollisionTest(new Vector2(oldPos.x, this.pos.y), this.size, this);
1473
- const isBlockedX = tileCollisionTest(new Vector2(this.pos.x, oldPos.y), this.size, this);
1474
- if (isBlockedY | !isBlockedX)
1481
+ const isBlockedY = tileCollisionTest(vec2(oldPos.x, this.pos.y), this.size, this);
1482
+ const isBlockedX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
1483
+ if (isBlockedY || !isBlockedX)
1475
1484
  {
1476
1485
  // set if landed on ground
1477
1486
  this.groundObject = wasMovingDown;
@@ -1534,7 +1543,7 @@ class EngineObject
1534
1543
  * @param {EngineObject} object - the object to test against
1535
1544
  * @return {Boolean} - true if the collision should be resolved
1536
1545
  */
1537
- collideWithObject(o) { return 1; }
1546
+ collideWithObject(object) { return 1; }
1538
1547
 
1539
1548
  /** How long since the object was created
1540
1549
  * @return {Number} */
@@ -1542,7 +1551,7 @@ class EngineObject
1542
1551
 
1543
1552
  /** Apply acceleration to this object (adjust velocity, not affected by mass)
1544
1553
  * @param {Vector2} acceleration */
1545
- applyAcceleration(a) { if (this.mass) this.velocity = this.velocity.add(a); }
1554
+ applyAcceleration(acceleration) { if (this.mass) this.velocity = this.velocity.add(acceleration); }
1546
1555
 
1547
1556
  /** Apply force to this object (adjust velocity, affected by mass)
1548
1557
  * @param {Vector2} force */
@@ -1607,7 +1616,7 @@ class EngineObject
1607
1616
  return text;
1608
1617
  }
1609
1618
  }
1610
- }
1619
+ }
1611
1620
  /**
1612
1621
  * LittleJS Drawing System
1613
1622
  * - Hybrid with both Canvas2D and WebGL available
@@ -1673,7 +1682,11 @@ let tileImageSize, tileImageFixBleed, drawCount;
1673
1682
  function screenToWorld(screenPos)
1674
1683
  {
1675
1684
  ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1676
- return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
1685
+ return screenPos
1686
+ .add(vec2(.5))
1687
+ .subtract(mainCanvasSize.scale(.5))
1688
+ .multiply(vec2(1/cameraScale,-1/cameraScale))
1689
+ .add(cameraPos);
1677
1690
  }
1678
1691
 
1679
1692
  /** Convert from world to screen space coordinates
@@ -1684,7 +1697,11 @@ function screenToWorld(screenPos)
1684
1697
  function worldToScreen(worldPos)
1685
1698
  {
1686
1699
  ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1687
- return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
1700
+ return worldPos
1701
+ .subtract(cameraPos)
1702
+ .multiply(vec2(cameraScale,-cameraScale))
1703
+ .add(mainCanvasSize.scale(.5))
1704
+ .subtract(vec2(.5));
1688
1705
  }
1689
1706
 
1690
1707
  /** Draw textured tile centered in world space, with color applied if using WebGL
@@ -1698,8 +1715,8 @@ function worldToScreen(worldPos)
1698
1715
  * @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
1699
1716
  * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
1700
1717
  * @memberof Draw */
1701
- function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color, angle=0, mirror,
1702
- additiveColor=new Color(0,0,0,0), useWebGL=glEnable)
1718
+ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color,
1719
+ angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable)
1703
1720
  {
1704
1721
  showWatermark && ++drawCount;
1705
1722
  if (glEnable && useWebGL)
@@ -1992,7 +2009,7 @@ function toggleFullscreen()
1992
2009
  else if (document.body.requestFullscreen)
1993
2010
  document.body.requestFullscreen();
1994
2011
  }
1995
-
2012
+
1996
2013
  /**
1997
2014
  * LittleJS Input System
1998
2015
  * - Tracks key down, pressed, and released
@@ -2426,7 +2443,7 @@ function touchGamepadRender()
2426
2443
  const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
2427
2444
  for (let i=4; i--;)
2428
2445
  {
2429
- const pos = rightCenter.add((new Vector2).setAngle(i*PI/2, touchGamepadSize/2));
2446
+ const pos = rightCenter.add(vec2().setAngle(i*PI/2, touchGamepadSize/2));
2430
2447
  overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
2431
2448
  overlayContext.beginPath();
2432
2449
  overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
@@ -2436,7 +2453,7 @@ function touchGamepadRender()
2436
2453
 
2437
2454
  // set canvas back to normal
2438
2455
  overlayContext.restore();
2439
- }
2456
+ }
2440
2457
  /**
2441
2458
  * LittleJS Audio System
2442
2459
  * - <a href=https://killedbyapixel.github.io/ZzFX/>ZzFX Sound Effects</a> - Sound Effect Generator
@@ -2877,7 +2894,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2877
2894
  patternChannel = patterns[patternIndex][channelIndex] || [0, 0, 0];
2878
2895
 
2879
2896
  // check if there are more channels
2880
- hasMore |= !!patterns[patternIndex][channelIndex];
2897
+ hasMore ||= !!patterns[patternIndex][channelIndex];
2881
2898
 
2882
2899
  // get next offset, use the length of first channel
2883
2900
  nextSampleOffset = outSampleOffset + (patterns[patternIndex][0].length - 2 - !notFirstBeat) * beatLength;
@@ -2890,7 +2907,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2890
2907
 
2891
2908
  // stop if end, different instrument or new note
2892
2909
  stop = i == patternChannel.length + isSequenceEnd - 1 && isSequenceEnd ||
2893
- instrument != (patternChannel[0] || 0) | note | 0;
2910
+ instrument != (patternChannel[0] || 0) || note;
2894
2911
 
2895
2912
  // fill buffer with samples for previous beat, most cpu intensive part
2896
2913
  for (j = 0; j < beatLength && notFirstBeat;
@@ -2934,7 +2951,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2934
2951
  }
2935
2952
 
2936
2953
  return [leftChannelBuffer, rightChannelBuffer];
2937
- }
2954
+ }
2938
2955
  /**
2939
2956
  * LittleJS Tile Layer System
2940
2957
  * - Caches arrays of tiles to off screen canvas for fast rendering
@@ -3004,12 +3021,12 @@ function tileCollisionTest(pos, size=vec2(), object)
3004
3021
  for (let x = minX; x < maxX; ++x)
3005
3022
  {
3006
3023
  const tileData = tileCollision[y*tileCollisionSize.x+x];
3007
- if (tileData && (!object || object.collideWithTile(tileData, new Vector2(x, y))))
3024
+ if (tileData && (!object || object.collideWithTile(tileData, vec2(x, y))))
3008
3025
  return 1;
3009
3026
  }
3010
3027
  }
3011
3028
 
3012
- /** Return the center of tile if any that is hit (this does not return the exact hit point)
3029
+ /** Return the center of tile if any that is hit (does not return the exact intersection)
3013
3030
  * @param {Vector2} posStart
3014
3031
  * @param {Vector2} posEnd
3015
3032
  * @param {EngineObject} [object]
@@ -3018,28 +3035,41 @@ function tileCollisionTest(pos, size=vec2(), object)
3018
3035
  function tileCollisionRaycast(posStart, posEnd, object)
3019
3036
  {
3020
3037
  // test if a ray collides with tiles from start to end
3021
- // todo: a way to get the exact hit point, it must still register as inside the hit tile
3022
- const posDelta = (posEnd = posEnd.floor()).subtract(posStart = posStart.floor());
3023
- const dx = abs(posDelta.x), dy = -abs(posDelta.y);
3024
- const sx = sign(posDelta.x), sy = sign(posDelta.y);
3025
-
3026
- for (let x = posStart.x, y = posStart.y, e = dx + dy;;)
3038
+ // todo: a way to get the exact hit point, it must still be inside the hit tile
3039
+ const delta = posEnd.subtract(posStart);
3040
+ const totalLength = delta.length();
3041
+ const normalizedDelta = delta.normalize();
3042
+ const unit = vec2(abs(1/normalizedDelta.x), abs(1/normalizedDelta.y));
3043
+ const flooredPosStart = posStart.floor();
3044
+
3045
+ // setup iteration variables
3046
+ let pos = flooredPosStart;
3047
+ let xi = unit.x * (delta.x < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1);
3048
+ let yi = unit.y * (delta.y < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1);
3049
+
3050
+ while (1)
3027
3051
  {
3028
- const tileData = getTileCollisionData(vec2(x,y));
3029
- if (tileData && (object ? object.collideWithTileRaycast(tileData, new Vector2(x, y)) : tileData > 0))
3052
+ // check for tile collision
3053
+ const tileData = getTileCollisionData(pos);
3054
+ if (tileData && (!object || object.collideWithTile(tileData, pos)))
3030
3055
  {
3031
- debugRaycast && debugLine(posStart, posEnd, '#f00',.02, 1);
3032
- debugRaycast && debugPoint(new Vector2(x+.5, y+.5), '#ff0', 1);
3033
- return new Vector2(x+.5, y+.5);
3056
+ debugRaycast && debugLine(posStart, posEnd, '#f00', .02);
3057
+ debugRaycast && debugPoint(pos.add(vec2(.5)), '#ff0');
3058
+ return pos.add(vec2(.5));
3034
3059
  }
3035
3060
 
3036
- // update Bresenham line drawing algorithm
3037
- if (x == posEnd.x & y == posEnd.y) break;
3038
- const e2 = 2*e;
3039
- if (e2 >= dy) e += dy, x += sx;
3040
- if (e2 <= dx) e += dx, y += sy;
3061
+ // check if past the end
3062
+ if (xi > totalLength && yi > totalLength)
3063
+ break;
3064
+
3065
+ // get coordinates of the next tile to check
3066
+ if (xi > yi)
3067
+ pos.y += sign(delta.y), yi += unit.y;
3068
+ else
3069
+ pos.x += sign(delta.x), xi += unit.x;
3041
3070
  }
3042
- debugRaycast && debugLine(posStart, posEnd, '#00f',.02, 1);
3071
+
3072
+ debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
3043
3073
  }
3044
3074
 
3045
3075
  ///////////////////////////////////////////////////////////////////////////////
@@ -3282,7 +3312,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
3282
3312
  * @param {Number} [angle=0] */
3283
3313
  drawRect(pos, size, color, angle)
3284
3314
  { this.drawTile(pos, size, -1, 0, color, angle); }
3285
- }
3315
+ }
3286
3316
  /**
3287
3317
  * LittleJS Particle System
3288
3318
  */
@@ -3370,7 +3400,7 @@ class ParticleEmitter extends EngineObject
3370
3400
  localSpace
3371
3401
  )
3372
3402
  {
3373
- super(pos, new Vector2, tileIndex, tileSize, angle, undefined, renderOrder);
3403
+ super(pos, vec2(), tileIndex, tileSize, angle, undefined, renderOrder);
3374
3404
 
3375
3405
  // emitter settings
3376
3406
  /** @property {Number} - World space size of the emitter (float for circle diameter, vec2 for rect) */
@@ -3437,7 +3467,7 @@ class ParticleEmitter extends EngineObject
3437
3467
  this.parent && super.update();
3438
3468
 
3439
3469
  // update emitter
3440
- if (!this.emitTime | this.getAliveTime() <= this.emitTime)
3470
+ if (!this.emitTime || this.getAliveTime() <= this.emitTime)
3441
3471
  {
3442
3472
  // emit particles
3443
3473
  if (this.emitRate * particleEmitRateScale)
@@ -3459,7 +3489,7 @@ class ParticleEmitter extends EngineObject
3459
3489
  {
3460
3490
  // spawn a particle
3461
3491
  let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
3462
- (new Vector2(rand(-.5,.5), rand(-.5,.5)))
3492
+ vec2(rand(-.5,.5), rand(-.5,.5))
3463
3493
  .multiply(this.emitSize).rotate(this.angle) // box emitter
3464
3494
  : randInCircle(this.emitSize/2); // circle emitter
3465
3495
  let angle = rand(this.particleConeAngle, -this.particleConeAngle);
@@ -3489,7 +3519,7 @@ class ParticleEmitter extends EngineObject
3489
3519
  // build particle settings
3490
3520
  particle.colorStart = colorStart;
3491
3521
  particle.colorEndDelta = colorEnd.subtract(colorStart);
3492
- particle.velocity = (new Vector2).setAngle(velocityAngle, speed);
3522
+ particle.velocity = vec2().setAngle(velocityAngle, speed);
3493
3523
  particle.angleVelocity = angleSpeed;
3494
3524
  particle.lifeTime = particleTime;
3495
3525
  particle.sizeStart = sizeStart;
@@ -3534,7 +3564,7 @@ class Particle extends EngineObject
3534
3564
  * @param {Number} [angle=0] - Angle to rotate the particle
3535
3565
  */
3536
3566
  constructor(pos, tileIndex, tileSize, angle)
3537
- { super(pos, new Vector2, tileIndex, tileSize, angle); }
3567
+ { super(pos, vec2(), tileIndex, tileSize, angle); }
3538
3568
 
3539
3569
  /** Render the particle, automatically called each frame, sorted by renderOrder */
3540
3570
  render()
@@ -3542,7 +3572,7 @@ class Particle extends EngineObject
3542
3572
  // modulate size and color
3543
3573
  const p = min((time - this.spawnTime) / this.lifeTime, 1);
3544
3574
  const radius = this.sizeStart + p * this.sizeEndDelta;
3545
- const size = new Vector2(radius, radius);
3575
+ const size = vec2(radius);
3546
3576
  const fadeRate = this.fadeRate/2;
3547
3577
  const color = new Color(
3548
3578
  this.colorStart.r + p * this.colorEndDelta.r,
@@ -3588,7 +3618,7 @@ class Particle extends EngineObject
3588
3618
  this.destroyed = 1;
3589
3619
  }
3590
3620
  }
3591
- }
3621
+ }
3592
3622
  /**
3593
3623
  * LittleJS Medal System
3594
3624
  * - Tracks and displays medals
@@ -3909,7 +3939,7 @@ class Newgrounds
3909
3939
  // end of Crypto-JS
3910
3940
  ///////////////////////////////////////////////////////////////////////////////
3911
3941
  }
3912
- }
3942
+ }
3913
3943
  /**
3914
3944
  * LittleJS WebGL Interface
3915
3945
  * - All webgl used by the engine is wrapped up here
@@ -4303,7 +4333,7 @@ gl_VERTICES_PER_QUAD = 6,
4303
4333
  gl_INDICIES_PER_VERT = 6,
4304
4334
  gl_MAX_BATCH = 1<<16,
4305
4335
  gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2, // vec2 * 2 + (char * 4) * 2
4306
- gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH * gl_VERTICES_PER_QUAD * gl_VERTEX_BYTE_STRIDE;
4336
+ gl_VERTEX_BUFFER_SIZE = gl_MAX_BATCH * gl_VERTICES_PER_QUAD * gl_VERTEX_BYTE_STRIDE;
4307
4337
  /**
4308
4338
  * LittleJS - The Tiny JavaScript Game Engine That Can!
4309
4339
  * MIT License - Copyright 2021 Frank Force
@@ -4336,7 +4366,7 @@ const engineName = 'LittleJS';
4336
4366
  * @type {String}
4337
4367
  * @default
4338
4368
  * @memberof Engine */
4339
- const engineVersion = '1.6.6';
4369
+ const engineVersion = '1.6.92';
4340
4370
 
4341
4371
  /** Frames per second to update objects
4342
4372
  * @type {Number}
@@ -4426,7 +4456,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4426
4456
  // set canvas style
4427
4457
  const styleCanvas = 'position:absolute;' +
4428
4458
  'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
4429
- (canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
4459
+ (canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
4430
4460
  (glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
4431
4461
 
4432
4462
  gameInit();
@@ -4434,7 +4464,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4434
4464
  };
4435
4465
 
4436
4466
  // frame time tracking
4437
- let frameTimeLastMS = 0, frameTimeBufferMS, averageFPS;
4467
+ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS;
4438
4468
 
4439
4469
  // main update loop
4440
4470
  function engineUpdate(frameTimeMS=0)
@@ -4625,8 +4655,8 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
4625
4655
  for (const o of objects)
4626
4656
  pos.distanceSquared(o.pos) < sizeSquared && callbackFunction(o);
4627
4657
  }
4628
- }
4629
-
4658
+ }
4659
+
4630
4660
  /**
4631
4661
  * LittleJS Module Export
4632
4662
  * - Export engine as a module with extra functions where necessary
@@ -4810,18 +4840,13 @@ function setMedalDisplayIconSize(size) { medalDisplayIconSize = size; }
4810
4840
  /** Set to stop medals from being unlockable
4811
4841
  * @param {Boolean} preventUnlock
4812
4842
  * @memberof Settings */
4813
- function setMedalsPreventUnlock(prevent) { medalsPreventUnlock = prevent; }
4843
+ function setMedalsPreventUnlock(preventUnlock) { medalsPreventUnlock = preventUnlock; }
4814
4844
 
4815
4845
  /** Set if watermark with FPS should be shown
4816
4846
  * @param {Boolean} show
4817
4847
  * @memberof Debug */
4818
4848
  function setShowWatermark(show) { showWatermark = show; }
4819
4849
 
4820
- /** Set if god mode is enabled
4821
- * @param {Boolean} enable
4822
- * @memberof Debug */
4823
- function setGodMode(enable) { godMode = enable; }
4824
-
4825
4850
  /** Set key code used to toggle debug mode, Esc by default
4826
4851
  * @param {Number} key
4827
4852
  * @memberof Debug */
@@ -4866,7 +4891,6 @@ export {
4866
4891
  setMedalDisplayIconSize,
4867
4892
  setMedalsPreventUnlock,
4868
4893
  setShowWatermark,
4869
- setGodMode,
4870
4894
  setDebugKey,
4871
4895
 
4872
4896
  // Settings
@@ -4909,7 +4933,6 @@ export {
4909
4933
  // Globals
4910
4934
  debug,
4911
4935
  showWatermark,
4912
- godMode,
4913
4936
 
4914
4937
  // Debug
4915
4938
  ASSERT,
@@ -5065,4 +5088,4 @@ export {
5065
5088
  engineObjectsUpdate,
5066
5089
  engineObjectsDestroy,
5067
5090
  engineObjectsCallback,
5068
- };
5091
+ };