littlejsengine 1.15.3 → 1.15.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.
package/src/engine.js CHANGED
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
30
30
  * @type {string}
31
31
  * @default
32
32
  * @memberof Engine */
33
- const engineVersion = '1.15.3';
33
+ const engineVersion = '1.15.8';
34
34
 
35
35
  /** Frames per second to update
36
36
  * @type {number}
@@ -276,7 +276,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
276
276
  o.destroyed || o.render();
277
277
  gameRenderPost();
278
278
  pluginList.forEach(plugin=>plugin.render?.());
279
- touchGamepadRender();
279
+ inputRender();
280
280
  debugRender();
281
281
  glFlush();
282
282
  debugVideoCaptureUpdate();
@@ -549,171 +549,4 @@ function engineObjectsRaycast(start, end, objects=engineObjects)
549
549
 
550
550
  debugRaycast && debugLine(start, end, hitObjects.length ? '#f00' : '#00f', .02);
551
551
  return hitObjects;
552
- }
553
-
554
- ///////////////////////////////////////////////////////////////////////////////
555
- // LittleJS splash screen and logo
556
-
557
- function drawEngineSplashScreen(t)
558
- {
559
- const x = overlayContext;
560
- const w = overlayCanvas.width = innerWidth;
561
- const h = overlayCanvas.height = innerHeight;
562
-
563
- {
564
- // background
565
- const p3 = percent(t, 1, .8);
566
- const p4 = percent(t, 0, .5);
567
- const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,hypot(w,h)*.7);
568
- g.addColorStop(0,hsl(0,0,lerp(0,p3/2,p4),p3).toString());
569
- g.addColorStop(1,hsl(0,0,0,p3).toString());
570
- x.save();
571
- x.fillStyle = g;
572
- x.fillRect(0,0,w,h);
573
- }
574
-
575
- // draw LittleJS logo...
576
- const rect = (X, Y, W, H, C)=>
577
- {
578
- x.beginPath();
579
- x.rect(X,Y,W,C?H*p:H);
580
- x.fillStyle = C;
581
- C ? x.fill() : x.stroke();
582
- };
583
- const line = (X, Y, Z, W)=>
584
- {
585
- x.beginPath();
586
- x.lineTo(X,Y);
587
- x.lineTo(Z,W);
588
- x.stroke();
589
- };
590
- const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
591
- {
592
- const D = (A+B)/2, E = p*(B-A)/2;
593
- x.beginPath();
594
- F && x.lineTo(X,Y);
595
- x.arc(X,Y,R,D-E,D+E);
596
- x.fillStyle = C;
597
- C ? x.fill() : x.stroke();
598
- };
599
- const color = (c=0, l=0) =>
600
- hsl([.98,.3,.57,.14][c%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();
601
- const alpha = wave(1,1,t);
602
- const p = percent(alpha, .1, .5);
603
-
604
- // setup
605
- x.translate(w/2,h/2);
606
- const size = min(6, min(w,h)/99); // fit to screen
607
- x.scale(size,size);
608
- x.translate(-40,-35);
609
- x.lineJoin = x.lineCap = 'round';
610
- x.lineWidth = .1 + p*1.9;
611
-
612
- // drawing effect
613
- const p2 = percent(alpha,.1,1);
614
- x.setLineDash([99*p2,99]);
615
-
616
- // cab top
617
- rect(7,16,18,-8,color(2,2));
618
- rect(7,8,18,4,color(2,3));
619
- rect(25,8,8,8,color(2,1));
620
- rect(25,8,-18,8);
621
- rect(25,8,8,8);
622
-
623
- // cab
624
- rect(25,16,7,23,color());
625
- rect(11,39,14,-23,color(1,1));
626
- rect(11,16,14,18,color(1,2));
627
- rect(11,16,14,8,color(1,3));
628
- rect(25,16,-14,24);
629
-
630
- // cab window
631
- rect(15,29,6,-9,color(2,2));
632
- circle(15,21,5,0,PI/2,color(2,4),1);
633
- rect(21,21,-6,9);
634
-
635
- // little stack
636
- rect(37,14,9,6,color(3,2));
637
- rect(37,14,4.5,6,color(3,3));
638
- rect(37,14,9,6);
639
-
640
- // big stack
641
- rect(50,20,10,-8,color(0,1));
642
- rect(50,20,6.5,-8,color(0,2));
643
- rect(50,20,3.5,-8,color(0,3));
644
- rect(50,20,10,-8);
645
- circle(55,2,11.4,.5,PI-.5,color(3,3));
646
- circle(55,2,11.4,.5,PI/2,color(3,2),1);
647
- circle(55,2,11.4,.5,PI-.5);
648
- rect(45,7,20,-7,color(0,2));
649
- rect(45,-1,20,4,color(0,3));
650
- rect(45,-1,20,8);
651
-
652
- // engine
653
- for (let i=5; i--;)
654
- {
655
- // stagger radius to fix slight seam
656
- circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
657
- circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
658
- circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
659
- }
660
-
661
- // engine outline
662
- circle(36,30,10,PI/2,PI*3/2);
663
- circle(48,30,10,PI/2,PI*3/2);
664
- circle(60,30,10);
665
- line(36,20,60,20);
666
-
667
- // engine front light
668
- circle(60,30,4,PI,3*PI,color(3,2));
669
- circle(60,30,4,PI,2*PI,color(3,3));
670
- circle(60,30,4,PI,3*PI);
671
-
672
- // front brush
673
- for (let i=6; i--;)
674
- {
675
- x.beginPath();
676
- x.lineTo(53,54);
677
- x.lineTo(53,40);
678
- x.lineTo(53+(1+i*2.9)*p,40);
679
- x.lineTo(53+(4+i*3.5)*p,54);
680
- x.fillStyle = color(0,i%2+2);
681
- x.fill();
682
- i%2 && x.stroke();
683
- }
684
-
685
- // wheels
686
- rect(6,40,5,5);
687
- rect(6,40,5,5,color());
688
- rect(15,54,38,-14,color());
689
- for (let i=3; i--;)
690
- for (let j=2; j--;)
691
- {
692
- circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
693
- x.stroke();
694
- circle(15*i+15,47,j?7:1,0,PI,color(i,2));
695
- x.stroke();
696
- }
697
- line(6,40,68,40); // center
698
- line(77,54,4,54); // bottom
699
-
700
- // draw engine name
701
- const s = engineName;
702
- x.font = '900 16px arial';
703
- x.textAlign = 'center';
704
- x.textBaseline = 'top';
705
- x.lineWidth = .1+p*3.9;
706
- let w2 = 0;
707
- for (let i=0; i<s.length; ++i)
708
- w2 += x.measureText(s[i]).width;
709
- for (let j=2; j--;)
710
- for (let i=0, X=41-w2/2; i<s.length; ++i)
711
- {
712
- x.fillStyle = color(i,2);
713
- const w = x.measureText(s[i]).width;
714
- x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
715
- X += w;
716
- }
717
-
718
- x.restore();
719
552
  }
@@ -26,6 +26,7 @@ const engineSourceFiles =
26
26
  `${SOURCE_FOLDER}/engineParticles.js`,
27
27
  `${SOURCE_FOLDER}/engineMedals.js`,
28
28
  `${SOURCE_FOLDER}/engineWebGL.js`,
29
+ `${SOURCE_FOLDER}/engineSplash.js`,
29
30
  ];
30
31
  const enginePluginFiles =
31
32
  [
@@ -194,7 +194,7 @@ function debugOverlap(posA, sizeA, posB, sizeB, color, time, screenSpace=false)
194
194
  }
195
195
 
196
196
  /** Draw a debug axis aligned bounding box in world space
197
- * @param {string} text
197
+ * @param {string|number} text
198
198
  * @param {Vector2} pos
199
199
  * @param {number} [size]
200
200
  * @param {Color|string} [color]
@@ -352,34 +352,46 @@ function debugRender()
352
352
  debugTakeScreenshot = 0;
353
353
  }
354
354
 
355
- if (debugGamepads && gamepadsEnable && navigator.getGamepads)
355
+ if (debugGamepads && gamepadsEnable)
356
356
  {
357
- // gamepad debug display
358
- const gamepads = navigator.getGamepads();
359
- for (let i = gamepads.length; i--;)
357
+ // draw gamepads
358
+ const maxGamepads = 8;
359
+ let gamepadConnectedCount = 0;
360
+ for (let i = 0; i < maxGamepads; i++)
361
+ gamepadConnected(i) && gamepadConnectedCount++;
362
+
363
+ for (let i = 0; i < maxGamepads; i++)
360
364
  {
361
- const gamepad = gamepads[i];
362
- if (gamepad)
365
+ if (!gamepadConnected(i))
366
+ continue;
367
+
368
+ const stickScale = 1;
369
+ const buttonScale = .2;
370
+ const cornerPos = cameraPos.add(vec2(-stickScale*2, ((gamepadConnectedCount-1)/2-i)*stickScale*3));
371
+ debugText(i, cornerPos.add(vec2(-stickScale, stickScale)), 1);
372
+ if (i === gamepadPrimary)
373
+ debugText('Main', cornerPos.add(vec2(-stickScale*2, 0)),1, '#0f0');
374
+
375
+ // read analog sticks
376
+ const stickCount = gamepadStickData[i].length;
377
+ for (let j = 0; j < stickCount; j++)
363
378
  {
364
- const stickScale = 1;
365
- const buttonScale = .2;
366
- const centerPos = cameraPos;
367
- const sticks = gamepadStickData[i];
368
- for (let j = sticks.length; j--;)
369
- {
370
- const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
371
- const stickPos = drawPos.add(sticks[j].scale(stickScale));
372
- debugCircle(drawPos, stickScale*2, '#fff7',0,true);
373
- debugLine(drawPos, stickPos, '#f00');
374
- debugPoint(stickPos, '#f00');
375
- }
376
- for (let j = gamepad.buttons.length; j--;)
377
- {
378
- const drawPos = centerPos.add(vec2(j*buttonScale*2, i*stickScale*3-stickScale-buttonScale));
379
- const pressed = gamepad.buttons[j].pressed;
380
- debugCircle(drawPos, buttonScale*2, pressed ? '#f00' : '#fff7', 0, true);
381
- debugText(''+j, drawPos, .2);
382
- }
379
+ const stick = gamepadStick(j, i);
380
+ const drawPos = cornerPos.add(vec2(j*stickScale*2, 0));
381
+ const stickPos = drawPos.add(stick.scale(stickScale));
382
+ debugCircle(drawPos, stickScale*2, '#fff7',0,true);
383
+ debugLine(drawPos, stickPos, '#f00');
384
+ debugText(j, drawPos, .3);
385
+ debugPoint(stickPos, '#f00');
386
+ }
387
+
388
+ const buttonCount = inputData[i+1].length;
389
+ for (let j = 0; j < buttonCount; j++)
390
+ {
391
+ const drawPos = cornerPos.add(vec2(j*buttonScale*2, -stickScale-buttonScale*2));
392
+ const pressed = gamepadIsDown(j, i);
393
+ debugCircle(drawPos, buttonScale*2, pressed ? '#f00' : '#fff7', 0, true);
394
+ debugText(j, drawPos, .3);
383
395
  }
384
396
  }
385
397
  }
@@ -561,14 +573,18 @@ function debugRender()
561
573
  mousePressed && overlayContext.fillText('Mouse: ' + mousePressed, x, y += h);
562
574
  keysPressed && overlayContext.fillText('Keys: ' + keysPressed, x, y += h);
563
575
 
564
- let buttonsPressed = '';
565
- if (inputData[1])
566
- for (const i in inputData[1])
576
+ // show gamepad buttons
577
+ for (let i = 1; i < inputData.length; i++)
567
578
  {
568
- if (keyIsDown(i, 1))
569
- buttonsPressed += i + ' ' ;
579
+ let buttonsPressed = '';
580
+ if (inputData[i])
581
+ for (const j in inputData[i])
582
+ {
583
+ if (keyIsDown(j, i))
584
+ buttonsPressed += j + ' ' ;
585
+ }
586
+ buttonsPressed && overlayContext.fillText(`Gamepad ${i-1}: ` + buttonsPressed, x, y += h);
570
587
  }
571
- buttonsPressed && overlayContext.fillText('Gamepad: ' + buttonsPressed, x, y += h);
572
588
  }
573
589
  else
574
590
  {
package/src/engineDraw.js CHANGED
@@ -151,7 +151,7 @@ class TileInfo
151
151
  this.padding = padding;
152
152
  /** @property {TextureInfo} - The texture info for this tile */
