littlejsengine 1.2.3 → 1.3.3

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 (94) hide show
  1. package/README.md +4 -3
  2. package/build.bat +6 -6
  3. package/buildSetup.bat +7 -0
  4. package/docs/Audio.html +2268 -0
  5. package/docs/Color.html +3376 -0
  6. package/docs/Debug.html +2933 -0
  7. package/docs/Draw.html +4480 -0
  8. package/docs/EngineObject.html +4734 -0
  9. package/docs/FontImage.html +1055 -0
  10. package/docs/Input.html +2806 -0
  11. package/docs/Medal.html +1007 -0
  12. package/docs/Medals.html +628 -0
  13. package/docs/Music.html +584 -0
  14. package/docs/Newgrounds.html +1399 -0
  15. package/docs/Particle.html +4825 -0
  16. package/docs/ParticleEmitter.html +8099 -0
  17. package/docs/Random.html +1774 -0
  18. package/docs/Settings.html +3140 -0
  19. package/docs/Sound.html +1249 -0
  20. package/docs/TileCollision.html +1409 -0
  21. package/docs/TileLayer.html +7310 -0
  22. package/docs/TileLayerData.html +1052 -0
  23. package/docs/Timer.html +1295 -0
  24. package/docs/Utilities.html +3278 -0
  25. package/docs/Vector2.html +4266 -0
  26. package/docs/WebGL.html +2307 -0
  27. package/docs/engine.js.html +443 -0
  28. package/docs/engineAudio.js.html +627 -0
  29. package/docs/engineDebug.js.html +554 -0
  30. package/docs/engineDraw.js.html +539 -0
  31. package/docs/engineInput.js.html +571 -0
  32. package/docs/engineMedals.js.html +460 -0
  33. package/docs/engineObject.js.html +533 -0
  34. package/docs/engineParticles.js.html +443 -0
  35. package/docs/engineSettings.js.html +381 -0
  36. package/docs/engineTileLayer.js.html +503 -0
  37. package/docs/engineUtilities.js.html +700 -0
  38. package/docs/engineWebGL.js.html +511 -0
  39. package/docs/fonts/MavenPro-Regular.ttf +0 -0
  40. package/docs/fonts/Montserrat-Regular.ttf +0 -0
  41. package/docs/fonts/Muli-Black.ttf +0 -0
  42. package/docs/fonts/OFL-hind.txt +93 -0
  43. package/docs/fonts/OFL-montserrat.txt +93 -0
  44. package/docs/global.html +1771 -0
  45. package/docs/index.css +6 -0
  46. package/docs/index.html +267 -0
  47. package/docs/scripts/fix-code-block.js +53 -0
  48. package/docs/scripts/fix-navbar.js +25 -0
  49. package/docs/scripts/linenumber.js +25 -0
  50. package/docs/scripts/misc.js +217 -0
  51. package/docs/scripts/resize.js +85 -0
  52. package/docs/scripts/search.js +83 -0
  53. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  54. package/docs/scripts/third-party/fuse.js +9 -0
  55. package/docs/scripts/third-party/lang-css.js +2 -0
  56. package/docs/scripts/third-party/prettify.js +28 -0
  57. package/docs/static/favicon.png +0 -0
  58. package/docs/static/index.css +4 -0
  59. package/docs/styles/clean-jsdoc-theme-base.css +393 -0
  60. package/docs/styles/clean-jsdoc-theme-dark.css +324 -0
  61. package/docs/styles/clean-jsdoc-theme-light.css +319 -0
  62. package/docs/styles/reset.css +346 -0
  63. package/docs/styles/third-party/ionicons.min.css +11 -0
  64. package/docs/styles/third-party/prettify-jsdoc.css +111 -0
  65. package/docs/styles/third-party/prettify-tomorrow.css +5 -0
  66. package/engine/engine.all.js +171 -67
  67. package/engine/engine.all.min.js +1 -1
  68. package/engine/engine.all.release.js +162 -53
  69. package/engine/engine.js +3 -3
  70. package/engine/engineAudio.js +5 -7
  71. package/engine/engineBuild.bat +3 -4
  72. package/engine/engineDebug.js +9 -14
  73. package/engine/engineDraw.js +32 -13
  74. package/engine/engineInput.js +5 -1
  75. package/engine/engineMedals.js +5 -2
  76. package/engine/engineObject.js +24 -5
  77. package/engine/engineParticles.js +2 -2
  78. package/engine/engineSettings.js +5 -0
  79. package/engine/engineTileLayer.js +11 -10
  80. package/engine/engineUtilities.js +67 -7
  81. package/engine/engineWebGL.js +3 -3
  82. package/engine/index.d.ts +57 -18
  83. package/examples/breakout/index.html +3 -3
  84. package/examples/particles/index.html +366 -0
  85. package/examples/particles/tiles.png +0 -0
  86. package/examples/platformer/gameEffects.js +6 -6
  87. package/examples/platformer/index.html +6 -6
  88. package/examples/puzzle/game.js +4 -2
  89. package/examples/puzzle/index.html +2 -2
  90. package/examples/stress/index.html +1 -1
  91. package/game.js +3 -14
  92. package/index.html +13 -13
  93. package/package.json +1 -1
  94. package/engine/engineBuildSetup.bat +0 -7
