littlejsengine 1.2.9 → 1.3.5

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.
@@ -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
@@ -481,6 +481,34 @@ class Color
481
481
  return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
482
482
  }
483
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
+
484
512
  /** Set this color from a hex code
485
513
  * @param {String} hex - html hex code
486
514
  * @return {Color} */
@@ -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
@@ -599,6 +627,11 @@ let tileFixBleedScale = .3;
599
627
  * @memberof Settings */
600
628
  let objectDefaultSize = vec2(1);
601
629
 
630
+ /** Enable physics solver for collisions between objects
631
+ * @default
632
+ * @memberof Settings */
633
+ let enablePhysicsSolver = 1;
634
+
602
635
  /** Default object mass for collison calcuations (how heavy objects are)
603
636
  * @default
604
637
  * @memberof Settings */
@@ -785,7 +818,7 @@ let medalDisplayIconSize = 50;
785
818
  const engineName = 'LittleJS';
786
819
 
787
820
  /** Version of engine */
788
- const engineVersion = '1.2.8';
821
+ const engineVersion = '1.3.5';
789
822
 
790
823
  /** Frames per second to update objects
791
824
  * @default */
@@ -1081,7 +1114,7 @@ class EngineObject
1081
1114
  /** Create an engine object and adds it to the list of objects
1082
1115
  * @param {Vector2} [position=new Vector2()] - World space position of the object
1083
1116
  * @param {Vector2} [size=objectDefaultSize] - World space size of the object
1084
- * @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)
1085
1118
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
1086
1119
  * @param {Number} [angle=0] - Angle the object is rotated by
1087
1120
  * @param {Color} [color] - Color to apply to tile when rendered
@@ -1098,7 +1131,7 @@ class EngineObject
1098
1131
  this.size = size;
1099
1132
  /** @property {Vector2} - Size of object used for drawing, uses size if not set */
1100
1133
  this.drawSize;
1101
- /** @property {Number} - Tile to use to render object, untextured if -1 */
1134
+ /** @property {Number} - Tile to use to render object (-1 is untextured) */
1102
1135
  this.tileIndex = tileIndex;
1103
1136
  /** @property {Vector2} - Size of tile in source pixels */
1104
1137
  this.tileSize = tileSize;
@@ -1110,7 +1143,7 @@ class EngineObject
1110
1143
  this.additiveColor;
1111
1144
 
1112
1145
  // set object defaults
1113
- /** @property {Number} [mass=objectDefaultMass] - How heavy the object is */
1146
+ /** @property {Number} [mass=objectDefaultMass] - How heavy the object is, static if 0 */
1114
1147
  this.mass = objectDefaultMass;
1115
1148
  /** @property {Number} [damping=objectDefaultDamping] - How much to slow down velocity each frame (0-1) */
1116
1149
  this.damping = objectDefaultDamping;
@@ -1164,7 +1197,7 @@ class EngineObject
1164
1197
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
1165
1198
  ASSERT(this.damping >= 0 && this.damping <= 1);
1166
1199
 
1167
- if (!this.mass) // do not update collision for fixed objects
1200
+ if (!enablePhysicsSolver || !this.mass) // do not update collision for fixed objects
1168
1201
  return;
1169
1202
 
1170
1203
  const wasMovingDown = this.velocity.y < 0;
@@ -1174,7 +1207,7 @@ class EngineObject
1174
1207
  const groundSpeed = this.groundObject.velocity ? this.groundObject.velocity.x : 0;
1175
1208
  this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * this.friction;
1176
1209
  this.groundObject = 0;
1177
- //debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
1210
+ //debugOverlay && debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
1178
1211
  }
1179
1212
 
1180
1213
  if (this.collideSolidObjects)
@@ -1206,7 +1239,7 @@ class EngineObject
1206
1239
  if (o.mass) // push away if not fixed
1207
1240
  o.velocity = o.velocity.subtract(velocity);
1208
1241
 
1209
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
1242
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
1210
1243
  continue;
1211
1244
  }
1212
1245
 
@@ -1269,7 +1302,7 @@ class EngineObject
1269
1302
  else // bounce if other object is fixed
1270
1303
  this.velocity.x *= -this.elasticity;
1271
1304
  }
1272
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
1305
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
1273
1306
  }
1274
1307
  }
1275
1308
  if (this.collideTiles)