153
153
  this.textureInfo = textureInfos[this.textureIndex];
154
- /** @property {float} - Shrinks tile by this many pixels to prevent neighbors bleeding */
154
+ /** @property {number} - Shrinks tile by this many pixels to prevent neighbors bleeding */
155
155
  this.bleedScale = bleedScale;
156
156
  }
157
157
 
@@ -638,7 +638,7 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
638
638
 
639
639
  /** Draw text on main canvas in world space
640
640
  * Automatically splits new lines into rows
641
- * @param {string} text
641
+ * @param {string|number} text
642
642
  * @param {Vector2} pos
643
643
  * @param {number} [size]
644
644
  * @param {Color} [color=(1,1,1,1)]
@@ -665,7 +665,7 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
665
665
 
666
666
  /** Draw text on overlay canvas in world space
667
667
  * Automatically splits new lines into rows
668
- * @param {string} text
668
+ * @param {string|number} text
669
669
  * @param {Vector2} pos
670
670
  * @param {number} [size]
671
671
  * @param {Color} [color=(1,1,1,1)]
@@ -684,7 +684,7 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
684
684
 
685
685
  /** Draw text on overlay canvas in screen space
686
686
  * Automatically splits new lines into rows
687
- * @param {string} text
687
+ * @param {string|number} text
688
688
  * @param {Vector2} pos
689
689
  * @param {number} [size]
690
690
  * @param {Color} [color=(1,1,1,1)]
@@ -849,11 +849,28 @@ function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
849
849
  ];
850
850
  }
851
851
 
852
- /** Get the camera's visible area in world space
852
+ /** Get the size of the camera window in world space
853
853
  * @return {Vector2}
854
854
  * @memberof Draw */
