littlejsengine 1.3.0 → 1.3.8

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.
@@ -8,9 +8,9 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ let showWatermark = 0;
12
+ let godMode = 0;
11
13
  const debug = 0;
12
- const showWatermark = 0;
13
- const godMode = 0;
14
14
  const debugOverlay = 0;
15
15
  const debugPhysics = 0;
16
16
  const debugParticles = 0;
@@ -288,7 +288,7 @@ class Vector2
288
288
  /** Returns a new vector in same direction as this one with the length passed in
289
289
  * @param {Number} [length=1]
290
290
  * @return {Vector2} */
291
- normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(length); }
291
+ normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(0, length); }
292
292
 
293
293
  /** Returns a new vector clamped to length passed in
294
294
  * @param {Number} [length=1]
@@ -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
@@ -442,6 +442,34 @@ class Color
442
442
  return this;
443
443
  }
444
444
 
445
+ /** Returns this color expressed in hsla format
446
+ * @return {Array} */
447
+ getHSLA()
448
+ {
449
+ const r = this.r;
450
+ const g = this.g;
451
+ const b = this.b;
452
+ const a = this.a;
453
+ const max = Math.max(r, g, b);
454
+ const min = Math.min(r, g, b);
455
+ const l = (max + min) / 2;
456
+
457
+ let h = 0, s = 0;
458
+ if (max != min)
459
+ {
460
+ let d = max - min;
461
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
462
+ if (r == max)
463
+ h = (g - b) / d + (g < b ? 6 : 0);
464
+ else if (g == max)
465
+ h = (b - r) / d + 2;
466
+ else if (b == max)
467
+ h = (r - g) / d + 4;
468
+ }
469
+
470
+ return [h / 6, s, l, a];
471
+ }
472
+
445
473
  /** Returns a new color that has each component randomly adjusted
446
474
  * @param {Number} [amount=.05]
447
475
  * @param {Number} [alphaAmount=0]
@@ -473,14 +501,6 @@ class Color
473
501
  return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
474
502
  }
475
503
 
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
504
  /** Set this color from a hex code
485
505
  * @param {String} hex - html hex code
486
506
  * @return {Color} */
@@ -494,6 +514,14 @@ class Color
494
514
  ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
495
515
  return this;
496
516
  }
517
+
518
+ /** Returns this color expressed as a hex code
519
+ * @return {String} */
520
+ getHex()
521
+ {
522
+ const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
523
+ return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
524
+ }
497
525
  }
498
526
 
499
527
  ///////////////////////////////////////////////////////////////////////////////
@@ -542,7 +570,7 @@ class Timer
542
570
 
543
571
  /** Returns this timer expressed as a string
544
572
  * @return {String} */
545
- toString() { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); }
573
+ toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
546
574
  }
547
575
  /**
548
576
  * LittleJS Engine Settings
@@ -560,7 +588,8 @@ class Timer
560
588
  * @memberof Settings */
561
589
  let canvasMaxSize = vec2(1920, 1200);
562
590
 
563
- /** Fixed size of the canvas, if enabled cavnvas size never changes
591
+ /** Fixed size of the canvas, if enabled canvas size never changes
592
+ * - you may also need to set mainCanvasSize if using screen space coords in startup
564
593
  * @type {Vector2}
565
594
  * @default
566
595
  * @memberof Settings */
@@ -599,6 +628,11 @@ let tileFixBleedScale = .3;
599
628
  * @memberof Settings */
600
629
  let objectDefaultSize = vec2(1);
601
630
 
631
+ /** Enable physics solver for collisions between objects
632
+ * @default
633
+ * @memberof Settings */
634
+ let enablePhysicsSolver = 1;
635
+
602
636
  /** Default object mass for collison calcuations (how heavy objects are)
603
637
  * @default
604
638
  * @memberof Settings */
@@ -785,7 +819,7 @@ let medalDisplayIconSize = 50;
785
819
  const engineName = 'LittleJS';