@@ -1402,18 +1435,21 @@ class EngineObject
1402
1435
 
1403
1436
  toString()
1404
1437
  {
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;
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
+ }
1417
1453
  }
1418
1454
  }
1419
1455
  /**
@@ -1583,7 +1619,7 @@ function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angl
1583
1619
  * @memberof Draw */
1584
1620
  function drawRectScreenSpace(pos, size, color, angle, useWebGL)
1585
1621
  {
1586
- drawTileSrceenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1622
+ drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
1587
1623
  }
1588
1624
 
1589
1625
  /** Draw colored line between two points
@@ -1646,14 +1682,15 @@ function setBlendMode(additive, useWebGL=glEnable)
1646
1682
  function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
1647
1683
  {
1648
1684
  overlayContext.fillStyle = color;
1649
- overlayContext.lineWidth = lineWidth *= cameraScale;
1685
+ overlayContext.lineWidth = lineWidth;
1650
1686
  overlayContext.strokeStyle = lineColor;
1651
1687
  overlayContext.textAlign = textAlign;
1652
1688
  overlayContext.font = size + 'px '+ font;
1653
1689
  overlayContext.textBaseline = 'middle';
1690
+ overlayContext.lineJoin = 'round';
1654
1691
 
1655
1692
  pos = pos.copy();
1656
- text.split('\n').forEach(line=>
1693
+ (text+'').split('\n').forEach(line=>
1657
1694
  {
1658
1695
  lineWidth && overlayContext.strokeText(line, pos.x, pos.y);
1659
1696
  overlayContext.fillText(line, pos.x, pos.y);
@@ -1673,7 +1710,7 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
1673
1710
  * @memberof Draw */
1674
1711
  function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
1675
1712
  {
1676
- drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth, lineColor, textAlign, font);
1713
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
1677
1714
  }
1678
1715
 
1679
1716
  ///////////////////////////////////////////////////////////////////////////////
@@ -1867,6 +1904,10 @@ let mouseWheel = 0;
1867
1904
  * @memberof Input */
1868
1905
  let isUsingGamepad = 0;
1869
1906
 
1907
+ /** Prevents input continuing to the default browser handling (false by default)
1908
+ * @memberof Input */
1909
+ let preventDefaultInput = 0;
1910
+
1870
1911
  /** Returns true if gamepad button is down
1871
1912
  * @param {Number} button
1872
1913
  * @param {Number} [gamepad=0]
@@ -1930,7 +1971,7 @@ onkeydown = (e)=>
1930
1971
  {
1931
1972
  if (debug && e.target != document.body) return;
1932
1973
  e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
1933
- debug || e.preventDefault();
1974
+ preventDefaultInput && e.preventDefault();
1934
1975
  }
1935
1976
  onkeyup = (e)=>
1936
1977
  {
@@ -2494,8 +2535,7 @@ function zzfxG
2494
2535
  )
2495
2536
  {
2496
2537
  // init parameters
2497
- let PI2 = PI*2, sign = v => v>0?1:-1,
2498
- startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2538
+ let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
2499
2539
  startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
2500
2540
  t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length;
2501
2541
 
@@ -2519,15 +2559,15 @@ function zzfxG
2519
2559
  {
2520
2560
  s = shape? shape>1? shape>2? shape>3? // wave shape
2521
2561
  Math.sin((t%PI2)**3) : // 4 noise
2522
- Math.max(Math.min(Math.tan(t),1),-1): // 3 tan
2562
+ max(min(Math.tan(t),1),-1): // 3 tan
2523
2563
  1-(2*t/PI2%2+2)%2: // 2 saw
2524
- 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2564
+ 1-4*abs(Math.round(t/PI2)-t/PI2): // 1 triangle
2525
2565
  Math.sin(t); // 0 sin
2526
2566
 
2527
2567
  s = (repeatTime ?
2528
2568
  1 - tremolo + tremolo*Math.sin(PI2*i/repeatTime) // tremolo
2529
2569
  : 1) *
2530
- sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2570
+ sign(s)*(abs(s)**shapeCurve) * // curve 0=square, 2=pointy
2531
2571
  volume * soundVolume * ( // envelope
2532
2572
  i < attack ? i/attack : // attack
2533
2573
  i < attack + decay ? // decay
@@ -2588,7 +2628,6 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2588
2628
  let notFirstBeat;
2589
2629
  let stop;
2590
2630
  let instrument;
2591
- let pitch;
2592
2631
  let attenuation;
2593
2632
  let outSampleOffset;
2594
2633
  let isSequenceEnd;
@@ -2607,7 +2646,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
2607
2646
  for (; hasMore; channelIndex++) {
2608
2647
 
2609
2648
  // reset current values
2610
- sampleBuffer = [hasMore = notFirstBeat = pitch = outSampleOffset = 0];
2649
+ sampleBuffer = [hasMore = notFirstBeat = outSampleOffset = 0];
2611
2650
 
2612
2651
  // for each pattern in sequence
2613
2652
  sequence.forEach((patternIndex, sequenceIndex) => {
@@ -3132,7 +3171,7 @@ class ParticleEmitter extends EngineObject
3132
3171
  // particle settings
3133
3172
  /** @property {Number} - How long particles live */
