littlejsengine 1.17.10 → 1.17.11

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.
package/dist/littlejs.js CHANGED
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
33
33
  * @type {string}
34
34
  * @default
35
35
  * @memberof Engine */
36
- const engineVersion = '1.17.10';
36
+ const engineVersion = '1.17.11';
37
37
 
38
38
  /** Frames per second to update
39
39
  * @type {number}
@@ -396,33 +396,11 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
396
396
  workReadContext = workReadCanvas.getContext('2d', { willReadFrequently: true });
397
397
 
398
398
  // create promises for loading images
399
- const promises = imageSources.map((src, textureIndex)=>
400
- new Promise(resolve =>
401
- {
402
- ASSERT(isString(src), 'imageSources must be an array of strings');
403
-
404
- const image = new Image;
405
- image.onerror = image.onload = ()=>
406
- {
407
- const textureInfo = new TextureInfo(image);
408
- textureInfos[textureIndex] = textureInfo;
409
- resolve();
410
- }
411
- image.crossOrigin = 'anonymous';
412
- image.src = src;
413
- })
414
- );
399
+ const promises = imageSources.map((src, i)=> loadTexture(i, src));
415
400
 
401
+ // no images to load
416
402
  if (!imageSources.length)
417
- {
418
- // no images to load
419
- promises.push(new Promise(resolve =>
420
- {
421
- const textureInfo = new TextureInfo(new Image);
422
- textureInfos[0] = textureInfo;
423
- resolve();
424
- }));
425
- }
403
+ promises.push(loadTexture(0));
426
404
 
427
405
  // load engine font image
428
406
  promises.push(fontImageInit());
@@ -649,7 +627,7 @@ function drawEngineLogo(t)
649
627
  x.lineWidth = .1+p*3.9;
650
628
  x.textAlign = 'center';
651
629
  x.textBaseline = 'top';
652
- rect(11,Y+2,59,8*p,-1);
630
+ rect(11,Y+1,59,8*p,-1);
653
631
  x.beginPath();
654
632
 
655
633
  let w2 = 0;
@@ -672,8 +650,8 @@ function drawEngineLogo(t)
672
650
  rect(25,15,8,25,-1); // cab front
673
651
  rect(10,40,15,-25,1); // cab back
674
652
  rect(14,21,7,9,2); // cab window
675
- rect(38,15,6,6,2); // little stack
676
-
653
+ rect(38,20,6,-6,2); // little stack
654
+
677
655
  // big stack
678
656
  rect(49,20,10,-6,0);
679
657
  const stackPoints = [vec2(44,8),vec2(64,8),vec2(59,8+6*p),vec2(49,8+6*p)];
@@ -681,8 +659,8 @@ function drawEngineLogo(t)
681
659
  rect(44,8,20,-7,0);
682
660
 
683
661
  // engine
684
- for (let i=5;i--;) circle(59-i*6,30,10,0,9,1,0);
685
- circle(59,30,4,0,9,2); // light
662
+ for (let i=5;i--;) circle(59-i*6*p,30,10,0,2*PI,1,0);
663
+ circle(59,30,4,0,7,2); // light
686
664
 
687
665
  // engine outline
688
666
  rect(35,20,24,0); // top
@@ -693,9 +671,7 @@ function drawEngineLogo(t)
693
671
  rect(17,40,43,14,-1); // bottom center
694
672
 
695
673
  // wheels
696
- for (let i=3;i--;)
697
- for (let j=2;j--;)
698
- circle(15*i+17,47,j?7:1,PI,3*PI,2);
674
+ for (let i=3;i--;) for (let j=2;j--;) circle(17+15*i,47,j?7:1,0,2*PI,2);
699
675
 
700
676
  // cowcatcher
701
677
  for (let i=2;i--;)
@@ -865,7 +841,7 @@ function debugPoint(pos, color, time, angle, screenSpace=false)
865
841
  function debugLine(posA, posB, color, width=.1, time, screenSpace=false)
866
842
  {
867
843
  ASSERT(isVector2(posA), 'posA must be a vec2');
868
- ASSERT(isVector2(posB), 'posB must be sa vec2');
844
+ ASSERT(isVector2(posB), 'posB must be a vec2');
869
845
  ASSERT(isNumber(width), 'width must be a number');
870
846
 
871
847
  const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
@@ -1693,7 +1669,9 @@ function wave(frequency=1, amplitude=1, t=time, offset=0)
1693
1669
  function isNumber(n) { return typeof n === 'number' && !isNaN(n); }
1694
1670
 
1695
1671
  /**
1696
- * Check if object is a valid string or can be converted to one
1672
+ * Check if object can be converted to a string (has a toString method)
1673
+ * - Returns true for strings, numbers, and most objects
1674
+ * - Returns false for null and undefined
1697
1675
  * @param {any} s
1698
1676
  * @return {boolean}
1699
1677
  * @memberof Math */
@@ -1770,7 +1748,7 @@ function lineTest(posStart, posEnd, testFunction, normal)
1770
1748
  if (stepX < 0)
1771
1749
  hitPos.x -= e;