786
820
 
787
821
  /** Version of engine */
788
- const engineVersion = '1.3.0';
822
+ const engineVersion = '1.3.8';
789
823
 
790
824
  /** Frames per second to update objects
791
825
  * @default */
@@ -876,6 +910,33 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
876
910
  timeReal += frameTimeDeltaMS / 1e3;
877
911
  frameTimeBufferMS = min(frameTimeBufferMS + !paused * frameTimeDeltaMS, 50); // clamp incase of slow framerate
878
912
 
913
+ if (canvasFixedSize.x)
914
+ {
915
+ // clear set fixed size
916
+ overlayCanvas.width = mainCanvas.width = canvasFixedSize.x;
917
+ overlayCanvas.height = mainCanvas.height = canvasFixedSize.y;
918
+
919
+ // fit to window by adding space on top or bottom if necessary
920
+ const aspect = innerWidth / innerHeight;
921
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
922
+ mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
923
+ mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
924
+ if (glCanvas)
925
+ {
926
+ glCanvas.style.width = mainCanvas.style.width;
927
+ glCanvas.style.height = mainCanvas.style.height;
928
+ }
929
+ }
930
+ else
931
+ {
932
+ // clear and set size to same as window
933
+ overlayCanvas.width = mainCanvas.width = min(innerWidth, canvasMaxSize.x);
934
+ overlayCanvas.height = mainCanvas.height = min(innerHeight, canvasMaxSize.y);
935
+ }
936
+
937
+ // save canvas size
938
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
939
+
879
940
  if (paused)
880
941
  {
881
942
  // do post update even when paused
@@ -912,30 +973,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
912
973
  // add the time smoothing back in
913
974
  frameTimeBufferMS += deltaSmooth;
914
975
  }
915
-
916
- if (canvasFixedSize.x)
917
- {
918
- // clear set fixed size
919
- mainCanvas.width = canvasFixedSize.x;
920
- mainCanvas.height = canvasFixedSize.y;
921
-
922
- // fit to window by adding space on top or bottom if necessary
923
- const aspect = innerWidth / innerHeight;
924
- const fixedAspect = mainCanvas.width / mainCanvas.height;
925
- mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
926
- mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
927
- if (glCanvas)
928
- {
929
- glCanvas.style.width = mainCanvas.style.width;
930
- glCanvas.style.height = mainCanvas.style.height;
931
- }
932
- }
933
- else
934
- {
935
- // clear and set size to same as window
936
- mainCanvas.width = min(innerWidth, canvasMaxSize.x);
937
- mainCanvas.height = min(innerHeight, canvasMaxSize.y);
938
- }
939
976
 
940
977
  // render sort then render while removing destroyed objects
941
978
  enginePreRender();
@@ -975,8 +1012,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
975
1012
  // called by engine to setup render system
976
1013
  function enginePreRender()