855
855
  function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
856
856
 
857
+ /** Check if a point or circle is on screen
858
+ * If size is a Vector2, uses the largest dimension as diameter
859
+ * This can be used to cull offscreen objects from render or update
860
+ * @param {Vector2} pos - world space position
861
+ * @param {Vector2|number} size - world space size or diameter
862
+ * @return {boolean}
863
+ * @memberof Draw */
864
+ function isOnScreen(pos, size=0)
865
+ {
866
+ pos = worldToScreen(pos);
867
+ if (size instanceof Vector2)
868
+ size = max(size.x, size.y); // use largest dimension
869
+ size *= cameraScale/2;
870
+ return pos.x + size > 0 && pos.x - size < mainCanvasSize.x &&
871
+ pos.y + size > 0 && pos.y - size < mainCanvasSize.y;
872
+ }
873
+
857
874
  /** Enable normal or additive blend mode
858
875
  * @param {boolean} [additive]
859
876
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
@@ -1017,7 +1034,7 @@ class FontImage
1017
1034
  }
1018
1035
 
1019
1036
  /** Draw text in world space using the image font
1020
- * @param {string} text
1037
+ * @param {string|number} text
1021
1038
  * @param {Vector2} pos
1022
1039
  * @param {number} [scale=.25]
1023
1040
  * @param {boolean} [center]
@@ -1029,7 +1046,7 @@ class FontImage
1029
1046
  }
1030
1047
 
1031
1048
  /** Draw text on overlay canvas in world space using the image font
1032
- * @param {string} text
1049
+ * @param {string|number} text
1033
1050
  * @param {Vector2} pos
1034
1051
  * @param {number} [scale]
1035
1052
  * @param {boolean} [center]
@@ -1038,7 +1055,7 @@ class FontImage
1038
1055
  { this.drawText(text, pos, scale, center, overlayContext); }
1039
1056
 
1040
1057
  /** Draw text on overlay canvas in screen space using the image font
1041
- * @param {string} text
1058
+ * @param {string|number} text
1042
1059
  * @param {Vector2} pos
1043
1060
  * @param {number} [scale]
1044
1061
  * @param {boolean} [center]
@@ -124,6 +124,7 @@ export
124
124
  setInputWASDEmulateDirection,
125
125
  setTouchGamepadEnable,
126
126
  setTouchGamepadCenterButton,
127
+ setTouchGamepadButtonCount,
127
128
  setTouchGamepadAnalog,
128
129
  setTouchGamepadSize,
129
130
  setTouchGamepadAlpha,
@@ -295,12 +296,14 @@ export
295
296
  mouseInWindow,
296
297
  isUsingGamepad,
297
298
  inputPreventDefault,
299
+ gamepadPrimary,
298
300
  setInputPreventDefault,
299
301
  gamepadIsDown,
300
302
  gamepadWasPressed,
301
303
  gamepadWasReleased,
302
304
  gamepadStick,
303
- gamepadsUpdate,
305
+ gamepadDpad,
306
+ gamepadConnected,
304
307
  vibrate,
305
308
  vibrateStop,
306
309
  isTouchDevice,