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
@@ -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
  {
@@ -700,7 +695,7 @@ class Vector2
700
695
 
701
696
  /** Returns the area this vector covers as a rectangle
702
697
  * @return {Number} */
703
- area() { return this.x * this.y; }
698
+ area() { return abs(this.x * this.y); }
704
699
 
705
700
  /** Returns a new vector that is p percent between this and the vector passed in
706
701
  * @param {Vector2} vector
@@ -711,7 +706,13 @@ class Vector2
711
706
  /** Returns true if this vector is within the bounds of an array size passed in
712
707
  * @param {Vector2} arraySize
713
708
  * @return {Boolean} */
714
- arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
709
+ arrayCheck(arraySize) { return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y; }
710
+
711
+ /** Returns this vector expressed as a string
712
+ * @param {float} digits - precision to display
713
+ * @return {String} */
714
+ toString(digits=3)
715
+ { return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`; }
715
716
  }
716
717
 
717
718
  ///////////////////////////////////////////////////////////////////////////////
@@ -782,7 +783,7 @@ class Color
782
783
  * @return {Color} */
783
784
  lerp(c, p) { return this.add(c.subtract(this).scale(clamp(p))); }
784
785
 
785
- /** Sets this color given a hue, saturation, lightness , and alpha
786
+ /** Sets this color given a hue, saturation, lightness, and alpha
786
787
  * @param {Number} [hue=0]
787
788
  * @param {Number} [saturation=0]
788
789
  * @param {Number} [lightness=1]
@@ -818,21 +819,71 @@ class Color
818
819
  ).clamp();
819
820
  }
820
821
 
821
- /** Returns this color expressed as an rgba string
822
+ /** Returns this color expressed as an CSS color value
822
823
  * @return {String} */
823
- rgba()
824
+ toString()
824
825
  {
825
826
  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);
826
827
  return `rgb(${this.r*255|0},${this.g*255|0},${this.b*255|0},${this.a})`;
827
828
  }
828
829
 
829
- /** Returns this color expressed as 32 bit integer value
830
+ /** Returns this color expressed as 32 bit integer RGBA value
830
831
  * @return {Number} */
831
832
  rgbaInt()
832
833
  {
833
834
  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);
834
835
  return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
835
836
  }
837
+
838
+ /** Returns this color expressed as a hex code
839
+ * @return {String} */
840
+ hex()
841
+ {
842
+ const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
843
+ return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
844
+ }
845
+
846
+ /** Returns this color expressed in hsla format
847
+ * @return {Array} */
848
+ getHSLA()
849
+ {
850
+ const r = this.r;
851
+ const g = this.g;
852
+ const b = this.b;
853
+ const a = this.a;
854
+ const max = Math.max(r, g, b);
855
+ const min = Math.min(r, g, b);
856
+ const l = (max + min) / 2;
857
+
858
+ let h = 0, s = 0;
859
+ if (max != min)
860
+ {
861
+ let d = max - min;
862
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
863
+ if (r == max)
864
+ h = (g - b) / d + (g < b ? 6 : 0);
865
+ else if (g == max)
866
+ h = (b - r) / d + 2;
867
+ else if (b == max)
868
+ h = (r - g) / d + 4;
869
+ }
870
+
871
+ return [h / 6, s, l, a];
872
+ }
873
+
874
+ /** Set this color from a hex code
875
+ * @param {String} hex - html hex code
876
+ * @return {Color} */
877
+ setHex(hex)
878
+ {
879
+ const fromHex = (a)=> parseInt(hex.slice(a,a+2), 16)/255;
880
+ this.r = fromHex(1);
881
+ this.g = fromHex(3),
882
+ this.b = fromHex(5);
883
+ this.a = 1;
884
+ ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
885
+ return this;
886
+ }
836
887
  }
837
888
 
838
889
  ///////////////////////////////////////////////////////////////////////////////
@@ -869,7 +920,7 @@ class Timer
869
920
 
870
921
  /** Returns true if set and elapsed
871
922
  * @return {Boolean} */
872
- elapsed() { return time > this.time; }
923
+ elapsed() { return time > this.time; }
873
924
 
874
925
  /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
875
926
  * @return {Number} */
@@ -878,6 +929,10 @@ class Timer
878
929
  /** Get percentage elapsed based on time it was set to, returns 0 if not set
879
930
  * @return {Number} */
880
931
  getPercent() { return this.isSet()? percent(this.time - time, this.setTime, 0) : 0; }
932
+
933
+ /** Returns this timer expressed as a string
934
+ * @return {String} */
935
+ toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
881
936
  }
882
937
  /**
883
938
  * LittleJS Engine Settings
@@ -934,6 +989,11 @@ let tileFixBleedScale = .3;
934
989
  * @memberof Settings */
935
990
  let objectDefaultSize = vec2(1);
936
991
 
992
+ /** Enable physics solver for collisions between objects
993
+ * @default
994
+ * @memberof Settings */
995
+ let enablePhysicsSolver = 1;
996
+
937
997
  /** Default object mass for collison calcuations (how heavy objects are)
938
998
  * @default
939
999
  * @memberof Settings */
@@ -1132,9 +1192,9 @@ class EngineObject
1132
1192
  /** Create an engine object and adds it to the list of objects
1133
1193
  * @param {Vector2} [position=new Vector2()] - World space position of the object
1134
1194
  * @param {Vector2} [size=objectDefaultSize] - World space size of the object
1135
- * @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
1195
+ * @param {Number} [tileIndex=-1] - Tile to use to render object (-1 is untextured)
1136
1196
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
1137
- * @param {Number} [angle=0] - Angle to rotate the object
1197
+ * @param {Number} [angle=0] - Angle the object is rotated by
1138
1198
  * @param {Color} [color] - Color to apply to tile when rendered
1139
1199
  * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
1140
1200
  */
@@ -1149,7 +1209,7 @@ class EngineObject
1149
1209
  this.size = size;
1150
1210
  /** @property {Vector2} - Size of object used for drawing, uses size if not set */
1151
1211
  this.drawSize;
1152
- /** @property {Number} - Tile to use to render object, untextured if -1 */
1212
+ /** @property {Number} - Tile to use to render object (-1 is untextured) */
1153
1213
  this.tileIndex = tileIndex;
1154
1214
  /** @property {Vector2} - Size of tile in source pixels */
1155
1215
  this.tileSize = tileSize;
@@ -1161,7 +1221,7 @@ class EngineObject
1161
1221
  this.additiveColor;
1162
1222
 
1163
1223
  // set object defaults
1164
- /** @property {Number} [mass=objectDefaultMass] - How heavy the object is */
1224
+ /** @property {Number} [mass=objectDefaultMass] - How heavy the object is, static if 0 */
1165
1225
  this.mass = objectDefaultMass;
1166
1226
  /** @property {Number} [damping=objectDefaultDamping] - How much to slow down velocity each frame (0-1) */
1167
1227
  this.damping = objectDefaultDamping;
@@ -1215,7 +1275,7 @@ class EngineObject
1215
1275
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
1216
1276
  ASSERT(this.damping >= 0 && this.damping <= 1);
1217
1277
 
1218
- if (!this.mass) // do not update collision for fixed objects
1278
+ if (!enablePhysicsSolver || !this.mass) // do not update collision for fixed objects
1219
1279
  return;
1220
1280
 
1221
1281
  const wasMovingDown = this.velocity.y < 0;
@@ -1450,6 +1510,25 @@ class EngineObject
1450
1510
  this.isSolid = isSolid;
1451
1511
  this.collideTiles = collideTiles;
1452
1512
  }
1513
+
1514
+ toString()
1515
+ {
1516
+ if (debug)
1517
+ {
1518
+ let text = 'type = ' + this.constructor.name;
1519
+ if (this.pos.x || this.pos.y)
1520
+ text += '\npos = ' + this.pos;
1521
+ if (this.velocity.x || this.velocity.y)
1522
+ text += '\nvelocity = ' + this.velocity;
1523
+ if (this.size.x || this.size.y)
1524
+ text += '\nsize = ' + this.size;
1525
+ if (this.angle)
1526
+ text += '\nangle = ' + this.angle.toFixed(3);
1527
+ if (this.color)
1528
+ text += '\ncolor = ' + this.color;
1529
+ return text;
1530
+ }
1531
+ }
1453
1532
  }
1454
1533
  /**
1455
1534
  * LittleJS Drawing System
@@ -1563,7 +1642,7 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
1563
1642
  if (tileIndex < 0)
1564
1643
  {
1565
1644
  // if negative tile index, force untextured
1566
- context.fillStyle = color.rgba();
1645
+ context.fillStyle = color;
1567
1646
  context.fillRect(-.5, -.5, 1, 1);
1568
1647
  }
1569
1648
  else
@@ -1618,7 +1697,7 @@ function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angl
1618
1697
  * @memberof Draw */
1619
1698
  function drawRectScreenSpace(pos, size, color, angle, useWebGL)
1620
1699
  {
1621
- drawTileSrceenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1700
+ drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1622
1701
  }
1623
1702
 
1624
1703
  /** Draw colored line between two points
@@ -1668,7 +1747,8 @@ function setBlendMode(additive, useWebGL=glEnable)
1668
1747
  mainContext.globalCompositeOperation = additive ? 'lighter' : 'source-over';
1669
1748
  }
1670
1749
 
1671
- /** Draw text on overlay canvas in world space
1750
+ /** Draw text on overlay canvas in screen space
1751
+ * Automatically splits new lines into rows
1672
1752
  * @param {String} text
1673
1753
  * @param {Vector2} pos
1674
1754
  * @param {Number} [size=1]
@@ -1677,20 +1757,38 @@ function setBlendMode(additive, useWebGL=glEnable)
1677
1757
  * @param {Color} [lineColor=new Color(0,0,0)]
1678
1758
  * @param {String} [textAlign='center']
1679
1759
  * @memberof Draw */
1680
- function drawText(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1760
+ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1681
1761
  {
1682
- pos = worldToScreen(pos);
1683
- overlayContext.font = size*cameraScale + 'px '+ font;
1762
+ overlayContext.fillStyle = color;
1763
+ overlayContext.lineWidth = lineWidth;
1764
+ overlayContext.strokeStyle = lineColor;
1684
1765
  overlayContext.textAlign = textAlign;
1766
+ overlayContext.font = size + 'px '+ font;
1685
1767
  overlayContext.textBaseline = 'middle';
1686
- if (lineWidth)
1768
+ overlayContext.lineJoin = 'round';
1769
+
1770
+ pos = pos.copy();
1771
+ text.split('\n').forEach(line=>
1687
1772
  {
1688
- overlayContext.lineWidth = lineWidth*cameraScale;
1689
- overlayContext.strokeStyle = lineColor.rgba();
1690
- overlayContext.strokeText(text, pos.x, pos.y);
1691
- }
1692
- overlayContext.fillStyle = color.rgba();
1693
- overlayContext.fillText(text, pos.x, pos.y);
1773
+ lineWidth && overlayContext.strokeText(line, pos.x, pos.y);
1774
+ overlayContext.fillText(line, pos.x, pos.y);
1775
+ pos.y += size;
1776
+ });
1777
+ }
1778
+
1779
+ /** Draw text on overlay canvas in world space
1780
+ * Automatically splits new lines into rows
1781
+ * @param {String} text
1782
+ * @param {Vector2} pos
1783
+ * @param {Number} [size=1]
1784
+ * @param {Color} [color=new Color(1,1,1)]
1785
+ * @param {Number} [lineWidth=0]
1786
+ * @param {Color} [lineColor=new Color(0,0,0)]
1787
+ * @param {String} [textAlign='center']
1788
+ * @memberof Draw */
1789
+ function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
1790
+ {
1791
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
1694
1792
  }
1695
1793
 
1696
1794
  ///////////////////////////////////////////////////////////////////////////////
@@ -1884,6 +1982,10 @@ let mouseWheel = 0;
1884
1982
  * @memberof Input */
1885
1983
  let isUsingGamepad = 0;
1886
1984
 
1985
+ /** Prevents input continuing to the default browser handling (false by default)
1986
+ * @memberof Input */
1987
+ let preventDefaultInput = 0;
1988
+
1887
1989
  /** Returns true if gamepad button is down
1888
1990
  * @param {Number} button
1889
1991
  * @param {Number} [gamepad=0]
@@ -1947,7 +2049,7 @@ onkeydown = (e)=>
1947
2049
  {
1948
2050
  if (debug && e.target != document.body) return;
1949
2051
  e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
1950
- debug || e.preventDefault();
2052
+ preventDefaultInput && e.preventDefault();
1951
2053
  }
1952
2054
  onkeyup = (e)=>
1953
2055
  {
@@ -2511,8 +2613,7 @@ function zzfxG
2511
2613
  )
2512
2614
  {
2513
2615
  // init parameters
2514
- let PI2 = PI*2, sign = v => v>0?1:-1,
2515
- startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2616
+ let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2516
2617
  startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
2517
2618
  t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
2518
2619
 
@@ -2536,15 +2637,15 @@ function zzfxG
2536
2637
  {
2537
2638
  s = shape? shape>1? shape>2? shape>3? // wave shape
2538
2639
  Math.sin((t%PI2)**3) : // 4 noise
2539
- Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
2640
+ max(min(Math.tan(t),1),-1): // 3 tan
2540
2641
  1-(2*t/PI2%2+2)%2: // 2 saw
2541
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2642
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2542
2643
  Math.sin(t); // 0 sin
2543
2644
 
2544
2645
  s = (repeatTime ?
2545
2646
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
2546
2647
  : 1) *
2547
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2648
+ sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2548
2649
  volume * soundVolume * ( // envelope
2549
2650
  i < attack ? i/attack : // attack
2550
2651
  i < attack + decay ? // decay
@@ -2605,7 +2706,6 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2605
2706
  let notFirstBeat;
2606
2707
  let stop;
2607
2708
  let instrument;
2608
- let pitch;
2609
2709
  let attenuation;
2610
2710
  let outSampleOffset;
2611
2711
  let isSequenceEnd;
@@ -2624,7 +2724,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2624
2724
  for (; hasMore; channelIndex++) {
2625
2725
 
2626
2726
  // reset current values
2627
- sampleBuffer = [hasMore = notFirstBeat = pitch = outSampleOffset = 0];
2727
+ sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
2628
2728
 
2629
2729
  // for each pattern in sequence
2630
2730
  sequence.forEach((patternIndex, sequenceIndex) => {
@@ -2845,14 +2945,14 @@ class TileLayerData
2845
2945
  */
2846
2946
  class TileLayer extends EngineObject
2847
2947
  {
2848
- /** Create a tile layer object
2849
- * @param {Vector2} [position=new Vector2()] - World space position
2850
- * @param {Vector2} [size=objectDefaultSize] - World space size
2851
- * @param {Vector2} [tileSize=tileSizeDefault] - Size of tiles in source pixels
2852
- * @param {Vector2} [scale=new Vector2(1,1)] - How much to scale this layer when rendered
2853
- * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
2854
- */
2855
- constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1), renderOrder=0)
2948
+ /** Create a tile layer object
2949
+ * @param {Vector2} [position=new Vector2()] - World space position
2950
+ * @param {Vector2} [size=tileCollisionSize] - World space size
2951
+ * @param {Vector2} [tileSize=tileSizeDefault] - Size of tiles in source pixels
2952
+ * @param {Vector2} [scale=new Vector2(1,1)] - How much to scale this layer when rendered
2953
+ * @param {Number} [renderOrder=0] - Objects sorted by renderOrder before being rendered
2954
+ */
2955
+ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1), renderOrder=0)
2856
2956
  {
2857
2957
  super(pos, size, -1, tileSize, 0, undefined, renderOrder);
2858
2958
 
@@ -3012,7 +3112,7 @@ class TileLayer extends EngineObject
3012
3112
  if (tileIndex < 0)
3013
3113
  {
3014
3114
  // untextured
3015
- context.fillStyle = color.rgba();
3115
+ context.fillStyle = color;
3016
3116
  context.fillRect(-.5, -.5, 1, 1);
3017
3117
  }
3018
3118
  else
@@ -3031,7 +3131,8 @@ class TileLayer extends EngineObject
3031
3131
  * @param {Vector2} [size=new Vector2(1,1)]
3032
3132
  * @param {Color} [color=new Color(1,1,1)]
3033
3133
  * @param {Number} [angle=0] */
3034
- drawRect(pos, size, color, angle) { this.drawTile(pos, size, -1, 0, color, angle); }
3134
+ drawRect(pos, size, color, angle)
3135
+ { this.drawTile(pos, size, -1, 0, color, angle); }
3035
3136
  }
3036
3137
  /*
3037
3138
  LittleJS Particle System
@@ -3063,7 +3164,7 @@ class ParticleEmitter extends EngineObject
3063
3164
  {
3064
3165
  /** Create a particle system with the given settings
3065
3166
  * @param {Vector2} position - World space position of the emitter
3066
- * @param {Number} [angle=0] - Angle to rotate the object
3167
+ * @param {Number} [angle=0] - Angle to emit the particles
3067
3168
  * @param {Number} [emitSize=0] - World space size of the emitter (float for circle diameter, vec2 for rect)
3068
3169
  * @param {Number} [emitTime=0] - How long to stay alive (0 is forever)
3069
3170
  * @param {Number} [emitRate=100] - How many particles per second to spawn, does not emit if 0
@@ -3148,7 +3249,7 @@ class ParticleEmitter extends EngineObject
3148
3249
  // particle settings
3149
3250
  /** @property {Number} - How long particles live */
3150
3251
  this.particleTime = particleTime;
3151
- /** @property {Number} - How big are particles at start */
3252
+ /** @property {Number} - How big are particles at start */
3152
3253
  this.sizeStart = sizeStart;
3153
3254
  /** @property {Number} - How big are particles at end */
3154
3255
  this.sizeEnd = sizeEnd;
@@ -3354,7 +3455,7 @@ function medalsInit(saveName)
3354
3455
  {
3355
3456
  // check if medals are unlocked
3356
3457
  medalsSaveName = saveName;
3357
- debugMedals || medals.forEach(medal=> medal.unlocked = 1 || localStorage[medal.storageKey()]);
3458
+ debugMedals || medals.forEach(medal=> localStorage[medal.storageKey()]);
3358
3459
  }
3359
3460
 
3360
3461
  /**
@@ -3511,7 +3612,7 @@ class Newgrounds
3511
3612
  cipher && (this.cryptoJS = CryptoJS());
3512
3613
 
3513
3614
  // get session id from url search params
3514
- const url = new URL(window.location.href);
3615
+ const url = new URL(location.href);
3515
3616
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
3516
3617
 
3517
3618
  if (this.session_id == 0)
@@ -3543,6 +3644,9 @@ class Newgrounds
3543
3644
  const scoreboardResult = this.call('ScoreBoard.getBoards');
3544
3645
  this.scoreboards = scoreboardResult ? scoreboardResult.result.data.scoreboards : [];
3545
3646
  debugMedals && console.log(this.scoreboards);
3647
+
3648
+ const keepAliveMS = 5 * 60 * 1e3;
3649
+ setInterval(()=>this.call('Gateway.ping', 0, 1), keepAliveMS);
3546
3650
  }
3547
3651
 
3548
3652
  /** Send message to unlock a medal by id
@@ -3664,7 +3768,7 @@ function glInit()
3664
3768
 
3665
3769
  // setup vertex and fragment shaders
3666
3770
  glShader = glCreateProgram(
3667
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3771
+ 'precision highp float;'+ // use highp for better accuracy
3668
3772
  'uniform mat4 m;'+ // transform matrix
3669
3773
  'attribute vec2 p,t;'+ // position, uv
3670
3774
  'attribute vec4 c,a;'+ // color, additiveColor
@@ -3675,7 +3779,7 @@ function glInit()
3675
3779
  'v=t;d=c;e=a;'+ // pass stuff to fragment shader
3676
3780
  '}' // end of shader
3677
3781
  ,
3678
- 'precision highp float;'+ // use highp for better accuracy, lowp for better perf
3782
+ 'precision highp float;'+ // use highp for better accuracy
3679
3783
  'varying vec2 v;'+ // uv
3680
3784
  'varying vec4 d,e;'+ // color, additiveColor
3681
3785
  'uniform sampler2D s;'+ // texture
@@ -3861,7 +3965,7 @@ function glFlush()
3861
3965
  * @memberof WebGL */
3862
3966
  function glCopyToContext(context, forceDraw)
3863
3967
  {
3864
- if (!glEnable || !glBatchCount) return;
3968
+ if ((!glEnable || !glBatchCount) && !forceDraw) return;
3865
3969
 
3866
3970
  glFlush();
3867
3971
 
@@ -3991,7 +4095,7 @@ gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2; // vec2 * 2 + (char * 4) * 2
3991
4095
  const engineName = 'LittleJS';
3992
4096
 
3993
4097
  /** Version of engine */
3994
- const engineVersion = '1.2.3';
4098
+ const engineVersion = '1.3.3';
3995
4099
 
3996
4100
  /** Frames per second to update objects
3997
4101
  * @default */
@@ -4072,8 +4176,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4072
4176
  // main update loop
4073
4177
  const engineUpdate = (frameTimeMS=0)=>
4074
4178
  {
4075
- requestAnimationFrame(engineUpdate);
4076
-
4077
4179
  // update time keeping
4078
4180
  let frameTimeDeltaMS = frameTimeMS - frameTimeLastMS;
4079
4181
  frameTimeLastMS = frameTimeMS;
@@ -4172,6 +4274,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
4172
4274
  overlayContext.fillText(text, mainCanvas.width-2, 2);
4173
4275
  drawCount = 0;
4174
4276
  }
4277
+
4278
+ requestAnimationFrame(engineUpdate);
4175
4279
  }
4176
4280
 
4177
4281
  // set tile image source to load the image and start the engine