977
1014
  {
978
- // save canvas size and clear canvases
979
- mainCanvasSize = vec2(overlayCanvas.width = mainCanvas.width, overlayCanvas.height = mainCanvas.height);
1015
+ // save canvas size
1016
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
980
1017
 
981
1018
  // disable smoothing for pixel art
982
1019
  mainContext.imageSmoothingEnabled = !cavasPixelated;
@@ -1081,7 +1118,7 @@ class EngineObject
1081
1118
  /** Create an engine object and adds it to the list of objects
1082
1119
  * @param {Vector2} [position=new Vector2()] - World space position of the object
1083
1120
  * @param {Vector2} [size=objectDefaultSize] - World space size of the object
1084
- * @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
1121
+ * @param {Number} [tileIndex=-1] - Tile to use to render object (-1 is untextured)
1085
1122
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
1086
1123
  * @param {Number} [angle=0] - Angle the object is rotated by
1087
1124
  * @param {Color} [color] - Color to apply to tile when rendered
@@ -1098,7 +1135,7 @@ class EngineObject
1098
1135
  this.size = size;
1099
1136
  /** @property {Vector2} - Size of object used for drawing, uses size if not set */
1100
1137
  this.drawSize;
1101
- /** @property {Number} - Tile to use to render object, untextured if -1 */
1138
+ /** @property {Number} - Tile to use to render object (-1 is untextured) */
1102
1139
  this.tileIndex = tileIndex;
1103
1140
  /** @property {Vector2} - Size of tile in source pixels */
1104
1141
  this.tileSize = tileSize;
@@ -1110,7 +1147,7 @@ class EngineObject
1110
1147
  this.additiveColor;
1111
1148
 
1112
1149
  // set object defaults
1113
- /** @property {Number} [mass=objectDefaultMass] - How heavy the object is */
1150
+ /** @property {Number} [mass=objectDefaultMass] - How heavy the object is, static if 0 */
1114
1151
  this.mass = objectDefaultMass;
1115
1152
  /** @property {Number} [damping=objectDefaultDamping] - How much to slow down velocity each frame (0-1) */
1116
1153
  this.damping = objectDefaultDamping;
@@ -1164,7 +1201,7 @@ class EngineObject
1164
1201
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
1165
1202
  ASSERT(this.damping >= 0 && this.damping <= 1);
1166
1203
 
1167
- if (!this.mass) // do not update collision for fixed objects
1204
+ if (!enablePhysicsSolver || !this.mass) // do not update collision for fixed objects
1168
1205
  return;
1169
1206
 
1170
1207
  const wasMovingDown = this.velocity.y < 0;
@@ -1174,7 +1211,7 @@ class EngineObject
1174
1211
  const groundSpeed = this.groundObject.velocity ? this.groundObject.velocity.x : 0;
1175
1212
  this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * this.friction;
1176
1213
  this.groundObject = 0;
1177
- //debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
1214
+ //debugOverlay && debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
1178
1215
  }
1179
1216
 
1180
1217
  if (this.collideSolidObjects)
@@ -1206,7 +1243,7 @@ class EngineObject
1206
1243
  if (o.mass) // push away if not fixed
1207
1244
  o.velocity = o.velocity.subtract(velocity);
1208
1245
 
1209
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
1246
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
1210
1247
  continue;
1211
1248
  }
1212
1249
 
@@ -1269,7 +1306,7 @@ class EngineObject
1269
1306
  else // bounce if other object is fixed
1270
1307
  this.velocity.x *= -this.elasticity;
1271
1308
  }
1272
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
1309
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
1273
1310
  }
1274
1311
  }
1275
1312
  if (this.collideTiles)
@@ -1402,18 +1439,21 @@ class EngineObject
1402
1439
 
1403
1440
  toString()
1404
1441
  {
1405
- let text = 'type = ' + this.constructor.name;
1406
- if (this.pos.x || this.pos.y)
1407
- text += '\npos = ' + this.pos;
1408
- if (this.velocity.x || this.velocity.y)
1409
- text += '\nvelocity = ' + this.velocity;
1410
- if (this.size.x || this.size.y)
1411
- text += '\nsize = ' + this.size;
1412
- if (this.angle)
1413
- text += '\nangle = ' + this.angle.toFixed(3);
1414
- if (this.color)
1415
- text += '\ncolor = ' + this.color;
1416
- return text;
1442
+ if (debug)
1443
+ {
1444
+ let text = 'type = ' + this.constructor.name;
1445
+ if (this.pos.x || this.pos.y)
1446
+ text += '\npos = ' + this.pos;
1447
+ if (this.velocity.x || this.velocity.y)
1448
+ text += '\nvelocity = ' + this.velocity;
1449
+ if (this.size.x || this.size.y)
1450
+ text += '\nsize = ' + this.size;
1451
+ if (this.angle)
1452
+ text += '\nangle = ' + this.angle.toFixed(3);
1453
+ if (this.color)
1454
+ text += '\ncolor = ' + this.color;
1455
+ return text;
1456
+ }
1417
1457
  }