3134
3173
  this.particleTime = particleTime;
3135
- /** @property {Number} - How big are particles at start */
3174
+ /** @property {Number} - How big are particles at start */
3136
3175
  this.sizeStart = sizeStart;
3137
3176
  /** @property {Number} - How big are particles at end */
3138
3177
  this.sizeEnd = sizeEnd;
@@ -3495,7 +3534,7 @@ class Newgrounds
3495
3534
  cipher && (this.cryptoJS = CryptoJS());
3496
3535
 
3497
3536
  // get session id from url search params
3498
- const url = new URL(window.location.href);
3537
+ const url = new URL(location.href);
3499
3538
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
3500
3539
 
3501
3540
  if (this.session_id == 0)
@@ -3848,7 +3887,7 @@ function glFlush()
3848
3887
  * @memberof WebGL */
3849
3888
  function glCopyToContext(context, forceDraw)
3850
3889
  {
3851
- if (!glEnable || !glBatchCount) return;
3890
+ if ((!glEnable || !glBatchCount) && !forceDraw) return;
3852
3891
 
3853
3892
  glFlush();
3854
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.9';
25
+ const engineVersion = '1.3.5';
26
26
 
27
27
  /** Frames per second to update objects
28
28
  * @default */
@@ -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%
@@ -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;
@@ -165,7 +165,7 @@ function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angl
165
165
  * @memberof Draw */
166
166
  function drawRectScreenSpace(pos, size, color, angle, useWebGL)
167
167
  {
168
- drawTileSrceenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
168
+ drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
169
169
  }
170
170
 
171
171
  /** Draw colored line between two points
@@ -228,14 +228,15 @@ function setBlendMode(additive, useWebGL=glEnable)
228
228
  function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
229
229
  {
230
230
  overlayContext.fillStyle = color;
231
- overlayContext.lineWidth = lineWidth *= cameraScale;
231
+ overlayContext.lineWidth = lineWidth;
232
232
  overlayContext.strokeStyle = lineColor;
233
233
  overlayContext.textAlign = textAlign;
234
234
  overlayContext.font = size + 'px '+ font;
235
235
  overlayContext.textBaseline = 'middle';
236
+ overlayContext.lineJoin = 'round';
236
237
 
237
238
  pos = pos.copy();
238
- text.split('\n').forEach(line=>
239
+ (text+'').split('\n').forEach(line=>
239
240
  {
240
241
  lineWidth && overlayContext.strokeText(line, pos.x, pos.y);
241
242
  overlayContext.fillText(line, pos.x, pos.y);
@@ -255,7 +256,7 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
255
256
  * @memberof Draw */
256
257
  function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
257
258
  {
258
- drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth, lineColor, textAlign, font);
259
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
259
260
  }
260
261
 
261
262
  ///////////////////////////////////////////////////////////////////////////////
@@ -70,6 +70,10 @@ let mouseWheel = 0;
70
70
  * @memberof Input */
71
71
  let isUsingGamepad = 0;
72
72
 