1772
1750
  }
1773
- if (stepY < 0)
1751
+ else if (stepY < 0)
1774
1752
  hitPos.y -= e;
1775
1753
 
1776
1754
  // set normal
@@ -2477,7 +2455,7 @@ class Color
2477
2455
  * @memberof Math */
2478
2456
  const WHITE = debugProtectConstant(rgb());
2479
2457
 
2480
- /** Color - Clear White #757474ff with 0 alpha
2458
+ /** Color - Clear White #ffffff00 with 0 alpha
2481
2459
  * @type {Color}
2482
2460
  * @memberof Math */
2483
2461
  const CLEAR_WHITE = debugProtectConstant(rgb(1,1,1,0));
@@ -2487,7 +2465,7 @@ const CLEAR_WHITE = debugProtectConstant(rgb(1,1,1,0));
2487
2465
  * @memberof Math */
2488
2466
  const BLACK = debugProtectConstant(rgb(0,0,0));
2489
2467
 
2490
- /** Color - Clear Black #000000 with 0 alpha
2468
+ /** Color - Clear Black #00000000 with 0 alpha
2491
2469
  * @type {Color}
2492
2470
  * @memberof Math */
2493
2471
  const CLEAR_BLACK = debugProtectConstant(rgb(0,0,0,0));