1418
1458
  }
1419
1459
  /**
@@ -1471,18 +1511,26 @@ let overlayContext;
1471
1511
  let mainCanvasSize = vec2();
1472
1512
 
1473
1513
  /** Convert from screen to world space coordinates
1514
+ * - if calling outside of render, you may need to manually set mainCanvasSize
1474
1515
  * @param {Vector2} screenPos
1475
1516
  * @return {Vector2}
1476
1517
  * @memberof Draw */
1477
1518
  const screenToWorld = (screenPos)=>
1478
- screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
1519
+ {
1520
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1521
+ return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
1522
+ }
1479
1523
 
1480
1524
  /** Convert from world to screen space coordinates
1525
+ * - if calling outside of render, you may need to manually set mainCanvasSize
1481
1526
  * @param {Vector2} worldPos
1482
1527
  * @return {Vector2}
1483
1528
  * @memberof Draw */
1484
1529
  const worldToScreen = (worldPos)=>
1485
- worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
1530
+ {
1531
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1532
+ return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
1533
+ }
1486
1534
 
1487
1535
  /** Draw textured tile centered in world space, with color applied if using WebGL
1488
1536
  * @param {Vector2} pos - Center of the tile in world space
@@ -1583,7 +1631,7 @@ function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angl
1583
1631
  * @memberof Draw */
1584
1632
  function drawRectScreenSpace(pos, size, color, angle, useWebGL)
1585
1633
  {
1586
- drawTileSrceenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1634
+ drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1587
1635
  }
1588
1636
 
1589
1637
  /** Draw colored line between two points
@@ -1646,14 +1694,15 @@ function setBlendMode(additive, useWebGL=glEnable)
1646
1694
  function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1647
1695
  {
1648
1696
  overlayContext.fillStyle = color;
1649
- overlayContext.lineWidth = lineWidth *= cameraScale;
1697
+ overlayContext.lineWidth = lineWidth;
1650
1698
  overlayContext.strokeStyle = lineColor;
1651
1699
  overlayContext.textAlign = textAlign;
1652
1700
  overlayContext.font = size + 'px '+ font;
1653
1701
  overlayContext.textBaseline = 'middle';
1702
+ overlayContext.lineJoin = 'round';
1654
1703
 
1655
1704
  pos = pos.copy();
1656
- text.split('\n').forEach(line=>
1705
+ (text+'').split('\n').forEach(line=>
1657
1706
  {
1658
1707
  lineWidth && overlayContext.strokeText(line, pos.x, pos.y);
1659
1708
  overlayContext.fillText(line, pos.x, pos.y);
@@ -1673,7 +1722,7 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
1673
1722
  * @memberof Draw */
1674
1723
  function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
1675
1724
  {
1676
- drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth, lineColor, textAlign, font);
1725
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
1677
1726
  }
1678
1727
 
1679
1728
  ///////////////////////////////////////////////////////////////////////////////
@@ -1867,6 +1916,10 @@ let mouseWheel = 0;
1867
1916
  * @memberof Input */
1868
1917
  let isUsingGamepad = 0;
1869
1918
 