@@ -333,7 +333,7 @@ class Vector2
333
333
 
334
334
  /** Returns the area this vector covers as a rectangle
335
335
  * @return {Number} */
336
- area() { return this.x * this.y; }
336
+ area() { return abs(this.x * this.y); }
337
337
 
338
338
  /** Returns a new vector that is p percent between this and the vector passed in
339
339
  * @param {Vector2} vector
@@ -344,7 +344,13 @@ class Vector2
344
344
  /** Returns true if this vector is within the bounds of an array size passed in
345
345
  * @param {Vector2} arraySize
346
346
  * @return {Boolean} */
347
- arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
347
+ arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
348
+
349
+ /** Returns this vector expressed as a string
350
+ * @param {float} digits - precision to display
351
+ * @return {String} */
352
+ toString(digits=3)
353
+ { return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`; }
348
354
  }
349
355
 
350
356
  ///////////////////////////////////////////////////////////////////////////////
@@ -415,7 +421,7 @@ class Color
415
421
  * @return {Color} */
416
422
  lerp(c, p) { return this.add(c.subtract(this).scale(clamp(p))); }
417
423
 
418
- /** Sets this color given a hue, saturation, lightness , and alpha
424
+ /** Sets this color given a hue, saturation, lightness, and alpha
419
425
  * @param {Number} [hue=0]
420
426
  * @param {Number} [saturation=0]
421
427
  * @param {Number} [lightness=1]
@@ -451,21 +457,71 @@ class Color
451
457
  ).clamp();
452
458
  }
453
459
 
454
- /** Returns this color expressed as an rgba string
460
+ /** Returns this color expressed as an CSS color value
455
461
  * @return {String} */
456
- rgba()
462
+ toString()
457
463
  {
458
464
  ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
459
465
  return `rgb(${this.r*255|0},${this.g*255|0},${this.b*255|0},${this.a})`;
460
466
  }
461
467
 
462
- /** Returns this color expressed as 32 bit integer value
468
+ /** Returns this color expressed as 32 bit integer RGBA value
463
469
  * @return {Number} */
464
470
  rgbaInt()
465
471
  {
466
472
  ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
467
473
  return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
468
474
  }
475
+
476
+ /** Returns this color expressed as a hex code
477
+ * @return {String} */
478
+ hex()
479
+ {
480
+ const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
481
+ return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
482
+ }
483
+
484
+ /** Returns this color expressed in hsla format
485
+ * @return {Array} */
486
+ getHSLA()
487
+ {
488
+ const r = this.r;
489
+ const g = this.g;
490
+ const b = this.b;
491
+ const a = this.a;
492
+ const max = Math.max(r, g, b);
493
+ const min = Math.min(r, g, b);
494
+ const l = (max + min) / 2;
495
+
496
+ let h = 0, s = 0;
497
+ if (max != min)
498
+ {
499
+ let d = max - min;
500
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
501
+ if (r == max)
502
+ h = (g - b) / d + (g < b ? 6 : 0);
503
+ else if (g == max)
504
+ h = (b - r) / d + 2;
505
+ else if (b == max)
506
+ h = (r - g) / d + 4;
507
+ }
508
+
509
+ return [h / 6, s, l, a];
510
+ }
511
+
512
+ /** Set this color from a hex code
513
+ * @param {String} hex - html hex code
514
+ * @return {Color} */
515
+ setHex(hex)
516
+ {
517
+ const fromHex = (a)=> parseInt(hex.slice(a,a+2), 16)/255;
518
+ this.r = fromHex(1);
519
+ this.g = fromHex(3),
520
+ this.b = fromHex(5);
521
+ this.a = 1;
522
+ ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
523
+ return this;
524
+ }
469
525
  }
470
526
 
471
527
  ///////////////////////////////////////////////////////////////////////////////
@@ -502,7 +558,7 @@ class Timer
502
558
 
503
559
  /** Returns true if set and elapsed
504
560
  * @return {Boolean} */
505
- elapsed() { return time > this.time; }
561
+ elapsed() { return time > this.time; }
506
562
 
507
563
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
508
564
  * @return {Number} */
@@ -511,6 +567,10 @@ class Timer
511
567
  /** Get percentage elapsed based on time it was set to, returns 0 if not set
512
568
  * @return {Number} */
513
569
  getPercent() { return this.isSet()? percent(this.time - time, this.setTime, 0) : 0; }
570
+
571
+ /** Returns this timer expressed as a string
572
+ * @return {String} */
573
+ toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
514
574
  }
515
575
  /**
516
576
  * LittleJS Engine Settings
@@ -567,6 +627,11 @@ let tileFixBleedScale = .3;
567
627
  * @memberof Settings */
568
628
  let objectDefaultSize = vec2(1);
569
629
 
630
+ /** Enable physics solver for collisions between objects
631
+ * @default
632
+ * @memberof Settings */
633
+ let enablePhysicsSolver = 1;
634
+
570
635
  /** Default object mass for collison calcuations (how heavy objects are)
571
636
  * @default
572
637
  * @memberof Settings */
@@ -753,7 +818,7 @@ let medalDisplayIconSize = 50;
753
818
  const engineName = 'LittleJS';
754
819
 
755
820
  /** Version of engine */
756
- const engineVersion = '1.2.3';
821
+ const engineVersion = '1.3.3';
757
822
 
758
823
  /** Frames per second to update objects
759
824
  * @default */
@@ -834,8 +899,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
834
899
  // main update loop
835
900
  const engineUpdate = (frameTimeMS=0)=>
836
901
  {
837
- requestAnimationFrame(engineUpdate);
838
-
839
902
  // update time keeping
840
903
  let frameTimeDeltaMS = frameTimeMS - frameTimeLastMS;
841
904
  frameTimeLastMS = frameTimeMS;
@@ -934,6 +997,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
934
997
  overlayContext.fillText(text, mainCanvas.width-2, 2);
935
998
  drawCount = 0;
936
999
  }
1000
+
1001
+ requestAnimationFrame(engineUpdate);
937
1002
  }
938
1003
 
939
1004
  // set tile image source to load the image and start the engine
@@ -1049,9 +1114,9 @@ class EngineObject
1049
1114
  /** Create an engine object and adds it to the list of objects
1050
1115
  * @param {Vector2} [position=new Vector2()] - World space position of the object
1051
1116
  * @param {Vector2} [size=objectDefaultSize] - World space size of the object
1052
- * @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
1117
+ * @param {Number} [tileIndex=-1] - Tile to use to render object (-1 is untextured)
1053
1118
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
1054
- * @param {Number} [angle=0] - Angle to rotate the object
1119
+ * @param {Number} [angle=0] - Angle the object is rotated by
1055
1120
  * @param {Color} [color] - Color to apply to tile when rendered
1056
1121
  * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
1057
1122
  */
@@ -1066,7 +1131,7 @@ class EngineObject
1066
1131
  this.size = size;
1067
1132
  /** @property {Vector2} - Size of object used for drawing, uses size if not set */
1068
1133
  this.drawSize;
1069
- /** @property {Number} - Tile to use to render object, untextured if -1 */
1134
+ /** @property {Number} - Tile to use to render object (-1 is untextured) */
1070
1135
  this.tileIndex = tileIndex;
1071
1136
  /** @property {Vector2} - Size of tile in source pixels */
1072
1137
  this.tileSize = tileSize;
@@ -1078,7 +1143,7 @@ class EngineObject
1078
1143
  this.additiveColor;
1079
1144
 
1080
1145
  // set object defaults
1081
- /** @property {Number} [mass=objectDefaultMass] - How heavy the object is */
1146
+ /** @property {Number} [mass=objectDefaultMass] - How heavy the object is, static if 0 */
1082
1147
  this.mass = objectDefaultMass;
1083
1148
  /** @property {Number} [damping=objectDefaultDamping] - How much to slow down velocity each frame (0-1) */
1084
1149
  this.damping = objectDefaultDamping;
@@ -1132,7 +1197,7 @@ class EngineObject
1132
1197
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
1133
1198
  ASSERT(this.damping >= 0 && this.damping <= 1);
1134
1199
 
1135
- if (!this.mass) // do not update collision for fixed objects
1200
+ if (!enablePhysicsSolver || !this.mass) // do not update collision for fixed objects
1136
1201
  return;
1137
1202
 
1138
1203
  const wasMovingDown = this.velocity.y < 0;
@@ -1367,6 +1432,25 @@ class EngineObject
1367
1432
  this.isSolid = isSolid;
1368
1433
  this.collideTiles = collideTiles;
1369
1434
  }
1435
+
1436
+ toString()
1437
+ {
1438
+ if (debug)
1439
+ {
1440
+ let text = 'type = ' + this.constructor.name;
1441
+ if (this.pos.x || this.pos.y)
1442
+ text += '\npos = ' + this.pos;
1443
+ if (this.velocity.x || this.velocity.y)
1444
+ text += '\nvelocity = ' + this.velocity;
1445
+ if (this.size.x || this.size.y)
1446
+ text += '\nsize = ' + this.size;
1447
+ if (this.angle)
1448
+ text += '\nangle = ' + this.angle.toFixed(3);
1449
+ if (this.color)
1450
+ text += '\ncolor = ' + this.color;
1451
+ return text;
1452
+ }
1453
+ }
1370
1454
  }
1371
1455
  /**
1372
1456
  * LittleJS Drawing System
@@ -1480,7 +1564,7 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
1480
1564
  if (tileIndex < 0)
1481
1565
  {
1482
1566
  // if negative tile index, force untextured
1483
- context.fillStyle = color.rgba();
1567
+ context.fillStyle = color;
1484
1568
  context.fillRect(-.5, -.5, 1, 1);
1485
1569
  }
1486
1570
  else
@@ -1535,7 +1619,7 @@ function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angl
1535
1619
  * @memberof Draw */
1536
1620
  function drawRectScreenSpace(pos, size, color, angle, useWebGL)
1537
1621
  {
1538
- drawTileSrceenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1622
+ drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1539
1623
  }
1540
1624
 
1541
1625
  /** Draw colored line between two points
@@ -1585,7 +1669,8 @@ function setBlendMode(additive, useWebGL=glEnable)
1585
1669
  mainContext.globalCompositeOperation = additive ? 'lighter' : 'source-over';
1586
1670
  }
1587
1671
 
1588
- /** Draw text on overlay canvas in world space
1672
+ /** Draw text on overlay canvas in screen space
1673
+ * Automatically splits new lines into rows
1589
1674
  * @param {String} text
1590
1675
  * @param {Vector2} pos
1591
1676
  * @param {Number} [size=1]
@@ -1594,20 +1679,38 @@ function setBlendMode(additive, useWebGL=glEnable)
1594
1679
  * @param {Color} [lineColor=new Color(0,0,0)]
1595
1680
  * @param {String} [textAlign='center']
1596
1681
  * @memberof Draw */
1597
- function drawText(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1682
+ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1598
1683
  {
1599
- pos = worldToScreen(pos);
1600
- overlayContext.font = size*cameraScale + 'px '+ font;
1684
+ overlayContext.fillStyle = color;
1685
+ overlayContext.lineWidth = lineWidth;
1686
+ overlayContext.strokeStyle = lineColor;
1601
1687
  overlayContext.textAlign = textAlign;
1688
+ overlayContext.font = size + 'px '+ font;
1602
1689
  overlayContext.textBaseline = 'middle';
1603
- if (lineWidth)
1690
+ overlayContext.lineJoin = 'round';
1691
+
1692
+ pos = pos.copy();
1693
+ text.split('\n').forEach(line=>
1604
1694
  {
1605
- overlayContext.lineWidth = lineWidth*cameraScale;
1606
- overlayContext.strokeStyle = lineColor.rgba();
1607
- overlayContext.strokeText(text, pos.x, pos.y);
1608
- }
1609
- overlayContext.fillStyle = color.rgba();
1610
- overlayContext.fillText(text, pos.x, pos.y);
1695
+ lineWidth && overlayContext.strokeText(line, pos.x, pos.y);
1696
+ overlayContext.fillText(line, pos.x, pos.y);
1697
+ pos.y += size;
1698
+ });
1699
+ }
1700
+
1701
+ /** Draw text on overlay canvas in world space
1702
+ * Automatically splits new lines into rows
1703
+ * @param {String} text
1704
+ * @param {Vector2} pos
1705
+ * @param {Number} [size=1]
1706
+ * @param {Color} [color=new Color(1,1,1)]
1707
+ * @param {Number} [lineWidth=0]
1708
+ * @param {Color} [lineColor=new Color(0,0,0)]
1709
+ * @param {String} [textAlign='center']
1710
+ * @memberof Draw */
1711
+ function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
1712
+ {
1713
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
1611
1714
  }
1612
1715
 
1613
1716
  ///////////////////////////////////////////////////////////////////////////////
@@ -1801,6 +1904,10 @@ let mouseWheel = 0;
1801
1904
  * @memberof Input */
1802
1905
  let isUsingGamepad = 0;
1803
1906
 
1907
+ /** Prevents input continuing to the default browser handling (false by default)
1908
+ * @memberof Input */
1909
+ let preventDefaultInput = 0;
1910
+
1804
1911
  /** Returns true if gamepad button is down
1805
1912
  * @param {Number} button
1806
1913
  * @param {Number} [gamepad=0]
@@ -1864,7 +1971,7 @@ onkeydown = (e)=>
1864
1971
  {
1865
1972
  if (debug && e.target != document.body) return;
1866
1973
  e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
1867
- debug || e.preventDefault();
1974
+ preventDefaultInput && e.preventDefault();
1868
1975
  }
1869
1976
  onkeyup = (e)=>
1870
1977
  {
@@ -2428,8 +2535,7 @@ function zzfxG
2428
2535
  )
2429
2536
  {
2430
2537
  // init parameters
2431
- let PI2 = PI*2, sign = v => v>0?1:-1,
2432
- startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2538
+ let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2433
2539
  startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
2434
2540
  t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
2435
2541
 
@@ -2453,15 +2559,15 @@ function zzfxG
2453
2559
  {
2454
2560
  s = shape? shape>1? shape>2? shape>3? // wave shape
2455
2561
  Math.sin((t%PI2)**3) : // 4 noise
2456
- Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
2562
+ max(min(Math.tan(t),1),-1): // 3 tan
2457
2563
  1-(2*t/PI2%2+2)%2: // 2 saw
2458
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2564
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2459
2565
  Math.sin(t); // 0 sin
2460
2566
 
2461
2567
  s = (repeatTime ?
2462
2568
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
2463
2569
  : 1) *
2464
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2570
+ sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2465
2571
  volume * soundVolume * ( // envelope
2466
2572
  i < attack ? i/attack : // attack
2467
2573
  i < attack + decay ? // decay
@@ -2522,7 +2628,6 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2522
2628
  let notFirstBeat;
2523
2629
  let stop;
2524
2630
  let instrument;
2525
- let pitch;
2526
2631
  let attenuation;
2527
2632
  let outSampleOffset;
2528
2633
  let isSequenceEnd;
@@ -2541,7 +2646,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2541
2646
  for (; hasMore; channelIndex++) {
2542
2647
 
2543
2648
  // reset current values
2544
- sampleBuffer = [hasMore = notFirstBeat = pitch = outSampleOffset = 0];
2649
+ sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
2545
2650
 
2546
2651
  // for each pattern in sequence
2547
2652
  sequence.forEach((patternIndex, sequenceIndex) => {
@@ -2762,14 +2867,14 @@ class TileLayerData
2762
2867
  */
2763
2868
  class TileLayer extends EngineObject
2764
2869
  {
2765
- /** Create a tile layer object
2766
- * @param {Vector2} [position=new Vector2()] - World space position
2767
- * @param {Vector2} [size=objectDefaultSize] - World space size
2768
- * @param {Vector2} [tileSize=tileSizeDefault] - Size of tiles in source pixels
2769
- * @param {Vector2} [scale=new Vector2(1,1)] - How much to scale this layer when rendered
2770
- * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
2771
- */
2772
- constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1), renderOrder=0)
2870
+ /** Create a tile layer object
2871
+ * @param {Vector2} [position=new Vector2()] - World space position
2872
+ * @param {Vector2} [size=tileCollisionSize] - World space size
2873
+ * @param {Vector2} [tileSize=tileSizeDefault] - Size of tiles in source pixels
2874
+ * @param {Vector2} [scale=new Vector2(1,1)] - How much to scale this layer when rendered
2875
+ * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
2876
+ */
2877
+ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1), renderOrder=0)
2773
2878
  {
2774
2879
  super(pos, size, -1, tileSize, 0, undefined, renderOrder);
2775
2880
 
@@ -2929,7 +3034,7 @@ class TileLayer extends EngineObject
2929
3034
  if (tileIndex < 0)
2930
3035
  {
2931
3036
  // untextured
2932
- context.fillStyle = color.rgba();
3037
+ context.fillStyle = color;
2933
3038
  context.fillRect(-.5, -.5, 1, 1);
2934
3039
  }
2935
3040
  else
@@ -2948,7 +3053,8 @@ class TileLayer extends EngineObject
2948
3053
  * @param {Vector2} [size=new Vector2(1,1)]
2949
3054
  * @param {Color} [color=new Color(1,1,1)]
2950
3055
  * @param {Number} [angle=0] */
2951
- drawRect(pos, size, color, angle) { this.drawTile(pos, size, -1, 0, color, angle); }
3056
+ drawRect(pos, size, color, angle)
3057
+ { this.drawTile(pos, size, -1, 0, color, angle); }
2952
3058
  }
2953
3059
  /*
2954
3060
  LittleJS Particle System
@@ -2980,7 +3086,7 @@ class ParticleEmitter extends EngineObject
2980
3086
  {
2981
3087
  /** Create a particle system with the given settings
2982
3088
  * @param {Vector2} position - World space position of the emitter
2983
- * @param {Number} [angle=0] - Angle to rotate the object
3089
+ * @param {Number} [angle=0] - Angle to emit the particles
2984
3090
  * @param {Number} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
2985
3091
  * @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
2986
3092
  * @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
@@ -3065,7 +3171,7 @@ class ParticleEmitter extends EngineObject
3065
3171
  // particle settings
3066
3172
  /** @property {Number} - How long particles live */
3067
3173
  this.particleTime = particleTime;
3068
- /** @property {Number} - How big are particles at start */
3174
+ /** @property {Number} - How big are particles at start */
3069
3175
  this.sizeStart = sizeStart;
3070
3176
  /** @property {Number} - How big are particles at end */
3071
3177
  this.sizeEnd = sizeEnd;
@@ -3271,7 +3377,7 @@ function medalsInit(saveName)
3271
3377
  {
3272
3378
  // check if medals are unlocked
3273
3379
  medalsSaveName = saveName;
3274
- debugMedals || medals.forEach(medal=> medal.unlocked = 1 || localStorage[medal.storageKey()]);
3380
+ debugMedals || medals.forEach(medal=> localStorage[medal.storageKey()]);
3275
3381
  }
3276
3382
 
3277
3383
  /**
@@ -3428,7 +3534,7 @@ class Newgrounds
3428
3534
  cipher && (this.cryptoJS = CryptoJS());
3429
3535
 
3430
3536
  // get session id from url search params
3431
- const url = new URL(window.location.href);
3537
+ const url = new URL(location.href);
3432
3538
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
3433
3539
 
3434
3540
  if (this.session_id == 0)
@@ -3460,6 +3566,9 @@ class Newgrounds
3460
3566
  const scoreboardResult = this.call('ScoreBoard.getBoards');
3461
3567
  this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
3462
3568
  debugMedals && console.log(this.scoreboards);
3569
+
3570
+ const keepAliveMS = 5 * 60 * 1e3;
3571
+ setInterval(()=>this.call('Gateway.ping', 0, 1), keepAliveMS);
3463
3572
  }
3464
3573
 
3465
3574
  /** Send message to unlock a medal by id
@@ -3581,7 +3690,7 @@ function glInit()
3581
3690
 
3582
3691
  // setup vertex and fragment shaders
3583
3692
  glShader = glCreateProgram(
3584
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3693
+ 'precision highp float;'+ // use highp for better accuracy
3585
3694
  'uniform mat4 m;'+ // transform matrix
3586
3695
  'attribute vec2 p,t;'+ // position, uv
3587
3696
  'attribute vec4 c,a;'+ // color, additiveColor
@@ -3592,7 +3701,7 @@ function glInit()
3592
3701
  'v=t;d=c;e=a;'+ // pass stuff to fragment shader
3593
3702
  '}' // end of shader
3594
3703
  ,
3595
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3704
+ 'precision highp float;'+ // use highp for better accuracy
3596
3705
  'varying vec2 v;'+ // uv
3597
3706
  'varying vec4 d,e;'+ // color, additiveColor
3598
3707
  'uniform sampler2D s;'+ // texture
@@ -3778,7 +3887,7 @@ function glFlush()
3778
3887
  * @memberof WebGL */
3779
3888
  function glCopyToContext(context, forceDraw)
3780
3889
  {
3781
- if (!glEnable || !glBatchCount) return;
3890
+ if ((!glEnable || !glBatchCount) && !forceDraw) return;
3782
3891
 
3783
3892
  glFlush();
3784
3893
 
package/engine/engine.js CHANGED
@@ -22,7 +22,7 @@
22
22
  const engineName = 'LittleJS';
23
23
 
24
24
  /** Version of engine */
25
- const engineVersion = '1.2.3';
25
+ const engineVersion = '1.3.3';
26
26
 
27
27
  /** Frames per second to update objects
28
28
  * @default */
@@ -103,8 +103,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
103
103
  // main update loop
104
104
  const engineUpdate = (frameTimeMS=0)=>
105
105
  {
106
- requestAnimationFrame(engineUpdate);
107
-
108
106
  // update time keeping
109
107
  let frameTimeDeltaMS = frameTimeMS - frameTimeLastMS;
110
108
  frameTimeLastMS = frameTimeMS;
@@ -203,6 +201,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
203
201
  overlayContext.fillText(text, mainCanvas.width-2, 2);
204
202
  drawCount = 0;
205
203
  }
204
+
205
+ requestAnimationFrame(engineUpdate);
206
206
  }
207
207
 
208
208
  // set tile image source to load the image and start the engine
@@ -289,8 +289,7 @@ function zzfxG
289
289
  )
290
290
  {
291
291
  // init parameters
292
- let PI2 = PI*2, sign = v => v>0?1:-1,
293
- startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
292
+ let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
294
293
  startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
295
294
  t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
296
295
 
@@ -314,15 +313,15 @@ function zzfxG
314
313
  {
315
314
  s = shape? shape>1? shape>2? shape>3? // wave shape
316
315
  Math.sin((t%PI2)**3) : // 4 noise
317
- Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
316
+ max(min(Math.tan(t),1),-1): // 3 tan
318
317
  1-(2*t/PI2%2+2)%2: // 2 saw
319
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
318
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
320
319
  Math.sin(t); // 0 sin
321
320
 
322
321
  s = (repeatTime ?
323
322
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
324
323
  : 1) *
325
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
324
+ sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
326
325
  volume * soundVolume * ( // envelope
327
326
  i < attack ? i/attack : // attack
328
327
  i < attack + decay ? // decay
@@ -383,7 +382,6 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
383
382
  let notFirstBeat;
384
383
  let stop;
385
384
  let instrument;
386
- let pitch;
387
385
  let attenuation;
388
386
  let outSampleOffset;
389
387
  let isSequenceEnd;
@@ -402,7 +400,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
402
400
  for (; hasMore; channelIndex++) {
403
401
 
404
402
  // reset current values
405
- sampleBuffer = [hasMore = notFirstBeat = pitch = outSampleOffset = 0];
403
+ sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
406
404
 
407
405
  // for each pattern in sequence
408
406
  sequence.forEach((patternIndex, sequenceIndex) => {
@@ -79,7 +79,7 @@ copy engine.all.release.js %OUTPUT_FILENAME%
79
79
 
80
80
  rem check code with closure
81
81
  move %OUTPUT_FILENAME% %OUTPUT_FILENAME%.temp
82
- call google-closure-compiler --js %OUTPUT_FILENAME%.temp --js_output_file %OUTPUT_FILENAME% --language_out ECMASCRIPT_2019 --warning_level VERBOSE --jscomp_off *
82
+ call npx google-closure-compiler --js=%OUTPUT_FILENAME%.temp --js_output_file=%OUTPUT_FILENAME% --language_out=ECMASCRIPT_2019 --warning_level=VERBOSE --jscomp_off=*
83
83
  del %OUTPUT_FILENAME%.temp
84
84
  if %ERRORLEVEL% NEQ 0 (
85
85
  pause
@@ -87,15 +87,14 @@ if %ERRORLEVEL% NEQ 0 (
87
87
  )
88
88
 
89
89
  rem lightly minify with uglify
90
- call uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
90
+ call npx uglifyjs -o %OUTPUT_FILENAME% -- %OUTPUT_FILENAME%
91
91
  if %ERRORLEVEL% NEQ 0 (
92
92
  pause
93
93
  exit /b %ERRORLEVEL%
94
94
  )
95
95
 
96
96
  rem --- BUILD TYPESCRIPT DEFINITIONS ---
97
-
98
- call tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
97
+ call npx tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
99
98
  if %ERRORLEVEL% NEQ 0 (
100
99
  pause
101
100
  exit /b %ERRORLEVEL%
@@ -273,17 +273,11 @@ const debugRender = ()=>
273
273
  drawRect(mousePos.floor().add(vec2(.5)), vec2(1), new Color(0,0,1,.5));
274
274
  drawLine(mousePos, bestObject.pos, .1, !raycastHitPos ? new Color(0,1,0,.5) : new Color(1,0,0,.5));
275
275
 
276
- let pos = mousePos.copy(), height = vec2(0,.5);
277
- const printVec2 = (v)=> '(' + (v.x>0?' ':'') + (v.x).toFixed(2) + ',' + (v.y>0?' ':'') + (v.y).toFixed(2) + ')';
278
- const args = [.5, new Color, .05, undefined, undefined, 'monospace'];
279
-
280
- drawText('pos = ' + printVec2(bestObject.pos)
281
- + (bestObject.angle>0?' ':' ') + (bestObject.angle*180/PI).toFixed(1) + '°',
282
- pos = pos.add(height), ...args);
283
- drawText('vel = ' + printVec2(bestObject.velocity), pos = pos.add(height), ...args);
284
- drawText('size = ' + printVec2(bestObject.size), pos = pos.add(height), ...args);
285
- drawText('type = ' + ( bestObject.constructor.name), pos = mousePos.subtract(height), ...args);
286
- drawText('collision = ' + getTileCollisionData(mousePos), pos = mousePos.subtract(height.scale(2)), ...args);
276
+ const debugText = 'mouse pos = ' + mousePos +
277
+ '\nmouse collision = ' + getTileCollisionData(mousePos) +
278
+ '\n\n--- object info ---\n' +
279
+ bestObject.toString();
280
+ drawTextScreen(debugText, mousePosScreen, 24, new Color, .05, undefined, undefined, 'monospace');
287
281
  mainContext = saveContext;
288
282
  }
289
283
 
@@ -292,11 +286,12 @@ const debugRender = ()=>
292
286
 
293
287
  {
294
288
  // draw debug primitives
295
- overlayContext.save();
296
289
  overlayContext.lineWidth = 2;
297
290
  const pointSize = debugPointSize * cameraScale;
298
291
  debugPrimitives.forEach(p=>
299
292
  {
293
+ overlayContext.save();
294
+
300
295
  // create canvas transform from world space to screen space
301
296
  const pos = worldToScreen(p.pos);
302
297
 
@@ -332,12 +327,12 @@ const debugRender = ()=>
332
327
  p.fill && overlayContext.fill();
333
328
  overlayContext.stroke();
334
329
  }
330
+
331
+ overlayContext.restore();
335
332
  });
336
333
 
337
334
  // remove expired pritives
338
335
  debugPrimitives = debugPrimitives.filter(r=>r.time.get()<0);
339
-
340
- overlayContext.restore();
341
336
  }
342
337
 
343
338
  {