@@ -4582,6 +4560,31 @@ function drawTextScreen(text, pos, size, color=WHITE, lineWidth=0, lineColor=BLA
4582
4560
  ///////////////////////////////////////////////////////////////////////////////
4583
4561
  // Drawing utilities
4584
4562
 
4563
+ /** Load a texture at a specific index
4564
+ * @param {number} textureIndex - Index to store the texture at
4565
+ * @param {string} [src] - Image source path
4566
+ * @return {Promise} Promise that resolves when texture is loaded
4567
+ * @memberof Draw */
4568
+ async function loadTexture(textureIndex, src)
4569
+ {
4570
+ ASSERT(isNumber(textureIndex), 'textureIndex must be a number');
4571
+ ASSERT(!textureInfos[textureIndex], 'textureIndex is already loaded!');
4572
+ ASSERT(!src || isString(src), 'image src must be a string');
4573
+
4574
+ const image = new Image;
4575
+ if (src)
4576
+ {
4577
+ await new Promise(resolve =>
4578
+ {
4579
+ image.onerror = image.onload = resolve;
4580
+ image.crossOrigin = 'anonymous';
4581
+ image.src = src;
4582
+ });
4583
+ }
4584
+
4585
+ textureInfos[textureIndex] = new TextureInfo(image);
4586
+ }
4587
+
4585
4588
  /** Convert from screen to world space coordinates
4586
4589
  * @param {Vector2} screenPos
4587
4590
  * @return {Vector2}
@@ -4962,23 +4965,20 @@ class FontImage
4962
4965
  }
4963
4966
 
4964
4967
  // load engine font, called automatically on startup
4965
- function fontImageInit()
4968
+ async function fontImageInit()
4966
4969
  {
4967
- return new Promise(resolve =>
4970
+ const image = new Image;
4971
+ await new Promise(resolve =>
4968
4972
  {
4969
- // create the engine font
4970
- const image = new Image;
4971
- image.onerror = image.onload = ()=>
4972
- {
4973
- const tilePos=vec2(), tileSize=vec2(8), padding=1, bleed=0;
4974
- const textureInfo = new TextureInfo(image);
4975
- const tileInfo = new TileInfo(tilePos, tileSize, textureInfo, padding, bleed);
4976
- engineFontImage = new FontImage(tileInfo);
4977
- resolve();
4978
- }
4973
+ image.onerror = image.onload = resolve;
4979
4974
  image.crossOrigin = 'anonymous';
4980
4975
  image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAeAQMAAABnrVXaAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAAAjpJREFUOMu9kzFu2zAUhn+CAROgqrk+B2l0BWYxMjlXeYaAtFtbdA1sGgHqRQfI0CNkSG5AwYB0BQ8d5Bsomwah6CPVeGg6tEPzAxLwyI+P78cP4u9lNO9OoMKnLMOobG5020/yaj/MrRcCGh1gBbyiLTPJEYaIiom5KM9Jq7KgynMGtb6L4GL4MF2H4LQKCXTvDVw2I4MsgZT7QLExdiutH+D08VOP3INXRrWX1/mmpbkNgAPYRVANb4xpcegYvhiNbIXauQICEjBuYLfMakaakWQeXxiZ0VDtuJCKs3ztMV59QtsHJNcRxDzfdL21ty3PrfIcXTN+E+GFAv6T5nbT9jd50/WFxb5ksdAv49qS6ouymG66ji08UMT6moykYLAo+V0j23GN4m829ZySAD5K7QsBfQTvOG8eE+gTeGYRAmnNAubN3hf5Zv9tJWDHp/VTuaSm7SN4fyINQqaNO3RMVxvpSPXnOChnRNvFcGY0gnwiPswYwTKVPE0zVtX3mTEIOoFzaqLrGuJaV+Uqumb71fVk/VoOH3cdLNQP/FHi8hV0CQNoqBZsUPlLPMsdCJro9QAaQQ0woDy9BJm0eTxCFnO9srcYlhNVlfR2EyTrph1uUtbUtAJifwRgrKuYdXVHeb0YI3QpawohQHkloI3J5FuVwI5ORxC9k2Tuz9Ir1IjgeIPGMHYkAZe2RuYkmWFmt3gGbTPOmBUWVTmRmHtGrfpzG/yuQNOKa6gBB/WA9khitPgl6/GP+gl2Af6tCbvaygAAAABJRU5ErkJggg==';
4981
4976
  });
4977
+
4978
+ const tilePos=vec2(), tileSize=vec2(8), padding=1, bleed=0;
4979
+ const textureInfo = new TextureInfo(image);
4980
+ const tileInfo = new TileInfo(tilePos, tileSize, textureInfo, padding, bleed);
4981
+ engineFontImage = new FontImage(tileInfo);
4982
4982
  }
4983
4983
  /**
4984
4984
  * LittleJS Input System
@@ -5961,7 +5961,7 @@ class Sound
5961
5961
 
5962
5962
  /** Loads a sound from a URL and decodes it into sample data.
5963
5963
  * @param {string} filename
5964
- * @return {Promise<void>} */
5964
+ * @return {Promise} */
5965
5965
  async loadSound(filename)
5966
5966
  {
5967
5967
  const response = await fetch(filename);
@@ -6019,7 +6019,7 @@ class Sound
6019
6019
  * // Control the individual instance
6020
6020
  * instance.setVolume(.5);
6021
6021
  * instance.pause();
6022
- * instance.unpause();
6022
+ * instance.resume();
6023
6023
  * instance.stop();
6024
6024
  */
6025
6025
  class SoundInstance
@@ -6133,7 +6133,7 @@ class SoundInstance
6133
6133
  this.startTime = undefined;
6134
6134
  }
6135
6135
 
6136
- /** Unpauses this sound instance */
6136
+ /** Resume this sound instance */
6137
6137
  resume()
6138
6138
  {
6139
6139
  if (!this.isPaused()) return;
@@ -6147,8 +6147,8 @@ class SoundInstance
6147
6147
  */
6148
6148
  isPlaying() { return !!this.source; }
6149
6149
 
6150
- /** Check if this instance is paused and was not stopped
6151
- * @return {boolean} - True if paused
6150
+ /** Check if this instance is paused or stopped (not currently playing)
6151
+ * @return {boolean} - True if not playing
6152
6152
  */
6153
6153
  isPaused() { return !this.isPlaying(); }
6154
6154
 
@@ -7074,7 +7074,7 @@ class TileCollisionLayer extends TileLayer
7074
7074
  collisionTest(pos, size=new Vector2, callbackObject)
7075
7075
  {
7076
7076
  ASSERT(isVector2(pos) && isVector2(size), 'pos and size must be Vector2s');
7077
- ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a funtion or EngineObject');
7077
+ ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a function or EngineObject');
7078
7078
 
7079
7079
  // make function to check for collision
7080
7080
  const collisionTest = callbackObject ? typeof callbackObject === 'function' ?
@@ -7111,7 +7111,7 @@ class TileCollisionLayer extends TileLayer
7111
7111
  collisionRaycast(posStart, posEnd, callbackObject, normal)
7112
7112
  {
7113
7113
  ASSERT(isVector2(posStart) && isVector2(posEnd), 'positions must be Vector2s');
7114
- ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a funtion or EngineObject');
7114
+ ASSERT(!callbackObject || typeof callbackObject === 'function' || callbackObject instanceof EngineObject, 'callbackObject must be a function or EngineObject');
7115
7115
 
7116
7116
  // make function to check for collision
7117
7117
  const collisionTest = callbackObject ? typeof callbackObject === 'function' ?
@@ -10442,7 +10442,7 @@ class UIScrollbar extends UIObject
10442
10442
  else
10443
10443
  {
10444
10444
  // draw the scrollbar handle
10445
- const value = isHorizontal ? this.value : 1 - this.value;
10445
+ const value = clamp(isHorizontal ? this.value : 1 - this.value);
10446
10446
  const p = (barWidth - handleWidth) * (value - .5);
10447
10447
  const pos = this.pos.add(isHorizontal ? vec2(p, 0) : vec2(0, p));
10448
10448
  const color = this.disabled ? this.disabledColor : this.handleColor;
@@ -10511,12 +10511,11 @@ class UIVideo extends UIObject
10511
10511
 
10512
10512
  /** Play or resume the video
10513
10513
  * @return {Promise} Promise that resolves when playback starts */
10514
- play()
10514
+ async play()
10515
10515
  {
10516
10516
  // try to play the video, catch any errors (autoplay may be blocked)
10517
- const promise = this.video.play();
10518
- promise?.catch(()=>{});
10519
- return promise;
10517
+ try { await this.video.play(); }
10518
+ catch(e) {}
10520
10519
  }
10521
10520
 
10522
10521
  /** Pause the video */