1919
+ /** Prevents input continuing to the default browser handling (false by default)
1920
+ * @memberof Input */
1921
+ let preventDefaultInput = 0;
1922
+
1870
1923
  /** Returns true if gamepad button is down
1871
1924
  * @param {Number} button
1872
1925
  * @param {Number} [gamepad=0]
@@ -1930,7 +1983,7 @@ onkeydown = (e)=>
1930
1983
  {
1931
1984
  if (debug && e.target != document.body) return;
1932
1985
  e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
1933
- debug || e.preventDefault();
1986
+ preventDefaultInput && e.preventDefault();
1934
1987
  }
1935
1988
  onkeyup = (e)=>
1936
1989
  {
@@ -1955,7 +2008,7 @@ const mouseToScreen = (mousePos)=>
1955
2008
  return vec2(); // fix bug that can occur if user clicks before page loads
1956
2009
 
1957
2010
  const rect = mainCanvas.getBoundingClientRect();
1958
- return mainCanvasSize.multiply(
2011
+ return vec2(mainCanvas.width, mainCanvas.height).multiply(
1959
2012
  vec2(percent(mousePos.x, rect.left, rect.right), percent(mousePos.y, rect.top, rect.bottom)));
1960
2013
  }
1961
2014
 
@@ -2494,8 +2547,7 @@ function zzfxG
2494
2547
  )
2495
2548
  {
2496
2549
  // init parameters
2497
- let PI2 = PI*2, sign = v => v>0?1:-1,
2498
- startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2550
+ let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2499
2551
  startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
2500
2552
  t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
2501
2553
 
@@ -2519,15 +2571,15 @@ function zzfxG
2519
2571
  {
2520
2572
  s = shape? shape>1? shape>2? shape>3? // wave shape
2521
2573
  Math.sin((t%PI2)**3) : // 4 noise
2522
- Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
2574
+ max(min(Math.tan(t),1),-1): // 3 tan
2523
2575
  1-(2*t/PI2%2+2)%2: // 2 saw
2524
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2576
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2525
2577
  Math.sin(t); // 0 sin
2526
2578
 
2527
2579
  s = (repeatTime ?
2528
2580
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
2529
2581
  : 1) *
2530
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2582
+ sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2531
2583
  volume * soundVolume * ( // envelope
2532
2584
  i < attack ? i/attack : // attack
2533
2585
  i < attack + decay ? // decay
@@ -2588,7 +2640,6 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2588
2640
  let notFirstBeat;
2589
2641
  let stop;
2590
2642
  let instrument;
2591
- let pitch;
2592
2643
  let attenuation;
2593
2644
  let outSampleOffset;
2594
2645
  let isSequenceEnd;
@@ -2607,7 +2658,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2607
2658
  for (; hasMore; channelIndex++) {
2608
2659
 
2609
2660
  // reset current values
2610
- sampleBuffer = [hasMore = notFirstBeat = pitch = outSampleOffset = 0];
2661
+ sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
2611
2662
 
2612
2663
  // for each pattern in sequence
2613
2664
  sequence.forEach((patternIndex, sequenceIndex) => {
@@ -3132,7 +3183,7 @@ class ParticleEmitter extends EngineObject
3132
3183
  // particle settings
3133
3184
  /** @property {Number} - How long particles live */
3134
3185
  this.particleTime = particleTime;
3135
- /** @property {Number} - How big are particles at start */
3186
+ /** @property {Number} - How big are particles at start */
3136
3187
  this.sizeStart = sizeStart;
3137
3188
  /** @property {Number} - How big are particles at end */
3138
3189
  this.sizeEnd = sizeEnd;
@@ -3495,7 +3546,7 @@ class Newgrounds
3495
3546
  cipher && (this.cryptoJS = CryptoJS());
3496
3547
 
3497
3548
  // get session id from url search params
3498
- const url = new URL(window.location.href);
3549
+ const url = new URL(location.href);
3499
3550
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
3500
3551
 
3501
3552
  if (this.session_id == 0)
@@ -3848,7 +3899,7 @@ function glFlush()
3848
3899
  * @memberof WebGL */
3849
3900
  function glCopyToContext(context, forceDraw)