73
+ /** Prevents input continuing to the default browser handling (false by default)
74
+ * @memberof Input */
75
+ let preventDefaultInput = 0;
76
+
73
77
  /** Returns true if gamepad button is down
74
78
  * @param {Number} button
75
79
  * @param {Number} [gamepad=0]
@@ -133,7 +137,7 @@ onkeydown = (e)=>
133
137
  {
134
138
  if (debug && e.target != document.body) return;
135
139
  e.repeat || (inputData[isUsingGamepad = 0][remapKeyCode(e.keyCode)] = 3);
136
- debug || e.preventDefault();
140
+ preventDefaultInput && e.preventDefault();
137
141
  }
138
142
  onkeyup = (e)=>
139
143
  {
@@ -192,7 +192,7 @@ class Newgrounds
192
192
  cipher && (this.cryptoJS = CryptoJS());
193
193
 
194
194
  // get session id from url search params
195
- const url = new URL(window.location.href);
195
+ const url = new URL(location.href);
196
196
  this.session_id = url.searchParams.get('ngio_session_id') || 0;
197
197
 
198
198
  if (this.session_id == 0)
@@ -34,7 +34,7 @@ class EngineObject
34
34
  /** Create an engine object and adds it to the list of objects
35
35
  * @param {Vector2} [position=new Vector2()] - World space position of the object
36
36
  * @param {Vector2} [size=objectDefaultSize] - World space size of the object
37
- * @param {Number} [tileIndex=-1] - Tile to use to render object, untextured if -1
37
+ * @param {Number} [tileIndex=-1] - Tile to use to render object (-1 is untextured)
38
38
  * @param {Vector2} [tileSize=tileSizeDefault] - Size of tile in source pixels
39
39
  * @param {Number} [angle=0] - Angle the object is rotated by
40
40
  * @param {Color} [color] - Color to apply to tile when rendered
@@ -51,7 +51,7 @@ class EngineObject
51
51
  this.size = size;
52
52
  /** @property {Vector2} - Size of object used for drawing, uses size if not set */
53
53
  this.drawSize;
54
- /** @property {Number} - Tile to use to render object, untextured if -1 */
54
+ /** @property {Number} - Tile to use to render object (-1 is untextured) */
55
55
  this.tileIndex = tileIndex;
56
56
  /** @property {Vector2} - Size of tile in source pixels */
57
57
  this.tileSize = tileSize;
@@ -63,7 +63,7 @@ class EngineObject
63
63
  this.additiveColor;
64
64
 
65
65
  // set object defaults
66
- /** @property {Number} [mass=objectDefaultMass] - How heavy the object is */
66
+ /** @property {Number} [mass=objectDefaultMass] - How heavy the object is, static if 0 */
67
67
  this.mass = objectDefaultMass;
68
68
  /** @property {Number} [damping=objectDefaultDamping] - How much to slow down velocity each frame (0-1) */
69
69
  this.damping = objectDefaultDamping;
@@ -117,7 +117,7 @@ class EngineObject
117
117
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
118
118
  ASSERT(this.damping >= 0 && this.damping <= 1);
119
119
 
120
- if (!this.mass) // do not update collision for fixed objects
120
+ if (!enablePhysicsSolver || !this.mass) // do not update collision for fixed objects
121
121
  return;
122
122
 
123
123
  const wasMovingDown = this.velocity.y < 0;
@@ -127,7 +127,7 @@ class EngineObject
127
127
  const groundSpeed = this.groundObject.velocity ? this.groundObject.velocity.x : 0;
128
128
  this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * this.friction;
129
129
  this.groundObject = 0;
130
- //debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
130
+ //debugOverlay && debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
131
131
  }
132
132
 
133
133
  if (this.collideSolidObjects)
@@ -159,7 +159,7 @@ class EngineObject
159
159
  if (o.mass) // push away if not fixed
160
160
  o.velocity = o.velocity.subtract(velocity);
161
161
 
162
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
162
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f00');
163
163
  continue;
164
164
  }
165
165
 
@@ -222,7 +222,7 @@ class EngineObject
222
222
  else // bounce if other object is fixed
223
223
  this.velocity.x *= -this.elasticity;
224
224
  }
225
- debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
225
+ debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
226
226
  }
227
227
  }
228
228
  if (this.collideTiles)
@@ -355,17 +355,20 @@ class EngineObject
355
355
 
356
356
  toString()
