littlejsengine 1.15.8 → 1.15.9
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.d.ts +21 -2
- package/dist/littlejs.esm.js +269 -211
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +265 -211
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +265 -211
- package/examples/box2d/game.js +1 -1
- package/examples/electron/index.html +2 -2
- package/examples/platformer/game.js +7 -0
- package/examples/shorts/base.html +1 -2
- package/examples/shorts/uiSystem.js +1 -1
- package/examples/starter/index.html +2 -3
- package/examples/uiSystem/game.js +4 -7
- package/package.json +1 -1
- package/src/engine.js +214 -25
- package/src/engineBuild.js +0 -1
- package/src/engineExport.js +4 -0
- package/src/engineInput.js +13 -1
- package/src/engineParticles.js +8 -6
- package/src/engineSettings.js +24 -0
- package/src/engineTileLayer.js +1 -2
- package/src/engineSplash.js +0 -173
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.15.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.15.9></script>
|
|
11
11
|
|
|
12
12
|
<!-- LittleJS Engine Source
|
|
13
13
|
<script src=../../src/engine.js></script>
|
|
14
|
-
<script src=../../src/engineSplash.js></script>
|
|
15
14
|
<script src=../../src/engineDebug.js></script>
|
|
16
15
|
<script src=../../src/engineUtilities.js></script>
|
|
17
16
|
<script src=../../src/engineSettings.js></script>
|
|
@@ -32,4 +31,4 @@
|
|
|
32
31
|
-->
|
|
33
32
|
|
|
34
33
|
<!-- Add your game scripts here -->
|
|
35
|
-
<script src=game.js?1.15.
|
|
34
|
+
<script src=game.js?1.15.9></script>
|
|
@@ -43,14 +43,14 @@ function createUI()
|
|
|
43
43
|
uiMenu.addChild(uiBackground);
|
|
44
44
|
|
|
45
45
|
// example large text
|
|
46
|
-
const textTitle = new LJS.UIText(vec2(0,-220), vec2(
|
|
46
|
+
const textTitle = new LJS.UIText(vec2(0,-220), vec2(400, 120), 'Test Title');
|
|
47
47
|
uiMenu.addChild(textTitle);
|
|
48
48
|
textTitle.textColor = LJS.RED;
|
|
49
49
|
textTitle.textLineColor = LJS.BLUE;
|
|
50
50
|
textTitle.textLineWidth = 4;
|
|
51
51
|
|
|
52
52
|
// example multiline text
|
|
53
|
-
const textTest = new LJS.UIText(vec2(-60,-120), vec2(
|
|
53
|
+
const textTest = new LJS.UIText(vec2(-60,-120), vec2(300, 60), 'Test Text\nSecond text line.')
|
|
54
54
|
uiMenu.addChild(textTest);
|
|
55
55
|
|
|
56
56
|
// example tile image
|
|
@@ -61,14 +61,11 @@ function createUI()
|
|
|
61
61
|
let navigationIndex = 0;
|
|
62
62
|
|
|
63
63
|
// example checkbox
|
|
64
|
-
const checkbox = new LJS.UICheckbox(vec2(-140,-20), vec2(
|
|
64
|
+
const checkbox = new LJS.UICheckbox(vec2(-140,-20), vec2(50));
|
|
65
65
|
uiMenu.addChild(checkbox);
|
|
66
66
|
checkbox.onChange = ()=> button1.disabled = checkbox.checked;
|
|
67
67
|
checkbox.navigationIndex = ++navigationIndex;
|
|
68
|
-
|
|
69
|
-
// text attached to checkbox
|
|
70
|
-
const checkboxText = new LJS.UIText(vec2(170,0), vec2(300, 60), 'Test Checkbox');
|
|
71
|
-
checkbox.addChild(checkboxText);
|
|
68
|
+
checkbox.text = 'Test Checkbox';
|
|
72
69
|
|
|
73
70
|
// example scrollbar
|
|
74
71
|
const scrollbar = new LJS.UIScrollbar(vec2(0,60), vec2(350, 50));
|
package/package.json
CHANGED
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.
|
|
33
|
+
const engineVersion = '1.15.9';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -305,23 +305,48 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
305
305
|
|
|
306
306
|
if (canvasFixedSize.x)
|
|
307
307
|
{
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
308
|
+
// set canvas fixed size
|
|
309
|
+
mainCanvasSize = canvasFixedSize.copy();
|
|
310
|
+
|
|
311
|
+
// fit to window using css width and height
|
|
312
|
+
const innerAspect = innerWidth / innerHeight;
|
|
313
|
+
const fixedAspect = canvasFixedSize.x / canvasFixedSize.y;
|
|
314
|
+
const w = innerAspect < fixedAspect ? '100%' : '';
|
|
315
|
+
const h = innerAspect < fixedAspect ? '' : '100%';
|
|
316
|
+
overlayCanvas.style.width = mainCanvas.style.width = w;
|
|
317
|
+
overlayCanvas.style.height = mainCanvas.style.height = h;
|
|
318
|
+
if (glCanvas)
|
|
319
|
+
{
|
|
320
|
+
glCanvas.style.width = w;
|
|
321
|
+
glCanvas.style.height = h;
|
|
322
|
+
}
|
|
317
323
|
}
|
|
318
324
|
else
|
|
319
325
|
{
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
326
|
+
// get main canvas size based on window size
|
|
327
|
+
mainCanvasSize.x = min(innerWidth, canvasMaxSize.x);
|
|
328
|
+
mainCanvasSize.y = min(innerHeight, canvasMaxSize.y);
|
|
329
|
+
|
|
330
|
+
// responsive aspect ratio with native resolution
|
|
331
|
+
const innerAspect = innerWidth / innerHeight;
|
|
332
|
+
if (canvasMaxAspect && innerAspect > canvasMaxAspect)
|
|
333
|
+
{
|
|
334
|
+
// full height
|
|
335
|
+
const w = mainCanvasSize.y * canvasMaxAspect | 0;
|
|
336
|
+
mainCanvasSize.x = min(w, canvasMaxSize.x);
|
|
337
|
+
}
|
|
338
|
+
else if (innerAspect < canvasMinAspect)
|
|
339
|
+
{
|
|
340
|
+
// full width
|
|
341
|
+
const h = mainCanvasSize.x / canvasMinAspect | 0;
|
|
342
|
+
mainCanvasSize.y = min(h, canvasMaxSize.y);
|
|
343
|
+
}
|
|
323
344
|
}
|
|
324
345
|
|
|
346
|
+
// clear main and overlay canvas and set size
|
|
347
|
+
overlayCanvas.width = mainCanvas.width = mainCanvasSize.x;
|
|
348
|
+
overlayCanvas.height = mainCanvas.height = mainCanvasSize.y;
|
|
349
|
+
|
|
325
350
|
// apply the clear color to main canvas
|
|
326
351
|
if (canvasClearColor.a > 0)
|
|
327
352
|
{
|
|
@@ -330,13 +355,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
330
355
|
mainContext.fillStyle = BLACK.toString();
|
|
331
356
|
}
|
|
332
357
|
|
|
333
|
-
// clear overlay canvas and set size
|
|
334
|
-
overlayCanvas.width = mainCanvas.width;
|
|
335
|
-
overlayCanvas.height = mainCanvas.height;
|
|
336
|
-
|
|
337
|
-
// save canvas size
|
|
338
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
339
|
-
|
|
340
358
|
// set default line join and cap
|
|
341
359
|
const lineJoin = 'round', lineCap = 'round';
|
|
342
360
|
mainContext.lineJoin = overlayContext.lineJoin = lineJoin;
|
|
@@ -360,7 +378,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
360
378
|
'user-select:none;' + // prevent hold to select
|
|
361
379
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
362
380
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
363
|
-
'-webkit-touch-callout:none'
|
|
381
|
+
'-webkit-touch-callout:none'; // compatibility for ios
|
|
364
382
|
rootElement.style.cssText = styleRoot;
|
|
365
383
|
drawCanvas = mainCanvas = document.createElement('canvas');
|
|
366
384
|
rootElement.appendChild(mainCanvas);
|
|
@@ -377,7 +395,8 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
377
395
|
rootElement.appendChild(overlayCanvas);
|
|
378
396
|
overlayContext = overlayCanvas.getContext('2d');
|
|
379
397
|
|
|
380
|
-
//
|
|
398
|
+
// setup canvases
|
|
399
|
+
// transform way is still more reliable then flexbox or grid
|
|
381
400
|
const styleCanvas = 'position:absolute;'+ // allow canvases to overlap
|
|
382
401
|
'top:50%;left:50%;transform:translate(-50%,-50%)'; // center on screen
|
|
383
402
|
mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
@@ -441,9 +460,176 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
441
460
|
// wait for all the promises to finish
|
|
442
461
|
await Promise.all(promises);
|
|
443
462
|
return startEngine();
|
|
463
|
+
|
|
464
|
+
///////////////////////////////////////////////////////////////////////////
|
|
465
|
+
// LittleJS Splash Screen
|
|
466
|
+
function drawEngineSplashScreen(t)
|
|
467
|
+
{
|
|
468
|
+
const x = overlayContext;
|
|
469
|
+
const w = overlayCanvas.width = innerWidth;
|
|
470
|
+
const h = overlayCanvas.height = innerHeight;
|
|
471
|
+
|
|
472
|
+
{
|
|
473
|
+
// background
|
|
474
|
+
const p3 = percent(t, 1, .8);
|
|
475
|
+
const p4 = percent(t, 0, .5);
|
|
476
|
+
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,hypot(w,h)*.7);
|
|
477
|
+
g.addColorStop(0,hsl(0,0,lerp(0,p3/2,p4),p3).toString());
|
|
478
|
+
g.addColorStop(1,hsl(0,0,0,p3).toString());
|
|
479
|
+
x.save();
|
|
480
|
+
x.fillStyle = g;
|
|
481
|
+
x.fillRect(0,0,w,h);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// draw LittleJS logo...
|
|
485
|
+
const rect = (X, Y, W, H, C)=>
|
|
486
|
+
{
|
|
487
|
+
x.beginPath();
|
|
488
|
+
x.rect(X,Y,W,C?H*p:H);
|
|
489
|
+
x.fillStyle = C;
|
|
490
|
+
C ? x.fill() : x.stroke();
|
|
491
|
+
};
|
|
492
|
+
const line = (X, Y, Z, W)=>
|
|
493
|
+
{
|
|
494
|
+
x.beginPath();
|
|
495
|
+
x.lineTo(X,Y);
|
|
496
|
+
x.lineTo(Z,W);
|
|
497
|
+
x.stroke();
|
|
498
|
+
};
|
|
499
|
+
const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
|
|
500
|
+
{
|
|
501
|
+
const D = (A+B)/2, E = p*(B-A)/2;
|
|
502
|
+
x.beginPath();
|
|
503
|
+
F && x.lineTo(X,Y);
|
|
504
|
+
x.arc(X,Y,R,D-E,D+E);
|
|
505
|
+
x.fillStyle = C;
|
|
506
|
+
C ? x.fill() : x.stroke();
|
|
507
|
+
};
|
|
508
|
+
const color = (c=0, l=0) =>
|
|
509
|
+
hsl([.98,.3,.57,.14][c%4],.8,[0,.3,.5,.8,.9][l]).toString();
|
|
510
|
+
const alpha = wave(1,1,t);
|
|
511
|
+
const p = percent(alpha, .1, .5);
|
|
512
|
+
|
|
513
|
+
// setup
|
|
514
|
+
x.translate(w/2,h/2);
|
|
515
|
+
const size = min(6, min(w,h)/99); // fit to screen
|
|
516
|
+
x.scale(size,size);
|
|
517
|
+
x.translate(-40,-35);
|
|
518
|
+
x.lineJoin = x.lineCap = 'round';
|
|
519
|
+
x.lineWidth = .1 + p*1.9;
|
|
520
|
+
|
|
521
|
+
// drawing effect
|
|
522
|
+
const p2 = percent(alpha,.1,1);
|
|
523
|
+
x.setLineDash([99*p2,99]);
|
|
524
|
+
|
|
525
|
+
// cab top
|
|
526
|
+
rect(7,16,18,-8,color(2,2));
|
|
527
|
+
rect(7,8,18,4,color(2,3));
|
|
528
|
+
rect(25,8,8,8,color(2,1));
|
|
529
|
+
rect(25,8,-18,8);
|
|
530
|
+
rect(25,8,8,8);
|
|
531
|
+
|
|
532
|
+
// cab
|
|
533
|
+
rect(25,16,7,23,color());
|
|
534
|
+
rect(11,39,14,-23,color(1,1));
|
|
535
|
+
rect(11,16,14,18,color(1,2));
|
|
536
|
+
rect(11,16,14,8,color(1,3));
|
|
537
|
+
rect(25,16,-14,24);
|
|
538
|
+
|
|
539
|
+
// cab window
|
|
540
|
+
rect(15,29,6,-9,color(2,2));
|
|
541
|
+
circle(15,21,5,0,PI/2,color(2,4),1);
|
|
542
|
+
rect(21,21,-6,9);
|
|
543
|
+
|
|
544
|
+
// little stack
|
|
545
|
+
rect(37,14,9,6,color(3,2));
|
|
546
|
+
rect(37,14,4.5,6,color(3,3));
|
|
547
|
+
rect(37,14,9,6);
|
|
548
|
+
|
|
549
|
+
// big stack
|
|
550
|
+
rect(50,20,10,-8,color(0,1));
|
|
551
|
+
rect(50,20,6.5,-8,color(0,2));
|
|
552
|
+
rect(50,20,3.5,-8,color(0,3));
|
|
553
|
+
rect(50,20,10,-8);
|
|
554
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
555
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
556
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
557
|
+
rect(45,7,20,-7,color(0,2));
|
|
558
|
+
rect(45,-1,20,4,color(0,3));
|
|
559
|
+
rect(45,-1,20,8);
|
|
560
|
+
|
|
561
|
+
// engine
|
|
562
|
+
for (let i=5; i--;)
|
|
563
|
+
{
|
|
564
|
+
// stagger radius to fix slight seam
|
|
565
|
+
circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
|
|
566
|
+
circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
|
|
567
|
+
circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// engine outline
|
|
571
|
+
circle(36,30,10,PI/2,PI*3/2);
|
|
572
|
+
circle(48,30,10,PI/2,PI*3/2);
|
|
573
|
+
circle(60,30,10);
|
|
574
|
+
line(36,20,60,20);
|
|
575
|
+
|
|
576
|
+
// engine front light
|
|
577
|
+
circle(60,30,4,PI,3*PI,color(3,2));
|
|
578
|
+
circle(60,30,4,PI,2*PI,color(3,3));
|
|
579
|
+
circle(60,30,4,PI,3*PI);
|
|
580
|
+
|
|
581
|
+
// front brush
|
|
582
|
+
for (let i=6; i--;)
|
|
583
|
+
{
|
|
584
|
+
x.beginPath();
|
|
585
|
+
x.lineTo(53,54);
|
|
586
|
+
x.lineTo(53,40);
|
|
587
|
+
x.lineTo(53+(1+i*2.9)*p,40);
|
|
588
|
+
x.lineTo(53+(4+i*3.5)*p,54);
|
|
589
|
+
x.fillStyle = color(0,i%2+2);
|
|
590
|
+
x.fill();
|
|
591
|
+
i%2 && x.stroke();
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// wheels
|
|
595
|
+
rect(6,40,5,5);
|
|
596
|
+
rect(6,40,5,5,color());
|
|
597
|
+
rect(15,54,38,-14,color());
|
|
598
|
+
for (let i=3; i--;)
|
|
599
|
+
for (let j=2; j--;)
|
|
600
|
+
{
|
|
601
|
+
circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
|
|
602
|
+
x.stroke();
|
|
603
|
+
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
604
|
+
x.stroke();
|
|
605
|
+
}
|
|
606
|
+
line(6,40,68,40); // center
|
|
607
|
+
line(77,54,4,54); // bottom
|
|
608
|
+
|
|
609
|
+
// draw engine name
|
|
610
|
+
const s = engineName;
|
|
611
|
+
x.font = '900 16px arial';
|
|
612
|
+
x.textAlign = 'center';
|
|
613
|
+
x.textBaseline = 'top';
|
|
614
|
+
x.lineWidth = .1+p*3.9;
|
|
615
|
+
let w2 = 0;
|
|
616
|
+
for (let i=0; i<s.length; ++i)
|
|
617
|
+
w2 += x.measureText(s[i]).width;
|
|
618
|
+
for (let j=2; j--;)
|
|
619
|
+
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
620
|
+
{
|
|
621
|
+
x.fillStyle = color(i,2);
|
|
622
|
+
const w = x.measureText(s[i]).width;
|
|
623
|
+
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
624
|
+
X += w;
|
|
625
|
+
}
|
|
626
|
+
x.restore();
|
|
627
|
+
}
|
|
628
|
+
///////////////////////////////////////////////////////////////////////////
|
|
444
629
|
}
|
|
445
630
|
|
|
446
631
|
/** Update each engine object, remove destroyed objects, and update time
|
|
632
|
+
* can be called manually if objects need to be updated outside of main loop
|
|
447
633
|
* @memberof Engine */
|
|
448
634
|
function engineObjectsUpdate()
|
|
449
635
|
{
|
|
@@ -495,18 +681,21 @@ function engineObjectsDestroy()
|
|
|
495
681
|
function engineObjectsCollect(pos, size, objects=engineObjects)
|
|
496
682
|
{
|
|
497
683
|
const collectedObjects = [];
|
|
498
|
-
if (!pos)
|
|
684
|
+
if (!pos)
|
|
499
685
|
{
|
|
686
|
+
// all objects
|
|
500
687
|
for (const o of objects)
|
|
501
688
|
collectedObjects.push(o);
|
|
502
689
|
}
|
|
503
|
-
else if (size instanceof Vector2)
|
|
690
|
+
else if (size instanceof Vector2)
|
|
504
691
|
{
|
|
692
|
+
// bounding box test
|
|
505
693
|
for (const o of objects)
|
|
506
694
|
o.isOverlapping(pos, size) && collectedObjects.push(o);
|
|
507
695
|
}
|
|
508
|
-
else
|
|
696
|
+
else
|
|
509
697
|
{
|
|
698
|
+
// circle test
|
|
510
699
|
const sizeSquared = size*size;
|
|
511
700
|
for (const o of objects)
|
|
512
701
|
pos.distanceSquared(o.pos) < sizeSquared && collectedObjects.push(o);
|
package/src/engineBuild.js
CHANGED
package/src/engineExport.js
CHANGED
|
@@ -56,6 +56,8 @@ export
|
|
|
56
56
|
canvasColorTiles,
|
|
57
57
|
canvasClearColor,
|
|
58
58
|
canvasMaxSize,
|
|
59
|
+
canvasMinAspect,
|
|
60
|
+
canvasMaxAspect,
|
|
59
61
|
canvasFixedSize,
|
|
60
62
|
canvasPixelated,
|
|
61
63
|
overlayCanvasPixelated,
|
|
@@ -99,6 +101,8 @@ export
|
|
|
99
101
|
setCanvasColorTiles,
|
|
100
102
|
setCanvasClearColor,
|
|
101
103
|
setCanvasMaxSize,
|
|
104
|
+
setCanvasMinAspect,
|
|
105
|
+
setCanvasMaxAspect,
|
|
102
106
|
setCanvasFixedSize,
|
|
103
107
|
setCanvasPixelated,
|
|
104
108
|
setOverlayCanvasPixelated,
|
package/src/engineInput.js
CHANGED
|
@@ -243,6 +243,16 @@ function gamepadConnected(gamepad=gamepadPrimary)
|
|
|
243
243
|
return !!inputData[gamepad+1];
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
/** Returns how many control sticks the passed in gamepad has
|
|
247
|
+
* @param {number} [gamepad]
|
|
248
|
+
* @return {number}
|
|
249
|
+
* @memberof Input */
|
|
250
|
+
function gamepadStickCount(gamepad=gamepadPrimary)
|
|
251
|
+
{
|
|
252
|
+
ASSERT(isNumber(gamepad), 'gamepad must be a number');
|
|
253
|
+
return gamepadStickData[gamepad]?.length ?? 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
246
256
|
/** True if a touch device has been detected
|
|
247
257
|
* @memberof Input */
|
|
248
258
|
const isTouchDevice = !headlessMode && window.ontouchstart !== undefined;
|
|
@@ -583,9 +593,11 @@ function inputUpdate()
|
|
|
583
593
|
dpad.set(x, -y);
|
|
584
594
|
sticks[0] = dpad.clampLength(); // clamp to circle
|
|
585
595
|
}
|
|
586
|
-
const rightTouchStick = touchGamepadSticks[1] ?? vec2();
|
|
587
596
|
if (touchGamepadButtonCount === 1)
|
|
597
|
+
{
|
|
598
|
+
const rightTouchStick = touchGamepadSticks[1] ?? vec2();
|
|
588
599
|
sticks[1] = applyDeadZones(rightTouchStick);
|
|
600
|
+
}
|
|
589
601
|
|
|
590
602
|
// read virtual gamepad buttons
|
|
591
603
|
const data = inputData[1] ?? (inputData[1] = []);
|
package/src/engineParticles.js
CHANGED
|
@@ -109,9 +109,9 @@ class ParticleEmitter extends EngineObject
|
|
|
109
109
|
/** @property {Color} - Color at start of life 2, randomized between start colors */
|
|
110
110
|
this.colorStartB = colorStartB.copy();
|
|
111
111
|
/** @property {Color} - Color at end of life 1, randomized between end colors */
|
|
112
|
-
this.colorEndA
|
|
112
|
+
this.colorEndA = colorEndA.copy();
|
|
113
113
|
/** @property {Color} - Color at end of life 2, randomized between end colors */
|
|
114
|
-
this.colorEndB
|
|
114
|
+
this.colorEndB = colorEndB.copy();
|
|
115
115
|
/** @property {boolean} - Should color be randomized linearly or across each component */
|
|
116
116
|
this.randomColorLinear = randomColorLinear;
|
|
117
117
|
|
|
@@ -195,8 +195,10 @@ class ParticleEmitter extends EngineObject
|
|
|
195
195
|
if (debugParticles)
|
|
196
196
|
{
|
|
197
197
|
// show emitter bounds
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
if (typeof this.emitSize === 'number')
|
|
199
|
+
debugCircle(this.pos, this.emitSize/2, '#0f0');
|
|
200
|
+
else
|
|
201
|
+
debugRect(this.pos, this.emitSize, '#0f0', 0, this.angle);
|
|
200
202
|
}
|
|
201
203
|
}
|
|
202
204
|
|
|
@@ -206,8 +208,8 @@ class ParticleEmitter extends EngineObject
|
|
|
206
208
|
{
|
|
207
209
|
// spawn a particle
|
|
208
210
|
let pos = typeof this.emitSize === 'number' ? // check if number was used
|
|
209
|
-
randInCircle(this.emitSize/2)
|
|
210
|
-
: vec2(rand(-.5,.5), rand(-.5,.5))
|
|
211
|
+
randInCircle(this.emitSize/2) // circle emitter
|
|
212
|
+
: vec2(rand(-.5,.5), rand(-.5,.5)) // box emitter
|
|
211
213
|
.multiply(this.emitSize).rotate(this.angle)
|
|
212
214
|
let angle = rand(this.particleConeAngle, -this.particleConeAngle);
|
|
213
215
|
if (!this.localSpace)
|
package/src/engineSettings.js
CHANGED
|
@@ -48,6 +48,20 @@ let canvasClearColor = CLEAR_BLACK;
|
|
|
48
48
|
* @memberof Settings */
|
|
49
49
|
let canvasMaxSize = vec2(1920, 1080);
|
|
50
50
|
|
|
51
|
+
/** Minimum aspect ratio of the canvas (width/height), unused if 0
|
|
52
|
+
* Can be used with canvasMaxAspect to limit aspect ratio
|
|
53
|
+
* @type {number}
|
|
54
|
+
* @default
|
|
55
|
+
* @memberof Settings */
|
|
56
|
+
let canvasMinAspect = 0;
|
|
57
|
+
|
|
58
|
+
/** Maximum aspect ratio of the canvas (width/height), unused if 0
|
|
59
|
+
* Can be used with canvasMinAspect to limit aspect ratio
|
|
60
|
+
* @type {number}
|
|
61
|
+
* @default
|
|
62
|
+
* @memberof Settings */
|
|
63
|
+
let canvasMaxAspect = 0;
|
|
64
|
+
|
|
51
65
|
/** Fixed size of the canvas, if enabled canvas size never changes
|
|
52
66
|
* - you may also need to set mainCanvasSize if using screen space coords in startup
|
|
53
67
|
* @type {Vector2}
|
|
@@ -344,6 +358,16 @@ function setCanvasClearColor(color) { canvasClearColor = color.copy(); }
|
|
|
344
358
|
* @memberof Settings */
|
|
345
359
|
function setCanvasMaxSize(size) { canvasMaxSize = size.copy(); }
|
|
346
360
|
|
|
361
|
+
/** Set minimum aspect ratio of the canvas (width/height), unused if 0
|
|
362
|
+
* @param {number} aspect
|
|
363
|
+
* @memberof Settings */
|
|
364
|
+
function setCanvasMinAspect(aspect) { canvasMinAspect = aspect; }
|
|
365
|
+
|
|
366
|
+
/** Set maximum aspect ratio of the canvas (width/height), unused if 0
|
|
367
|
+
* @param {number} aspect
|
|
368
|
+
* @memberof Settings */
|
|
369
|
+
function setCanvasMaxAspect(aspect) { canvasMaxAspect = aspect; }
|
|
370
|
+
|
|
347
371
|
/** Set fixed size of the canvas
|
|
348
372
|
* @param {Vector2} size
|
|
349
373
|
* @memberof Settings */
|
package/src/engineTileLayer.js
CHANGED
package/src/engineSplash.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LittleJS Engine Splash Screen
|
|
3
|
-
* @namespace Settings
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
9
|
-
// LittleJS splash screen and logo
|
|
10
|
-
|
|
11
|
-
function drawEngineSplashScreen(t)
|
|
12
|
-
{
|
|
13
|
-
const x = overlayContext;
|
|
14
|
-
const w = overlayCanvas.width = innerWidth;
|
|
15
|
-
const h = overlayCanvas.height = innerHeight;
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
// background
|
|
19
|
-
const p3 = percent(t, 1, .8);
|
|
20
|
-
const p4 = percent(t, 0, .5);
|
|
21
|
-
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,hypot(w,h)*.7);
|
|
22
|
-
g.addColorStop(0,hsl(0,0,lerp(0,p3/2,p4),p3).toString());
|
|
23
|
-
g.addColorStop(1,hsl(0,0,0,p3).toString());
|
|
24
|
-
x.save();
|
|
25
|
-
x.fillStyle = g;
|
|
26
|
-
x.fillRect(0,0,w,h);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// draw LittleJS logo...
|
|
30
|
-
const rect = (X, Y, W, H, C)=>
|
|
31
|
-
{
|
|
32
|
-
x.beginPath();
|
|
33
|
-
x.rect(X,Y,W,C?H*p:H);
|
|
34
|
-
x.fillStyle = C;
|
|
35
|
-
C ? x.fill() : x.stroke();
|
|
36
|
-
};
|
|
37
|
-
const line = (X, Y, Z, W)=>
|
|
38
|
-
{
|
|
39
|
-
x.beginPath();
|
|
40
|
-
x.lineTo(X,Y);
|
|
41
|
-
x.lineTo(Z,W);
|
|
42
|
-
x.stroke();
|
|
43
|
-
};
|
|
44
|
-
const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
|
|
45
|
-
{
|
|
46
|
-
const D = (A+B)/2, E = p*(B-A)/2;
|
|
47
|
-
x.beginPath();
|
|
48
|
-
F && x.lineTo(X,Y);
|
|
49
|
-
x.arc(X,Y,R,D-E,D+E);
|
|
50
|
-
x.fillStyle = C;
|
|
51
|
-
C ? x.fill() : x.stroke();
|
|
52
|
-
};
|
|
53
|
-
const color = (c=0, l=0) =>
|
|
54
|
-
hsl([.98,.3,.57,.14][c%4],.8,[0,.3,.5,.8,.9][l]).toString();
|
|
55
|
-
const alpha = wave(1,1,t);
|
|
56
|
-
const p = percent(alpha, .1, .5);
|
|
57
|
-
|
|
58
|
-
// setup
|
|
59
|
-
x.translate(w/2,h/2);
|
|
60
|
-
const size = min(6, min(w,h)/99); // fit to screen
|
|
61
|
-
x.scale(size,size);
|
|
62
|
-
x.translate(-40,-35);
|
|
63
|
-
x.lineJoin = x.lineCap = 'round';
|
|
64
|
-
x.lineWidth = .1 + p*1.9;
|
|
65
|
-
|
|
66
|
-
// drawing effect
|
|
67
|
-
const p2 = percent(alpha,.1,1);
|
|
68
|
-
x.setLineDash([99*p2,99]);
|
|
69
|
-
|
|
70
|
-
// cab top
|
|
71
|
-
rect(7,16,18,-8,color(2,2));
|
|
72
|
-
rect(7,8,18,4,color(2,3));
|
|
73
|
-
rect(25,8,8,8,color(2,1));
|
|
74
|
-
rect(25,8,-18,8);
|
|
75
|
-
rect(25,8,8,8);
|
|
76
|
-
|
|
77
|
-
// cab
|
|
78
|
-
rect(25,16,7,23,color());
|
|
79
|
-
rect(11,39,14,-23,color(1,1));
|
|
80
|
-
rect(11,16,14,18,color(1,2));
|
|
81
|
-
rect(11,16,14,8,color(1,3));
|
|
82
|
-
rect(25,16,-14,24);
|
|
83
|
-
|
|
84
|
-
// cab window
|
|
85
|
-
rect(15,29,6,-9,color(2,2));
|
|
86
|
-
circle(15,21,5,0,PI/2,color(2,4),1);
|
|
87
|
-
rect(21,21,-6,9);
|
|
88
|
-
|
|
89
|
-
// little stack
|
|
90
|
-
rect(37,14,9,6,color(3,2));
|
|
91
|
-
rect(37,14,4.5,6,color(3,3));
|
|
92
|
-
rect(37,14,9,6);
|
|
93
|
-
|
|
94
|
-
// big stack
|
|
95
|
-
rect(50,20,10,-8,color(0,1));
|
|
96
|
-
rect(50,20,6.5,-8,color(0,2));
|
|
97
|
-
rect(50,20,3.5,-8,color(0,3));
|
|
98
|
-
rect(50,20,10,-8);
|
|
99
|
-
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
100
|
-
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
101
|
-
circle(55,2,11.4,.5,PI-.5);
|
|
102
|
-
rect(45,7,20,-7,color(0,2));
|
|
103
|
-
rect(45,-1,20,4,color(0,3));
|
|
104
|
-
rect(45,-1,20,8);
|
|
105
|
-
|
|
106
|
-
// engine
|
|
107
|
-
for (let i=5; i--;)
|
|
108
|
-
{
|
|
109
|
-
// stagger radius to fix slight seam
|
|
110
|
-
circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
|
|
111
|
-
circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
|
|
112
|
-
circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// engine outline
|
|
116
|
-
circle(36,30,10,PI/2,PI*3/2);
|
|
117
|
-
circle(48,30,10,PI/2,PI*3/2);
|
|
118
|
-
circle(60,30,10);
|
|
119
|
-
line(36,20,60,20);
|
|
120
|
-
|
|
121
|
-
// engine front light
|
|
122
|
-
circle(60,30,4,PI,3*PI,color(3,2));
|
|
123
|
-
circle(60,30,4,PI,2*PI,color(3,3));
|
|
124
|
-
circle(60,30,4,PI,3*PI);
|
|
125
|
-
|
|
126
|
-
// front brush
|
|
127
|
-
for (let i=6; i--;)
|
|
128
|
-
{
|
|
129
|
-
x.beginPath();
|
|
130
|
-
x.lineTo(53,54);
|
|
131
|
-
x.lineTo(53,40);
|
|
132
|
-
x.lineTo(53+(1+i*2.9)*p,40);
|
|
133
|
-
x.lineTo(53+(4+i*3.5)*p,54);
|
|
134
|
-
x.fillStyle = color(0,i%2+2);
|
|
135
|
-
x.fill();
|
|
136
|
-
i%2 && x.stroke();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// wheels
|
|
140
|
-
rect(6,40,5,5);
|
|
141
|
-
rect(6,40,5,5,color());
|
|
142
|
-
rect(15,54,38,-14,color());
|
|
143
|
-
for (let i=3; i--;)
|
|
144
|
-
for (let j=2; j--;)
|
|
145
|
-
{
|
|
146
|
-
circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
|
|
147
|
-
x.stroke();
|
|
148
|
-
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
149
|
-
x.stroke();
|
|
150
|
-
}
|
|
151
|
-
line(6,40,68,40); // center
|
|
152
|
-
line(77,54,4,54); // bottom
|
|
153
|
-
|
|
154
|
-
// draw engine name
|
|
155
|
-
const s = engineName;
|
|
156
|
-
x.font = '900 16px arial';
|
|
157
|
-
x.textAlign = 'center';
|
|
158
|
-
x.textBaseline = 'top';
|
|
159
|
-
x.lineWidth = .1+p*3.9;
|
|
160
|
-
let w2 = 0;
|
|
161
|
-
for (let i=0; i<s.length; ++i)
|
|
162
|
-
w2 += x.measureText(s[i]).width;
|
|
163
|
-
for (let j=2; j--;)
|
|
164
|
-
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
165
|
-
{
|
|
166
|
-
x.fillStyle = color(i,2);
|
|
167
|
-
const w = x.measureText(s[i]).width;
|
|
168
|
-
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
169
|
-
X += w;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
x.restore();
|
|
173
|
-
}
|