3850
3901
  {
3851
- if (!glEnable || !glBatchCount) return;
3902
+ if ((!glEnable || !glBatchCount) && !forceDraw) return;
3852
3903
 
3853
3904
  glFlush();
3854
3905
 
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.3.0';
25
+ const engineVersion = '1.3.8';
26
26
 
27
27
  /** Frames per second to update objects
28
28
  * @default */
@@ -113,6 +113,33 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
113
113
  timeReal += frameTimeDeltaMS / 1e3;
114
114
  frameTimeBufferMS = min(frameTimeBufferMS + !paused * frameTimeDeltaMS, 50); // clamp incase of slow framerate
115
115
 
116
+ if (canvasFixedSize.x)
117
+ {
118
+ // clear set fixed size
119
+ overlayCanvas.width = mainCanvas.width = canvasFixedSize.x;
120
+ overlayCanvas.height = mainCanvas.height = canvasFixedSize.y;
121
+
122
+ // fit to window by adding space on top or bottom if necessary
123
+ const aspect = innerWidth / innerHeight;
124
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
125
+ mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
126
+ mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
127
+ if (glCanvas)
128
+ {
129
+ glCanvas.style.width = mainCanvas.style.width;
130
+ glCanvas.style.height = mainCanvas.style.height;
131
+ }
132
+ }
133
+ else
134
+ {
135
+ // clear and set size to same as window
136
+ overlayCanvas.width = mainCanvas.width = min(innerWidth, canvasMaxSize.x);
137
+ overlayCanvas.height = mainCanvas.height = min(innerHeight, canvasMaxSize.y);
138
+ }
139
+
140
+ // save canvas size
141
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
142
+
116
143
  if (paused)
117
144
  {
118
145
  // do post update even when paused
@@ -149,30 +176,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
149
176
  // add the time smoothing back in
150
177
  frameTimeBufferMS += deltaSmooth;
151
178
  }
152
-
153
- if (canvasFixedSize.x)
154
- {
155
- // clear set fixed size
156
- mainCanvas.width = canvasFixedSize.x;
157
- mainCanvas.height = canvasFixedSize.y;
158
-
159
- // fit to window by adding space on top or bottom if necessary
160
- const aspect = innerWidth / innerHeight;
161
- const fixedAspect = mainCanvas.width / mainCanvas.height;
162
- mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
163
- mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
164
- if (glCanvas)
165
- {
166
- glCanvas.style.width = mainCanvas.style.width;
167
- glCanvas.style.height = mainCanvas.style.height;
168
- }
169
- }
170
- else
171
- {
172
- // clear and set size to same as window
173
- mainCanvas.width = min(innerWidth, canvasMaxSize.x);
174
- mainCanvas.height = min(innerHeight, canvasMaxSize.y);
175
- }
176
179
 
177
180
  // render sort then render while removing destroyed objects
178
181
  enginePreRender();
@@ -212,8 +215,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
212
215
  // called by engine to setup render system
213
216
  function enginePreRender()
214
217
  {
215
- // save canvas size and clear canvases
216
- mainCanvasSize = vec2(overlayCanvas.width = mainCanvas.width, overlayCanvas.height = mainCanvas.height);
218
+ // save canvas size
219
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
217
220
 
218
221
  // disable smoothing for pixel art
219
222
  mainContext.imageSmoothingEnabled = !cavasPixelated;
@@ -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) => {
@@ -94,7 +94,6 @@ if %ERRORLEVEL% NEQ 0 (
94
94
  )
95
95
 
96
96
  rem --- BUILD TYPESCRIPT DEFINITIONS ---
97
-
98
97
  call npx tsc engine.all.js --declaration --allowJs --emitDeclarationOnly --outFile index.d.ts
99
98
  if %ERRORLEVEL% NEQ 0 (
100
99
  pause
@@ -30,7 +30,7 @@ const enableAsserts = 1;
30
30
  * @memberof Debug */
31
31
  const debugPointSize = .5;
32
32
 
33
- /** True if watermark with FPS should be down
33
+ /** True if watermark with FPS should be down, false in release builds
34
34
  * @default
35
35
  * @memberof Debug */
36
36
  let showWatermark = 1;