357
357
  {
358
- let text = 'type = ' + this.constructor.name;
359
- if (this.pos.x || this.pos.y)
360
- text += '\npos = ' + this.pos;
361
- if (this.velocity.x || this.velocity.y)
362
- text += '\nvelocity = ' + this.velocity;
363
- if (this.size.x || this.size.y)
364
- text += '\nsize = ' + this.size;
365
- if (this.angle)
366
- text += '\nangle = ' + this.angle.toFixed(3);
367
- if (this.color)
368
- text += '\ncolor = ' + this.color;
369
- return text;
358
+ if (debug)
359
+ {
360
+ let text = 'type = ' + this.constructor.name;
361
+ if (this.pos.x || this.pos.y)
362
+ text += '\npos = ' + this.pos;
363
+ if (this.velocity.x || this.velocity.y)
364
+ text += '\nvelocity = ' + this.velocity;
365
+ if (this.size.x || this.size.y)
366
+ text += '\nsize = ' + this.size;
367
+ if (this.angle)
368
+ text += '\nangle = ' + this.angle.toFixed(3);
369
+ if (this.color)
370
+ text += '\ncolor = ' + this.color;
371
+ return text;
372
+ }
370
373
  }
371
374
  }
@@ -113,7 +113,7 @@ class ParticleEmitter extends EngineObject
113
113
  // particle settings
114
114
  /** @property {Number} - How long particles live */
115
115
  this.particleTime = particleTime;
116
- /** @property {Number} - How big are particles at start */
116
+ /** @property {Number} - How big are particles at start */
117
117
  this.sizeStart = sizeStart;
118
118
  /** @property {Number} - How big are particles at end */
119
119
  this.sizeEnd = sizeEnd;
@@ -53,6 +53,11 @@ let tileFixBleedScale = .3;
53
53
  * @memberof Settings */
54
54
  let objectDefaultSize = vec2(1);
55
55
 
56
+ /** Enable physics solver for collisions between objects
57
+ * @default
58
+ * @memberof Settings */
59
+ let enablePhysicsSolver = 1;
60
+
56
61
  /** Default object mass for collison calcuations (how heavy objects are)
57
62
  * @default
58
63
  * @memberof Settings */
@@ -255,7 +255,7 @@ class Vector2
255
255
  /** Returns a new vector in same direction as this one with the length passed in
256
256
  * @param {Number} [length=1]
257
257
  * @return {Vector2} */
258
- normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(length); }
258
+ normalize(length=1) { const l = this.length(); return l ? this.scale(length/l) : new Vector2(0, length); }
259
259
 
260
260
  /** Returns a new vector clamped to length passed in
261
261
  * @param {Number} [length=1]
@@ -300,7 +300,7 @@ class Vector2
300
300
 
301
301
  /** Returns the area this vector covers as a rectangle
302
302
  * @return {Number} */
303
- area() { return this.x * this.y; }
303
+ area() { return abs(this.x * this.y); }
304
304
 
305
305
  /** Returns a new vector that is p percent between this and the vector passed in
306
306
  * @param {Vector2} vector
@@ -448,6 +448,34 @@ class Color
448
448
  return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
449
449
  }
450
450
 
451
+ /** Returns this color expressed in hsla format
452
+ * @return {Array} */
453
+ getHSLA()
454
+ {
455
+ const r = this.r;
456
+ const g = this.g;
457
+ const b = this.b;
458
+ const a = this.a;
459
+ const max = Math.max(r, g, b);
460
+ const min = Math.min(r, g, b);
461
+ const l = (max + min) / 2;
462
+
463
+ let h = 0, s = 0;
464
+ if (max != min)
465
+ {
466
+ let d = max - min;
467
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
468
+ if (r == max)
469
+ h = (g - b) / d + (g < b ? 6 : 0);
470
+ else if (g == max)
471
+ h = (b - r) / d + 2;
472
+ else if (b == max)
473
+ h = (r - g) / d + 4;
474
+ }
475
+
476
+ return [h / 6, s, l, a];
477
+ }
478
+
451
479
  /** Set this color from a hex code
452
480
  * @param {String} hex - html hex code
453
481
  * @return {Color} */
@@ -509,5 +537,5 @@ class Timer
509
537
 
510
538
  /** Returns this timer expressed as a string
511
539
  * @return {String} */
512
- toString() { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); }
540
+ toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
513
541
  }
@@ -244,7 +244,7 @@ function glFlush()
244
244
  * @memberof WebGL */
245
245
  function glCopyToContext(context, forceDraw)
246
246
  {
247
- if (!glEnable || !glBatchCount) return;
247
+ if ((!glEnable || !glBatchCount) && !forceDraw) return;
248
248
 
249
249
  glFlush();
250
250